159

I have an RGB image. I want to convert it to numpy array. I did the following

im = cv.LoadImage("abc.tiff")
a = numpy.asarray(im)

It creates an array with no shape. I assume it is a iplimage object.

Francisco
  • 10,918
  • 6
  • 34
  • 45
Shan
  • 18,563
  • 39
  • 97
  • 132
  • 2
    If `cv` is the OpenCV module, then you should tag it as such. This link may help: http://opencv.willowgarage.com/documentation/python/cookbook.html#numpy-and-opencv – Paul Oct 14 '11 at 04:50

15 Answers15

193

You can use newer OpenCV python interface (if I'm not mistaken it is available since OpenCV 2.2). It natively uses numpy arrays:

import cv2
im = cv2.imread("abc.tiff",mode='RGB')
print(type(im))

result:

<type 'numpy.ndarray'>
Neuron
  • 5,141
  • 5
  • 38
  • 59
Andrey Kamaev
  • 29,582
  • 6
  • 94
  • 88
101

PIL (Python Imaging Library) and Numpy work well together.

I use the following functions.

from PIL import Image
import numpy as np

def load_image( infilename ) :
    img = Image.open( infilename )
    img.load()
    data = np.asarray( img, dtype="int32" )
    return data

def save_image( npdata, outfilename ) :
    img = Image.fromarray( np.asarray( np.clip(npdata,0,255), dtype="uint8"), "L" )
    img.save( outfilename )

The 'Image.fromarray' is a little ugly because I clip incoming data to [0,255], convert to bytes, then create a grayscale image. I mostly work in gray.

An RGB image would be something like:

out_img = Image.fromarray( ycc_uint8, "RGB" )
out_img.save( "ycc.tif" )
Neuron
  • 5,141
  • 5
  • 38
  • 59
David Poole
  • 3,432
  • 5
  • 34
  • 34
  • 1
    This fails with an error, `TypeError: long() argument must be a string or a number, not 'PixelAccess'` and looking at the documentation for PIL's `PixelAccess` class, it does not appear to offer methods that would enable `np.array` to convert its underlying data into an `ndarray` format. You need to omit the use of `img.load()` and deal only with the result of `Image.open(...)`. – ely May 05 '17 at 15:40
  • 1
    The img.load() works around a weird caching issue in PIL. The data wouldn't be loaded until explicitly needed. The example still works for me with the exception of changing "import Image" to "from PIL import Image" when working with Pillow (the PIL fork). – David Poole May 15 '17 at 13:06
  • 1
    Upvote for using PIL only and not OpenCV. I'm not against OpenCV though. – progyammer Apr 15 '18 at 04:06
89

You can also use matplotlib for this.

from matplotlib.image import imread

img = imread('abc.tiff')
print(type(img))

output: <class 'numpy.ndarray'>

Rishabh Agrahari
  • 3,447
  • 2
  • 21
  • 22
  • 3
    This is very simple. I like it :) – jeongmin.cha Nov 25 '17 at 11:30
  • 1
    @Mrinal Yes, it does. – Rishabh Agrahari Jan 20 '19 at 05:11
  • 3
    This should probably be the accepted answer? Matplotlib is almost always installed with numpy, and this is a one-line solution. All these other answers using PIL/CV are needlessly complicated, and less relevant to the actual question. Why install extra packages and add complexity when the one line solution is practically built in? – MRule Sep 18 '21 at 09:13
  • 1
    internally it uses, PIL so i guess it gets installed along with matplotlib – Rahul A Ranger Jan 08 '22 at 18:06
46

As of today, your best bet is to use:

img = cv2.imread(image_path)   # reads an image in the BGR format
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)   # BGR -> RGB

You'll see img will be a numpy array of type:

<class 'numpy.ndarray'>
belvederef
  • 2,195
  • 19
  • 16
  • Sorry, I need to know the advantages of this line `img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR -> RGB` – Maf Nov 17 '20 at 06:24
  • 1
    @Maf cv2 reads the image in the BGR format, so the second function turns it into the RGB format, which is the way we humans see colours. See [this image](https://miro.medium.com/max/3336/1*DuHDh3mxAiHDpmj1MsE92w.png) for a format comparison. – belvederef Nov 17 '20 at 12:11
  • Thank you @ belvederef – Maf Nov 17 '20 at 16:51
  • How is this related to converting an image to grayscale? – user1767754 Jan 03 '21 at 02:55
  • @user1767754 If you wanted to convert to greyscale, you would use the function argument `cv2.COLOR_BGR2GRAY` instead. – belvederef Jan 03 '21 at 08:54
  • And you should put that into your answer. At the moment your answer is just switching the color spaces. – user1767754 Jan 06 '21 at 18:05
  • @user1767754 just seen this. Why should I? The question asks how to convert an RGB image to numpy array, where are you getting this gray-scale thing from??? – belvederef Jun 06 '21 at 23:04
  • @belvederef lol, I must have been commenting on the wrong post... my comment doesn't make sense at all – user1767754 Jun 10 '21 at 04:49
17

Late answer, but I've come to prefer the imageio module to the other alternatives

import imageio
im = imageio.imread('abc.tiff')

Similar to cv2.imread(), it produces a numpy array by default, but in RGB form.

slizb
  • 5,742
  • 4
  • 25
  • 22
9

You can get numpy array of rgb image easily by using numpy and Image from PIL

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

im = Image.open('*image_name*') #These two lines
im_arr = np.array(im) #are all you need
plt.imshow(im_arr) #Just to verify that image array has been constructed properly
parth_07
  • 1,322
  • 16
  • 22
9

You need to use cv.LoadImageM instead of cv.LoadImage:

In [1]: import cv
In [2]: import numpy as np
In [3]: x = cv.LoadImageM('im.tif')
In [4]: im = np.asarray(x)
In [5]: im.shape
Out[5]: (487, 650, 3)
Justin Peel
  • 46,722
  • 6
  • 58
  • 80
  • Thanks a lot... Could you please also help me in finding out that if I create an image using 'cv.CreateImage(width,height,channels)'... How could it be converted to numpy array? – Shan Oct 14 '11 at 05:04
  • I think that you need to use cv.CreateMat instead or use cv.CreateMat and copy from the image to the mat using cv.CvtColor or some similar thing. Take a look at the link that Paul posted to above. – Justin Peel Oct 14 '11 at 05:12
6

load the image by using following syntax:-

from keras.preprocessing import image

X_test=image.load_img('four.png',target_size=(28,28),color_mode="grayscale"); #loading image and then convert it into grayscale and with it's target size 
X_test=image.img_to_array(X_test); #convert image into array
David Buck
  • 3,752
  • 35
  • 31
  • 35
Disha Doshi
  • 111
  • 1
  • 4
5

When using the answer from David Poole I get a SystemError with gray scale PNGs and maybe other files. My solution is:

import numpy as np
from PIL import Image

img = Image.open( filename )
try:
    data = np.asarray( img, dtype='uint8' )
except SystemError:
    data = np.asarray( img.getdata(), dtype='uint8' )

Actually img.getdata() would work for all files, but it's slower, so I use it only when the other method fails.

daign
  • 899
  • 1
  • 10
  • 18
4

OpenCV image format supports the numpy array interface. A helper function can be made to support either grayscale or color images. This means the BGR -> RGB conversion can be conveniently done with a numpy slice, not a full copy of image data.

Note: this is a stride trick, so modifying the output array will also change the OpenCV image data. If you want a copy, use .copy() method on the array!

import numpy as np

def img_as_array(im):
    """OpenCV's native format to a numpy array view"""
    w, h, n = im.width, im.height, im.channels
    modes = {1: "L", 3: "RGB", 4: "RGBA"}
    if n not in modes:
        raise Exception('unsupported number of channels: {0}'.format(n))
    out = np.asarray(im)
    if n != 1:
        out = out[:, :, ::-1]  # BGR -> RGB conversion
    return out
wim
  • 338,267
  • 99
  • 616
  • 750
2

I also adopted imageio, but I found the following machinery useful for pre- and post-processing:

import imageio
import numpy as np

def imload(*a, **k):
    i = imageio.imread(*a, **k)
    i = i.transpose((1, 0, 2))  # x and y are mixed up for some reason...
    i = np.flip(i, 1)  # make coordinate system right-handed!!!!!!
    return i/255


def imsave(i, url, *a, **k):
    # Original order of arguments was counterintuitive. It should
    # read verbally "Save the image to the URL" — not "Save to the
    # URL the image."

    i = np.flip(i, 1)
    i = i.transpose((1, 0, 2))
    i *= 255

    i = i.round()
    i = np.maximum(i, 0)
    i = np.minimum(i, 255)

    i = np.asarray(i, dtype=np.uint8)

    imageio.imwrite(url, i, *a, **k)

The rationale is that I am using numpy for image processing, not just image displaying. For this purpose, uint8s are awkward, so I convert to floating point values ranging from 0 to 1.

When saving images, I noticed I had to cut the out-of-range values myself, or else I ended up with a really gray output. (The gray output was the result of imageio compressing the full range, which was outside of [0, 256), to values that were inside the range.)

There were a couple other oddities, too, which I mentioned in the comments.

enigmaticPhysicist
  • 1,518
  • 16
  • 21
1

We can use following function of open CV2 to convert BGR 2 RGB format.

RBG_Image = cv2.cvtColor(Image, cv.COLOR_BGR2RGB)
Tapan Hegde
  • 1,222
  • 1
  • 8
  • 25
0

Using Keras:

from keras.preprocessing import image
  
img = image.load_img('path_to_image', target_size=(300, 300))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
images = np.vstack([x])
ESbros
  • 147
  • 1
  • 4
0

Try timing the options to load an image to numpy array, they are quite similar. Go for plt.imread for simplicity and speed.

def time_this(function, times=100):
    cum_time = 0
    for t in range(times):
        st = time.time()
        function()
        cum_time += time.time() - st
    return cum_time / times

import matplotlib.pyplot as plt
def load_img_matplotlib(img_path):
    return plt.imread(img_path)

import cv2
def load_img_cv2(img_path):
    return cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB)

from PIL import Image
import numpy as np
def load_img_pil(img_path):
    img = Image.open(img_path)
    img.load()
    return np.asarray( img, dtype="int32" )

if __name__=='__main__':
    img_path = 'your_image_path'
    for load_fn in [load_img_pil, load_img_cv2, load_img_matplotlib]:
        print('-'*20)
        print(time_this(lambda: load_fn(img_path)), 10000)

Result:

--------------------
0.0065201687812805175 10000  PIL, as in [the second answer][1]https://stackoverflow.com/a/7769424/16083419)
--------------------
0.0053211402893066405 10000  CV2
--------------------
0.005320906639099121 10000  matplotlib
0

You can try the following method. Here is a link to the docs.

tf.keras.preprocessing.image.img_to_array(img, data_format=None, dtype=None)
from PIL import Image
img_data = np.random.random(size=(100, 100, 3))
img = tf.keras.preprocessing.image.array_to_img(img_data)
array = tf.keras.preprocessing.image.img_to_array(img)
41 72 6c
  • 1,600
  • 5
  • 19
  • 30