1

I'm trying to reliably obtain the RGB values of an image pixel cross-platform.

For my test I am using a jpg image supplied to me by someone else (see Edit - The plot thickens section below).

In C#, I'm doing something similar to the following (where bmpData is a BitmapData object):

PixelData* pScan = (PixelData*)bmpData.Scan0;
...
struct PixelData
{
    internal byte r;
    internal byte g;
    internal byte b;

    internal PixelData(byte r, byte g, byte b)
    {
        this.r = r;
        this.g = g;
        this.b = b;
    }
}

In Java, I have tried the following where image is a BufferedImage object (created from a byte[] read in this utility method: http://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#read(java.io.InputStream)):

Raster raster = image.getRaster();
for(x){
   for(y){
      double[] pixel = raster.getPixel(x, y, new double[3]);

And this:

int rgb = image.getRGB(x, y);
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;

And this:

Raster raster = image.getRaster();
int r = raster.getSample(x, y, 0);
int g = raster.getSample(x, y, 1);
int b = raster.getSample(x, y, 2);

With my test image, the results are always as follows. For example, taking the first pixel:

C# Result:
R=16
G=60
B=109

Java Result (in every case):
R=52
G=160
B=102

So, I have three questions:
1. Why are they so wildly different?
2. Is it because I'm doing it wrong?
3. Is there a better way to do it in either case?

Thank you for any help you can offer!

Edit - 2015-10-19 After someone suggested I use an image tool to "pick" the colour of the first pixel, I did so. The values were as follows:

Microsoft Paint:
R=17
G=61
B=110

GIMP:
R=16
G=60
B=109

So my question has changed to:
Why are the RGB values from Java's BufferedImage class so wrong?

Edit - The plot thickens
I exported the image from GIMP and ran it through the same program, and now the RGB figures all match up correctly.

Something in the GIMP export process has changed it so that it now works the same in the Java library.

Now I need to figure out what has changed! Unfortunately I have limited knowledge in this area.

I've checked the alpha precalculations, the ColorModel and ColorSpace. Everything is perceivably the same.

Images (I hope unaltered):
https://www.dropbox.com/s/9pc4nxwdav5s0za/correctRGBs.jpg?dl=0 https://www.dropbox.com/s/fknlj1n4jcuk4pg/incorrectRGBs.jpg?dl=0


Implemented Solution
After Anders' suggestion, I investigated the twelvemonkeys "plugins" first, as it seemed the cleanest solution.

I also noticed that the author had written a plugin to handle tiff files, which was a bonus, as I was previously identifying tiffs by their magic numbers and converting them using the JAI library. No need anymore!

To get this to work I simply added the following gradle dependencies:

compile 'com.twelvemonkeys.imageio:imageio-jpeg:3.1.2'
compile 'com.twelvemonkeys.imageio:imageio-tiff:3.1.2'

Refreshed and ran it again. When it ran again, I could see from the debugger - as well as the results - that the image had been loaded into a BufferedImage object correctly.

The RGB values were then correct too. Thanks!

ndtreviv
  • 3,473
  • 1
  • 31
  • 45
  • Have you used a third tool to get the value of the same pixel in order to know if it is C# or Java which is mistaking ? – Gaël J Oct 16 '15 at 16:13
  • you're getting `int pixel = ` but then `(rgb >> 16)`, probably you need `(pixel >>> 16)`? – Iłya Bursov Oct 16 '15 at 19:05
  • @gael - that's not a bad idea. Can you suggest a tool? – ndtreviv Oct 16 '15 at 19:18
  • @Lashane - Ah sorry! Typo. Will fix ASAP. Assume pixel is actually called rgb – ndtreviv Oct 16 '15 at 19:18
  • @ndtreviv : well I would do it the hard way : open the image with Paint or equivalent, zoom in to first pixel, then use something like a color picker. But there should be quicker way of doing this ! – Gaël J Oct 16 '15 at 20:03
  • @Gaël - Did it in Paint. Think it might be biased, though! Going to check on a Mac based tool to see. I also have some C++ code that samples the image which I'm going to try and run as well... – ndtreviv Oct 19 '15 at 08:17
  • How do you actually open the image file in C# and in Java (show code)? What type of image is it (JPG, PNG, ..)? – Anders Carstensen Oct 19 '15 at 10:41
  • @AndersKellerCarstensen - I've added relevant info for java, but I've just discovered some new information. See section: Edit - The plot thickens in the posting. I don't think this is related to the way I read in the image, but rather the "type" of jpg?! – ndtreviv Oct 19 '15 at 11:06
  • Ah, interesting! If we need to figure out how to read it correctly, it would help greatly to get a copy of the image (unaltered - i.e. don't use an image service like imgur). – Anders Carstensen Oct 19 '15 at 11:11
  • @AndersKellerCarstensen - I've added the links to the images. I hope they remain unaltered - I don't know! – ndtreviv Oct 19 '15 at 11:22
  • @ndtreviv - The first/top-left pixel in that image is 158, 137, 94. Where are you getting 16, 60, 109 from? Also, please check if the images are unaltered - you could start by looking at the size... these images are 7385 & 7388 bytes. – Anders Carstensen Oct 19 '15 at 11:33
  • @AndersKellerCarstensen You're right - it has been altered. I'll try something else. – ndtreviv Oct 19 '15 at 12:13
  • @AndersKellerCarstensen Changed. Should be alright now. – ndtreviv Oct 19 '15 at 12:17
  • @AndersKellerCarstensen I was wrong previously - i'm using javax.imageio.ImageIO to read it in from byte[]. – ndtreviv Oct 19 '15 at 14:16
  • Similar to http://stackoverflow.com/questions/13072312/jpeg-image-color-gets-drastically-changed-after-just-imageio-read-and-imageio – ndtreviv Oct 19 '15 at 15:17

1 Answers1

0

As you have mentioned, this problem is exactly the same as in this thread. You can confirm it by reading the image and then writing it to a file. It looks like this.

There are various solutions to this problem. The easiest one seems to be to include TwelveMonkeys' ImageIO jars as dependencies to your project. You don't need to make any code changes. This worked for me.

Other alternatives:

  1. Mark Jeronimus wrote a method that converts the bad image to the correct image. I tested it on your sample image and it works. However, you will need to find a good way of detecting whether or not it is necessary to the conversion. There is a comment to that answer which might help.
  2. As suggested by ludovic, you can use Toolkit's getImage to open the image instead of ImageIO since it doesn't have the same bug.
Community
  • 1
  • 1
Anders Carstensen
  • 2,949
  • 23
  • 23
  • I, too, went for the twelvemonkeys "plugins". I'll add the full solution to the question above for ease of other people looking for the same answer. – ndtreviv Oct 20 '15 at 10:33