0

I have the following code-

Bitmap img = new Bitmap(ControlsMap.BtnYes.CaptureImage());
img.Save(@"E:\images\btnyes.png");

The image is also captured and saved correctly -
enter image description here

I want to get the background color of the image.

I tried several variations of the following line -

var a = img.Palette.Entries;

but I'm unable to get background color of the image. Is there any other way?

user3164272
  • 565
  • 1
  • 9
  • 20
  • If you have created the bitmap yourself, then you must have defined the color, so why do you wanna get back the color code, else if you haven't and loading the image from somewhere, .Net doesn't have any method for that. – JAX May 13 '14 at 08:13
  • this also would be kind of difficult. an image should be threated as a binary file - and just imagine you have a sprinkled background - how should c#/.net know which of these colors you need? in your button: do you want the dark green or the lime green border? – christian.s May 13 '14 at 08:17
  • @christian.s I want the dark green – user3164272 May 13 '14 at 08:19
  • @user3164272 I know - but you would have to express that in your language. maybe this helps: http://stackoverflow.com/questions/19808743/for-an-jpg-image-file-get-3-4-average-main-colors just have a look at the code snippets – christian.s May 13 '14 at 08:20
  • @user3164272 what i am trying to say is that you will need to process the whole image, you won't find a property like "background color", your question sounds like this is what you are looking for. – christian.s May 13 '14 at 08:22

2 Answers2

1

Just iterate over the entire image and keep a count for each found colour, and then take the colour with the largest count.

The simplest way to do this is probably with GetPixel, though for large images that may take a long time. So instead, you could use LockBits and Marshal.Copy to get the raw bytes out as 32bpp data, then iterate over those bytes, combine them into a colour per four, and check those colours.

For actually getting the maximum I'd use a Dictionary with the colours as keys, and the amounts as values.

All together, you get this:

public static Color FindMostCommonColor(Image image)
{
    // Avoid unnecessary getter calls
    Int32 height = image.Height;
    Int32 width = image.Width;
    Int32 stride;
    Byte[] imageData;
    // Expose bytes as 32bpp ARGB
    BitmapData sourceData = image.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    stride = sourceData.Stride;
    imageData = new Byte[stride * height];
    Marshal.Copy(sourceData.Scan0, imageData, 0, imageData.Length);
    image.UnlockBits(sourceData);
    // Store colour frequencies in a dictionary.
    Dictionary<Color,Int32> colorFreq = new Dictionary<Color, Int32>();
    for (Int32 y = 0; y < height; y++)
    {
        // Reset offset on every line, since stride is not guaranteed to always be width * pixel size.
        Int32 inputOffs = y * stride;
        //Final offset = y * line length in bytes + x * pixel length in bytes.
        //To avoid recalculating that offset each time we just increase it with the pixel size at the end of each x iteration.
        for (Int32 x = 0; x < width; x++)
        {
            //Get colour components out. "ARGB" is actually the order in the final integer which is read as little-endian, so the real order is BGRA.
            Color col = Color.FromArgb(imageData[inputOffs + 3], imageData[inputOffs + 2], imageData[inputOffs + 1], imageData[inputOffs]);
            Color bareCol = Color.FromArgb(255, col);
            // Only look at nontransparent pixels; cut off at 127.
            if (col.A > 127)
            {
                if (!colorFreq.ContainsKey(bareCol))
                    colorFreq.Add(bareCol, 1);
                else
                    colorFreq[bareCol]++;
            }
            // Increase the offset by the pixel width. For 32bpp ARGB, each pixel is 4 bytes.
            inputOffs += 4;
        }
    }
    // Get the maximum value in the dictionary values
    Int32 max = colorFreq.Values.Max();
    // Get the first colour that matches that maximum.
    return colorFreq.FirstOrDefault(x => x.Value == max).Key;
    // In case you want to know if there are multiple with the exact same frequency,
    // this could be expanded to give an array with all maxima like this:
    // Color[] maxCols = colorFreq.Where(x => x.Value == max).Select(kvp => kvp.Key).ToArray();
}

Do note that if the image is jpeg or something, this might not work too well, since it has slight fades on all colours. Then you'll have to somehow do a reduction of similar colours, or a threshold system. That's a whole different can of worms, though.

Nyerguds
  • 5,360
  • 1
  • 31
  • 63
0

http://www.codeproject.com/Questions/156542/how-i-can-get-color-in-image-by-c I hope this helps.

Here is an msdn link. http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.getpixel.aspx

Hope thats what you need. thanks.

Gaurav Deochakke
  • 2,265
  • 2
  • 21
  • 26
  • Yes, I'm aware of getting the color of a particular pixel. But I want something which stores an array of colors present in the image. I thought img.Palette would give me that, but it doesn't. – user3164272 May 13 '14 at 08:24
  • 1
    You can ,however, iterate through the entire image pixel by pixel using the GetPixel() method. like here: http://stackoverflow.com/questions/13748781/how-to-get-an-array-system-windows-media-color-from-a-bitmapimage But that may take a bit of time. LockBits might help you.. have a look here. http://stackoverflow.com/questions/3795268/find-a-color-in-an-image-in-c-sharp – Gaurav Deochakke May 13 '14 at 09:04