165

I'm trying to convert image from PIL to OpenCV format. I'm using OpenCV 2.4.3. here is what I've attempted till now.

>>> from PIL import Image
>>> import cv2 as cv
>>> pimg = Image.open('D:\\traffic.jpg')                           #PIL Image
>>> cimg = cv.cv.CreateImageHeader(pimg.size,cv.IPL_DEPTH_8U,3)    #CV Image
>>> cv.cv.SetData(cimg,pimg.tostring())
>>> cv.cv.NamedWindow('cimg')
>>> cv.cv.ShowImage('cimg',cimg)
>>> cv.cv.WaitKey()

But I think the image is not getting converted to CV format. The Window shows me a large brown image. Where am I going wrong in Converting image from PIL to CV format?

Also , why do i need to type cv.cv to access functions?

Milind Anantwar
  • 81,290
  • 25
  • 94
  • 125
md1hunox
  • 3,815
  • 10
  • 45
  • 67
  • Possible duplicate: http://stackoverflow.com/questions/1650568/how-do-i-create-an-opencv-image-from-a-pil-image – Tim Jan 03 '13 at 07:49
  • 1
    I referred to the question you mentioned, but the solution given there doesnt seem to work for me – md1hunox Jan 03 '13 at 07:50
  • I think you need to convert the image from RGB to BGR. check if it works. – Froyo Jan 03 '13 at 12:10

5 Answers5

263

use this:

pil_image = PIL.Image.open('Image.jpg').convert('RGB') 
open_cv_image = numpy.array(pil_image) 
# Convert RGB to BGR 
open_cv_image = open_cv_image[:, :, ::-1].copy() 
Abhishek Thakur
  • 16,337
  • 15
  • 66
  • 97
  • 3
    Thanks, Can you please explain me what the last line does in detail? – md1hunox Jan 03 '13 at 15:07
  • 22
    You have a RGB image represented by a 3d array, as in `ex = numpy.array([ [ [1, 2, 3], [4, 5, 6] ], [ [7, 8, 9], [0, 1, 2] ] ])`. So `ex[0]` is the first line of your image, `ex[0][0]` is the first column of the first line, `ex[0][0][0]` is the red component of the first pixel, `ex[0][0][1]` is the green component, and `ex[0][0][2]` is the blue component. Since you apparently need a BGR image (the inverse order of RGB), you invert each element that describes a pixel as in `ex[0][0][::-1]`. The last line (except for the useless `.copy`) is the equivalent of this operation for the whole image. – mmgp Jan 03 '13 at 22:09
  • 24
    It may be only a slight performance improvement, but `cv2.cvtColor(open_cv_image, cv2.cv.CV_BGR2RGB)` is a bit more efficient. – GuillaumeDufay Mar 09 '15 at 01:24
  • What was the purpose of .convert('RGB') in your answer? I am working with a 16 bit greyscale image (image mode=I;16) .. so far the nparray is keeping the image as a single PIL.Image object. (i.e., an array with only one entry, the original PIL.Image) – user391339 May 28 '15 at 19:11
  • 3
    If the image is binary (for example, scanned binary `TIF`), then the numpy array will be `bool` and so you won't be able to use it with OpenCV. In this case you need to convert it to OpenCV mask: `if image.dtype == bool: image = image.astype(np.uint8) * 255` – Maksym Ganenko Aug 25 '17 at 06:57
  • This worked on my Windows machine, but shows up with a blue hue to everything when used on a Mac. Same exact code. What could be the problem? – Frak Mar 01 '18 at 15:42
  • Here is an one-liner function for the same code: `convert = lambda filename: np.array(Image.open(filename).convert('RGB'))[:, :, ::-1].copy() ` – Martinez Oct 07 '19 at 01:22
  • Any Idea how to do the other way round? – Trect Nov 27 '19 at 14:57
  • As mentioned and visualized in this [article](https://towardsdatascience.com/image-read-and-resize-with-opencv-tensorflow-and-pil-3e0f29b992be), PIL does not support integer accurate decompression whereas in OpenCV, this is the default. Therefore, when loading lossy formats like JPEG, you will inevitably get some difference in pixel values. Using loss-less formats like PNG can avoid this – Addison Klinke Oct 07 '20 at 20:48
  • ```open_cv_image = cv2.cvtColor(open_cv_image, cv2.COLOR_RGB2BGR)``` is used instead of ```cv2.cvtColor(open_cv_image, cv2.cv.CV_BGR2RGB)``` if your openCV version if > 3.0 – ComNguoi Oct 13 '22 at 04:10
162

This is the shortest version I could find,saving/hiding an extra conversion:

pil_image = PIL.Image.open('image.jpg')
opencvImage = cv2.cvtColor(numpy.array(pil_image), cv2.COLOR_RGB2BGR)

If reading a file from a URL:

import cStringIO
import urllib
file = cStringIO.StringIO(urllib.urlopen(r'http://stackoverflow.com/a_nice_image.jpg').read())
pil_image = PIL.Image.open(file)
opencvImage = cv2.cvtColor(numpy.array(pil_image), cv2.COLOR_RGB2BGR)
Berthier Lemieux
  • 3,785
  • 1
  • 25
  • 25
  • 2
    If downloading from url, i would go with: `import requests` `response = requests.get(url)` `opencvImage = imdecode(np.asarray(bytearray(response.content)), 1)` – Lior Mar 01 '16 at 14:03
  • 4
    how do I convert pil image to mat again? –  Jul 22 '17 at 16:33
  • 1
    ur answer returns this error: `OpenCV Error: Assertion failed (scn == 3 || scn == 4) in cvtColor` – Farid Alijani May 11 '20 at 13:35
  • 1
    works. Why is that everyone in the python world does not state its imports? – pscheit Aug 30 '20 at 17:41
20

The code commented works as well, just choose which do you prefer

import numpy as np
from PIL import Image


def convert_from_cv2_to_image(img: np.ndarray) -> Image:
    # return Image.fromarray(img)
    return Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))


def convert_from_image_to_cv2(img: Image) -> np.ndarray:
    # return np.asarray(img)
    return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
Ivan Reshetnikov
  • 398
  • 2
  • 12
Pedro Nunes
  • 367
  • 2
  • 5
  • the second method does that, convert an image from PIL to cv2. I've posted two ways of doing that, one is in comment. just choose what do you prefer. I'ved also post a method to do the opposite, witch is the first one, that also shows two ways of doing it, one is commented, just choose what you prefer. – Pedro Nunes Jan 09 '21 at 20:21
2

Pillow image to OpenCV image:

cv2_img = np.array(pil_img)
cv2_img = cv2.cvtColor(cv2_img, cv2.COLOR_RGB2BGR)

OpenCV image to Pillow image:

cv2_img = cv2.cvtColor(cv2_img, cv2.COLOR_BGR2RGB)
pil_img = Image.fromarray(cv2_img)

Source: https://medium.com/analytics-vidhya/the-ultimate-handbook-for-opencv-pillow-72b7eff77cd7

1

Here are two functions to convert image between PIL and OpenCV:

def toImgOpenCV(imgPIL): # Conver imgPIL to imgOpenCV
    i = np.array(imgPIL) # After mapping from PIL to numpy : [R,G,B,A]
                         # numpy Image Channel system: [B,G,R,A]
    red = i[:,:,0].copy(); i[:,:,0] = i[:,:,2].copy(); i[:,:,2] = red;
    return i; 

def toImgPIL(imgOpenCV): return Image.fromarray(cv2.cvtColor(imgOpenCV, cv2.COLOR_BGR2RGB));

Convert from OpenCV img to PIL img will lost transparent channel. While convert PIL img to OpenCV img will able to keep transparent channel, although cv2.imshow not display it but save as png will gave result normally.

  • You can call cv2.imwrite("./"+"fileName.png", img); to export and check the transparent result of OpenCV img.
  • Or toImgPIL(img).save('test.png', 'PNG') to check PIL img.
phnghue
  • 1,578
  • 2
  • 10
  • 9