Reputation: 3026
I downloaded a random image from the internet, opened it using PIL.Image.open()
and cv2.imread()
then I checked some pixels' values. The problem is that I got different values for the same pixels using PIL and Opencv!
This is the image I tried:
This is what I did:
>>> import cv2
>>> from PIL import Image
>>> img = cv2.imread('img.jpg')
>>> im = Image.open('img.jpg')
>>> img[0][0]
>>> array([142, 152, 146], dtype=uint8)
>>> im.getpixel((0, 0))
>>> (138, 158, 131)
The R, G, B values ((138 != 146), (158 != 152), (131 != 142)) of both im
and img
don't match, although it is the same pixel and the same image!
I looked into SO posts, I found this post talking about the same issue, so I used the code that was posted to check the difference again:
from PIL import Image
import cv2
import sys
from hashlib import md5
import numpy as np
def hashIm(im):
imP = np.array(Image.open(im))
# Convert to BGR and drop alpha channel if it exists
imP = imP[..., 2::-1]
# Make the array contiguous again
imP = np.array(imP)
im = cv2.imread(im)
diff = im.astype(int)-imP.astype(int)
cv2.imshow('cv2', im)
cv2.imshow('PIL', imP)
cv2.imshow('diff', np.abs(diff).astype(np.uint8))
cv2.imshow('diff_overflow', diff.astype(np.uint8))
with open('dist.csv', 'w') as outfile:
diff = im-imP
for i in range(-256, 256):
outfile.write('{},{}\n'.format(i, np.count_nonzero(diff==i)))
cv2.waitKey(0)
cv2.destroyAllWindows()
return md5(im).hexdigest() + ' ' + md5(imP).hexdigest()
if __name__ == '__main__':
print(hashIm('img.jpg'))
The hashes I got are different, also the difference between the images is not black!
Additional info:
- Os: Ubuntu 18.04
- Python: 3.6
- Opencv: opencv-python==4.0.0.21
- PIL: Pillow==5.4.1
Is there any explanation for this?
Upvotes: 6
Views: 3433
Reputation: 51
This is probably not a numpy / rounding problem but a jpg decoding variation : https://github.com/python-pillow/Pillow/issues/3833
In particular:
JPEG decoders are allowed to produce slightly different results, "a maximum of one bit of difference for each pixel component" according to Wikipedia.
(https://github.com/python-pillow/Pillow/issues/3833#issuecomment-585211263)
Upvotes: 5
Reputation: 6935
Opencv stores image as a numpy ndarray.
import cv2
cv_img = cv2.imread(img_path)
from PIL import Image
pil_img = Image.open(img_path)
When you do cv_img[x][y]
you are accessing y
th column and x
th row, but if you do pil_img.getpixel((x,y))
pillow access pixels of x
th column and y
th row.
Another factor is pillow returns in (R, G, B)
format where as opencv returns in (B, G, R)
format.
For me cv_img[20][10]
gives array([127, 117, 129], dtype=uint8)
. Check here B = 127
, G = 117
, R = 129
.
But pil_img[10][20]
gives (129, 117, 127)
. Check here R = 129
, G = 117
, B = 127
.
Upvotes: 2