Nesa
Nesa

Reputation: 2965

Conversion from OpenCV to PIL is not accurate

When I convert an image from PIL to OpenCV, colors change slightly.

from PIL import Image
import cv2
import numpy as np
image = cv2.imread('1.jpg')
image1=Image.open('1.jpg')
image1 = cv2.cvtColor(np.array(image1), cv2.COLOR_RGB2BGR)
print(image[79])
print(image1[79])

The first four rows are:

[144 151 148]
[101 108 105]
[121 128 125]
[108 118 112]

and

[140 152 146]
[ 97 109 103]
[117 129 123]
[104 118 112]

I thought the indexing may be off by one but it isn't. Is there a way to fix this? This is the image (but it's the same on others too):

image

Upvotes: 2

Views: 2264

Answers (4)

Xin Yang
Xin Yang

Reputation: 433

libjpeg version may by different

Convert the original .jpg image to .bmp image

ffmpeg -i 1.jpg 1.bmp

than the opencv output and PIL output will be the same

Upvotes: 1

Andriy Makukha
Andriy Makukha

Reputation: 8334

This behaviour is dependent on different incompatible versions of libjpeg used by cv2 and PIL/Pillow, as @fireant already pointed out.

For example, when I try to run this code with older versions of Pillow (like 3.4.2), it generates same output. In my tests, Pillow 3.4.2 and older (oldest version tried was 2.2.0) all use libjpeg 8, while Pillow 4.0.0 and newer use libjpeg 9.2.

OpenCV, on the other hand, might use different versions on different systems:

On Microsoft Windows* OS and MacOSX*, the codecs shipped with an OpenCV image (libjpeg, libpng, libtiff, and libjasper) are used by default.

On Linux*, BSD flavors and other Unix-like open-source operating systems, OpenCV looks for codecs supplied with an OS image. Install the relevant packages (do not forget the development files, for example, "libjpeg-dev", in Debian* and Ubuntu*) to get the codec support or turn on the OPENCV_BUILD_3RDPARTY_LIBS flag in CMake.

So on Debian/Ubuntu systems opencv might use libjpeg-turbo which comes with the OS. (My machine, specifically, had version 8 installed.)

The way to fix this is to ensure that both Pillow and OpenCV use same libjpeg version.

You could try this:

  • if you have relatively new PIL/Pillow, downgrade it to version <= 3.4.2 (this is what worked for me)

     pip install Pillow==3.4.2
    
  • if you have old Pillow version, you could try to upgrade it to version >= 4.0.0

If that doesn't help, your solution could be either of two:

  • recompiling your OpenCV with same libjpeg flavor as used by Pillow.
  • reinstalling Pillow from source using same libjpeg version as used by OpenCV.

Upvotes: 1

Benehiko
Benehiko

Reputation: 472

Since OpenCV reads the image in as BGR format with cv2.imread() we need to convert it back to RGB before giving it to PIL.

Here is an example of reading an image with OpenCv and without change saving it with PIL:

image = cv2.imread('test.jpg')
pil_img = PIL.Image.fromarray(image)
pil_img.save('pil_img.jpg', 'JPEG')

The 'test.jpg' Image: enter image description here

The 'pil_img.jpg' Image: enter image description here

To correct this we need to use cv2.cvtColor to change the image to RGB

correct_img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
pil_img = PIL.Image.fromarray(correct_img)
pil_img.save('pil_correct_img.jpg', 'JPEG')

Result: enter image description here

Upvotes: 0

fireant
fireant

Reputation: 14538

That suggests PIL and OpenCV are using different versions of libjpeg or using it with different parameters. Also it seems OpenCV tries to use libjpeg-turbo if you don't ask it not to do so, see the code here: https://github.com/opencv/opencv/blob/master/cmake/OpenCVFindLibsGrfmt.cmake#L39

Upvotes: 2

Related Questions