1

I've noticed that the matrix output of an image from Python cv2, has different values for the same pixel read by Java ImageIO. What is the cause of this and how can we get an unanimous value in Java without usage of Java-OpenCV dependency. image for bus.jpg Test code and bus.jpg for comparison:

import cv2
if __name__ == '__main__':
    path = 'bus.jpg'
    img0 = cv2.imread(path)  # BGR
    print(img0[0][0][0]) # 122 output

VS

final BufferedImage image = ImageIO.read(new File("bus.jpg"));
var rgb = image.getRGB(0, 0);
var red = (rgb >> 16) & 0xFF;
var green = (rgb >> 8) & 0xFF;
var blue = rgb & 0xFF;
System.out.println(blue); // 118 output
BayanR
  • 149
  • 9
  • 1
    Why don't you print all 3 values in both cases? – CristiFati Jan 29 '23 at 21:45
  • @CristiFati We could. I didn't in order to keep the test code as brief as possible. I think the current code already displays a difference in results. – BayanR Jan 29 '23 at 21:50
  • 1
    You should print all 3 values so we could see whether every value is present in both versions or whether something else is going on, like different color profiles (opencv doesn't handle adobe rgb correctly for example) or handled vs. unhandled image rotation information. – Micka Jan 29 '23 at 21:58
  • Did you try to catch the single channels by their functions like getBlue etc.? https://stackoverflow.com/a/25761567/2393191 – Micka Jan 29 '23 at 22:02
  • Can you try to print opencv img.at(0,0)? – Micka Jan 29 '23 at 22:03
  • You could and maybe should render the images in both versions, for debugging purposes. Color profile interpretatiom differences might be visible with the eye. – Micka Jan 29 '23 at 22:06
  • @Micka The underlying implementation of getRed, etc. is done in the same way eg. return (getRGB() >> 16) & 0xFF; I have fully printed and diffed the entire arrays between Java and Python. However, in the end they are different. I'm unable to figure out *why* they are different. But indeed, I'm already certain they are different. And finally, I would like to achieve the same result in Java as I do in Python. – BayanR Jan 29 '23 at 23:14
  • JPEG is lossy, you are not guaranteed to read back the exact same values when using two different libraries or even two different versions of the same library. Try using a lossless PNG image to test your code. **ImageMagick** gets 121. – Mark Setchell Jan 30 '23 at 08:03
  • @Mark Setchell, decoding a JPEG image is a deterministic algorithm. Two implementations should result in the same image except for floating point errors. See my answer. – relent95 Jan 30 '23 at 08:24
  • 1
    @relent95 JPEG decoders are permitted to trade accuracy for performance, so they will not necessarily return the same values as each other. – Mark Setchell Jan 30 '23 at 08:45
  • 1
    @Mark Setchell, you mean approximations? Maybe you are right. But is a difference of 4/256 normal? Just for my curiosity. – relent95 Jan 30 '23 at 09:09

1 Answers1

2

It's because OpenCV does not process an ICC profile embedded in that JPEG image.

You can either convert colors with an image editing tool such as GIMP, or convert with Python using a library such as Pillow.

This is an example of the latter.

import io
import numpy as np
import cv2
import PIL.Image
import PIL.ImageCms

img = PIL.Image.open('bus.jpg')
img_profile = PIL.ImageCms.ImageCmsProfile(io.BytesIO(img.info.get('icc_profile')))
rgb_profile = PIL.ImageCms.createProfile('sRGB')
trans = PIL.ImageCms.buildTransform(img_profile, rgb_profile, 'RGB', 'RGB')
img = PIL.ImageCms.applyTransform(img, trans)

cv_img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
relent95
  • 3,703
  • 1
  • 14
  • 17