对于jpg图像文件,获得3-4个平均主色

我希望能够检测到jpg图像文件的3-4种主要颜色。

示例图像和示例代码如下:

图片示例1 – 红色,黑色,白色

图片示例2 – 白色,绿色,粉红色

图片示例3 – 蓝色,黄色,黑色

我修改了一些代码以获得以下内容,但仍然无法对颜色进行分组。

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 dicColors = new Dictionary(); // color, pixelcount ie ('#FFFFFF',100); unsafe { byte* p = (byte*)(void*)Scan0; for (int y = 0; y < height; y++) { for (int x = 0; x  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 } 
  • example1.jpg的输出是(#FF6E8C,#FF6482,#FA6E8C) – 3种红色/粉红色 – 应该是红色,黑色和白色
  • example2.jpg的输出是(#F0C8C8,#C8DC6E,#E6C8C8) – 2种粉红色和绿色 – 应该是浅粉色,绿色,白色
  • example3.jpg的输出是(#FFDC50,#640A28,#8C1E3C) – 3种蓝色 – 应该是蓝色,黄色,黑色

理想情况下需要忽略背景颜色(#FFFFFF)和黑色轮廓/阴影。

可以在线复制粘贴html颜色

我已经完成了任何颜色分析器应用程序 ,你可以看到它是如何工作的 。 你完全走在正确的轨道上。 如果需要缩小图像尺寸,如128×128,以保持性能。

色彩分析仪

然后,您需要使用C#将RGB值转换为Color Angle 。

现在您需要创建任何颜色计数排序 。 我完全建议将颜色角度从360°= 360度缩小到仅约36种颜色项目。 现在,您可以使用大多数颜色计数来拾取排序列表中的第一种颜色。

非常感谢您的提示和本文 。

这是解决方案:

  • GetWebColors() – 填充所有“命名”Web颜色的列表( http://www.w3schools.com/html/html_colornames.asp

  • GetNamedWebColor_NearestMatch(Color) – 对于任何给定的颜色(有16,777,216!),返回最近的’命名’web颜色(1 of 140)

  • GetMainXColors() – 返回前X个许多颜色,这些颜色因传入的最小HSL属性而不同(这将停止传回3个相同颜色的阴影)

调整:在此代码值下面修改(即对于色调,我们希望颜色之间的最小变化为10度。)

  float minHueDiff = (float)10; // 0 to 360 float minBrightDiff = (float)0.1; // 0 to 1 float minSatDiff = (float)0.1; // 0 to 1 

现在输出

  • example1.jpg的输出是:Gainsboro,Crimson,DarkSlateGray:现在接近白色,红色,黑色

  • example2.jpg的输出是:Gainsboro,DarkKhaki,Pink:现在接近白色,绿色,粉红色

  • example3.jpg的输出是:Black,DarkSlateBlue,Gold:正确

码:

 public void AverageColorTest_WebExample_FineTuned() { Bitmap bm = new Bitmap("C:\\Users\\XXX\\Desktop\\example1.jpg"); int width = bm.Width; int height = bm.Height; int red = 0; int green = 0; int blue = 0; float minDiversion = 30 / 100; // 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 dicColors = new Dictionary(); // color, pixelcount ie ('#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]; if (red == 255 && green == 255 && blue == 255) continue; Color GroupedColor = GetNamedWebColor_NearestMatch(red, green, blue); if (dicColors.ContainsKey(GroupedColor)) { dicColors[GroupedColor]++; } else { dicColors.Add(GroupedColor, 1); } } } } // sort dictionary of colors so that most used is at top dicColors = dicColors.OrderByDescending(x => x.Value).ToDictionary(pair => pair.Key, pair => pair.Value); List MainColors = null; Int16 numberOf = 3; float minHueDiff = (float)10; float minBrightDiff = (float)0.1; float minSatDiff = (float)0.1; MainColors = GetMainXColors(dicColors.Keys.ToList(), numberOf, minHueDiff, minBrightDiff, minSatDiff); foreach (Color MainColor in MainColors) { Console.WriteLine(ColorTranslator.ToHtml(MainColor)); // should ouput main colors } } ///  /// returns first x many colors that differ by min HSL properties passed in ///  ///  ///  ///  ///  ///  ///  private static List GetMainXColors(List listIn, Int32 ReturnMaxNumberOfColors, float minHueDiff, float minBrightDiff, float minSatDiff) { List response = new List(); Int32 i = 0; while (response.Count < ReturnMaxNumberOfColors && i < listIn.Count) { bool blnUniqueMainColor = true; // want main colors ie dark brown, gold, silver, not 3 shades of brown Color nextColor = listIn[i]; float brightness = nextColor.GetBrightness(); float sat = nextColor.GetSaturation(); float hue = nextColor.GetHue(); for (Int32 j = 0; j < response.Count; j++) { float brightnessOther = response[j].GetBrightness(); float satOther = response[j].GetSaturation(); float hueOther = response[j].GetHue(); // hue is 360 degrees of color, to calculate hue difference // need to subtract 360 when either are out by 180 (ie red is at 0 and 359, diff should be 1 etc) if (hue - hueOther > 180) hue -= 360; if (hueOther - hue > 180) hueOther -= 360; float brightdiff = Math.Abs(brightness - brightnessOther); float satdiff = Math.Abs(sat - satOther); float huediff = Math.Abs(hue - hueOther); int matchHSL = 0; if (brightdiff <= minBrightDiff) matchHSL++; if (satdiff <= minSatDiff) matchHSL++; if (huediff <= minHueDiff) matchHSL++; if (matchHSL != 0 & satdiff != 1)) { blnUniqueMainColor = false; break; } } if (blnUniqueMainColor) { // color differs by min ammount of HSL so add to response response.Add(nextColor); } i++; } return response; } private static List WebColors; ///  /// Returns the "nearest" color from a given "color space" ///  /// The color to be approximated /// The nearest color public static Color GetNamedWebColor_NearestMatch(double dbl_input_red, double dbl_input_green, double dbl_input_blue) { // get the colorspace as an ArrayList if (WebColors == null) WebColors = GetWebColors(); // the Euclidean distance to be computed // set this to an arbitrary number // must be greater than the largest possible distance (appr. 441.7) double distance = 500.0; // store the interim result double temp; // RGB-Values of test colors double dbl_test_red; double dbl_test_green; double dbl_test_blue; // initialize the result Color nearest_color = Color.Empty; foreach (Color o in WebColors) { // compute the Euclidean distance between the two colors // note, that the alpha-component is not used in this example dbl_test_red = Math.Pow(Convert.ToDouble(((Color)o).R) - dbl_input_red, 2.0); dbl_test_green = Math.Pow(Convert.ToDouble(((Color)o).G) - dbl_input_green, 2.0); dbl_test_blue = Math.Pow(Convert.ToDouble(((Color)o).B) - dbl_input_blue, 2.0); temp = Math.Sqrt(dbl_test_blue + dbl_test_green + dbl_test_red); // explore the result and store the nearest color if (temp < distance) { distance = temp; nearest_color = (Color)o; } } return nearest_color; } ///  /// Returns an ArrayList filled with "WebColors" ///  /// WebColors ///  private static List GetWebColors() { List listIgnore = new List(); listIgnore.Add("transparent"); Type color = (typeof(Color)); PropertyInfo[] propertyInfos = color.GetProperties(BindingFlags.Public | BindingFlags.Static); List colors = new List(); foreach (PropertyInfo pi in propertyInfos) { if (pi.PropertyType.Equals(typeof(Color))) { Color c = (Color)pi.GetValue((object)(typeof(Color)), null); if (listIgnore.Contains(c.Name.ToLower())) continue; colors.Add(c); } } return colors; } 

我认为你应该使用像Imagemagick或Opencv这样的图像处理库。有些方法可以在这些库中提取像素颜色。你只需要将这些库链接到你的项目。 我使用imagemagick从图像中提取主要颜色,但这是一个cpp应用程序。我认为.net interfece也适用于imagemagick

谢谢

我想如果你不想使用一些库,你应该使用HSL而不是RGB进行计算http://en.wikipedia.org/wiki/HSL_and_HSV