Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Bitmap.Load method produce different result on different computers

I try to load JPEG file and delete all black and white pixels from image

C# Code:

    ...
    m_SrcImage = new Bitmap(imagePath);

    Rectangle r = new Rectangle(0, 0, m_SrcImage.Width, m_SrcImage.Height);
    BitmapData bd = m_SrcImage.LockBits(r, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

    //Load Colors
    int[] colours = new int[m_SrcImage.Width * m_SrcImage.Height];
    Marshal.Copy(bd.Scan0, colours, 0, colours.Length);
    m_SrcImage.UnlockBits(bd);

    int len = colours.Length;

    List<Color> result = new List<Color>(len);

    for (int i = 0; i < len; ++i)
    {
        uint w = ((uint)colours[i]) & 0x00FFFFFF; //Delete alpha-channel
        if (w != 0x00000000 && w != 0x00FFFFFF)   //Check pixel is not black or white
        {
            w |= 0xFF000000;                      //Return alpha channel
            result.Add(Color.FromArgb((int)w));
        }
    }
    ...

After that I try to find unique colors in List by this code

    result.Sort((a, b) =>
    {
        return  a.R != b.R ? a.R - b.R :
                a.G != b.G ? a.G - b.G :
                a.B != b.B ? a.B - b.B :
                0;
    });


    List<Color> uniqueColors = new List<Color>( result.Count);   

    Color rgbTemp = result[0];

    for (int i = 0; i < len; ++i)
    {
         if (rgbTemp == result[i])
         {       
              continue;
         }

         uniqueColors.Add(rgbTemp);
         rgbTemp = result[i];
    }
    uniqueColors.Add(rgbTemp);

And this code produces different results on different machines on same image!

For example, on this image it produces:

  • 43198 unique colors on XP SP3 with .NET version 4
  • 43168 unique colors on Win7 Ultimate with .NEt version 4.5

Minimum test project you can download here. It just opens selected image and produces txt-file with unique colors.

One more fact. Some pixels are read differently on different machines. I compare txt-files with notepad++ and it shows that some pixels have different RGB components. The difference is 1 for each component, e.g.

  • Win7 pixel: 255 200 100
  • WinXP pixel: 254 199 99

I have read this post

stackoverflow.com/questions/2419598/why-might-different-computers-calculate-different-arithmetic-results-in-vb-net

(sorry, I haven't enough raiting for normal link).

...but there wasn't information how to fix it.


Project was compiled for .NET 4 Client profile on machine with OS Windows 7 in VS 2015 Commumity Edition.

like image 768
Pavel.Zh Avatar asked Oct 18 '22 15:10

Pavel.Zh


1 Answers

Wikipedia has this to say about the accuracy requirements for JPEG Decoders:

The encoding description in the JPEG standard does not fix the precision needed for the output compressed image. However, the JPEG standard (and the similar MPEG standards) includes some precision requirements for the decoding, including all parts of the decoding process (variable length decoding, inverse DCT, dequantization, renormalization of outputs); the output from the reference algorithm must not exceed:

  • a maximum of one bit of difference for each pixel component
  • low mean square error over each 8×8-pixel block
  • very low mean error over each 8×8-pixel block
  • very low mean square error over the whole image
  • extremely low mean error over the whole image

(my emphasis)

In short, there is simply two different decoder implementations at play here, and they produce different images, within the accuracy requirement (1 bit = +/- 1 in the component values, as you observed).

So short of using the same (non-built-in) jpeg decoder, this is to be expected. If you need to have the exact same output then you probably need to switch to a different decoder, one that will be the same no matter which .NET version or Windows you're running this on. I'm guessing that GDI+ is the culprit here as this has undergone larger changes since Windows XP.

like image 168
Lasse V. Karlsen Avatar answered Oct 21 '22 05:10

Lasse V. Karlsen