I would like to be able to detect the 3-4 main colors of a jpg image file.
Example images and sample code below:
- red, black, white
- white, green, pink
- blue, yellow, black
I have modified some code to get the below, but still has trouble grouping colors.
public static int RoundColorToGroup(int i)
{
int r = ((int)Math.Round(i / 10.0)) * 10;
if (r > 255)
r = 255;
return r;
}
[TestMethod]
public void AverageColorTest_WebExample()
{
Bitmap bm = new Bitmap("C:\\Users\\XXXX\\Desktop\\example1.jpg");
int width = bm.Width;
int height = bm.Height;
int red = 0;
int green = 0;
int blue = 0;
int minDiversion = 15; // drop pixels that do not differ by at least minDiversion between color values (white, gray or black)
int dropped = 0; // keep track of dropped pixels
int bppModifier = bm.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb ? 3 : 4; // cutting corners, will fail on anything else but 32 and 24 bit images
BitmapData srcData = bm.LockBits(new System.Drawing.Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, bm.PixelFormat);
int stride = srcData.Stride;
IntPtr Scan0 = srcData.Scan0;
Dictionary<string, Int64> dicColors = new Dictionary<string, long>(); // color, pixelcount i.e ('#FFFFFF',100);
unsafe
{
byte* p = (byte*)(void*)Scan0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int idx = (y * stride) + x * bppModifier;
red = p[idx + 2];
green = p[idx + 1];
blue = p[idx];
red = RoundColorToGroup(red);
green = RoundColorToGroup(green);
blue = RoundColorToGroup(blue);
if (Math.Abs(red - green) > minDiversion || Math.Abs(red - blue) > minDiversion || Math.Abs(green - blue) > minDiversion)
{
string htmlColorGroup = ColorTranslator.ToHtml(Color.FromArgb(red, green, blue));
if (dicColors.ContainsKey(htmlColorGroup))
{
dicColors[htmlColorGroup]++;
}
else
{
dicColors.Add(htmlColorGroup, 1);
}
}
else
{
dropped++;
}
}
}
}
dicColors = dicColors.OrderByDescending(x => x.Value).ToDictionary(pair => pair.Key, pair => pair.Value);
Console.WriteLine(dicColors.ElementAt(0).Key); // should ouput main color 1
Console.WriteLine(dicColors.ElementAt(1).Key); // should ouput main color 2
Console.WriteLine(dicColors.ElementAt(2).Key); // should ouput main color 3
}
- output for example1.jpg is (#FF6E8C, #FF6482, #FA6E8C) - 3 shades of red/pink - should be red, black and white
- output for example2.jpg is (#F0C8C8,#C8DC6E,#E6C8C8) - 2 shades of pinkand green - should be light pink, green, white
- output for example3.jpg is (#FFDC50,#640A28,#8C1E3C) - 3 shades of blue - should be blue, yellow, black
Ideally needs to ignore background color (#FFFFFF) and black outlining/shading.
Can copy paste html colors online here