165

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.

1

15 Answers 15

201

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'>
Sign up to request clarification or add additional context in comments.

10 Comments

Beware that cv2.imread() returns a numpy array in BGR not RGB.
@pnd your comment is sacred!
For future reference: $ pip install opencv-python to install opencv
TypeError: 'mode' is an invalid keyword argument for imread()
OpenCV seem to have dropped the mode argument. See my answer below for an updated method.
|
107

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" )

3 Comments

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(...).
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).
Upvote for using PIL only and not OpenCV. I'm not against OpenCV though.
96

You can also use matplotlib for this.

from matplotlib.image import imread

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

output: <class 'numpy.ndarray'>

4 Comments

This is very simple. I like it :)
@Mrinal Yes, it does.
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?
internally it uses, PIL so i guess it gets installed along with matplotlib
49

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'>

7 Comments

Sorry, I need to know the advantages of this line img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR -> RGB
@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 for a format comparison.
How is this related to converting an image to grayscale?
@user1767754 If you wanted to convert to greyscale, you would use the function argument cv2.COLOR_BGR2GRAY instead.
And you should put that into your answer. At the moment your answer is just switching the color spaces.
|
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.

Comments

13

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

Comments

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)

2 Comments

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?
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.
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

Comments

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.

Comments

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

Comments

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.

Comments

1

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])

1 Comment

It doesn't work for the jpeg format in my case. Recommended to use PIL.Image.
1

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

RBG_Image = cv2.cvtColor(Image, cv.COLOR_BGR2RGB)

1 Comment

Change cv.COLOR_BGR2RGB to cv2.COLOR_BGR2RGB
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

Comments

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.