只需遍历整个图像并对找到的每种颜色进行计数,然后获取计数最多的颜色。
执行此操作的最简单方法可能是使用 GetPixel,但对于可能需要很长时间的大图像。因此,您可以将图像粘贴到 32bppARGB 图像上,以确保它采用特定的已知格式,然后使用 LockBits 和 Marshal.Copy 取出原始字节,然后遍历这些字节,将它们组合成每四个颜色,然后检查那些颜色。
为了真正获得最大值,我会使用字典,其中颜色作为键,数量作为值。
所有的一切,你得到这个:
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 * bm.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();
}
请注意,如果图像是 jpeg 之类的,这可能效果不太好,因为它在所有颜色上都有轻微的褪色。然后你必须以某种方式减少相似的颜色,或阈值系统。不过,那是完全不同的蠕虫罐头。