我希望能够检测到3-4主颜色的jpg图像文件。
下面是示例图像和示例代码:



我已经修改了一些代码以获得下面的内容,但是仍然难以分组颜色。
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
}理想情况下,需要忽略背景色(#FFFFFF)和黑色大纲/阴影。
可以复制粘贴html颜色在线这里
发布于 2013-11-08 14:30:21
非常感谢您的提示和这个文章。
以下是解决办法:
调优:此(即色调方面,我们希望在不同颜色之间改变10度。)的代码值下面的修正
float minHueDiff = (float)10; // 0 to 360
float minBrightDiff = (float)0.1; // 0 to 1
float minSatDiff = (float)0.1; // 0 to 1现在输出
代码:
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<Color, Int64> dicColors = new Dictionary<Color, 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];
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<Color> 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
}
}
/// <summary>
/// returns first x many colors that differ by min HSL properties passed in
/// </summary>
/// <param name="listIn"></param>
/// <param name="ReturnMaxNumberOfColors"></param>
/// <param name="minHueDiff"></param>
/// <param name="minBrightDiff"></param>
/// <param name="minSatDiff"></param>
/// <returns></returns>
private static List<Color> GetMainXColors(List<Color> listIn, Int32 ReturnMaxNumberOfColors, float minHueDiff, float minBrightDiff, float minSatDiff)
{
List<Color> response = new List<Color>();
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 (i.e 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<Color> WebColors;
/// <summary>
/// Returns the "nearest" color from a given "color space"
/// </summary>
/// <param name="input_color">The color to be approximated</param>
/// <returns>The nearest color</returns>
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;
}
/// <summary>
/// Returns an ArrayList filled with "WebColors"
/// </summary>
/// <returns>WebColors</returns>
/// <remarks></remarks>
private static List<Color> GetWebColors()
{
List<string> listIgnore = new List<string>();
listIgnore.Add("transparent");
Type color = (typeof(Color));
PropertyInfo[] propertyInfos = color.GetProperties(BindingFlags.Public | BindingFlags.Static);
List<Color> colors = new List<Color>();
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;
}发布于 2013-11-08 11:04:36
我已经做过这样的颜色分析器应用程序了,您可以看到它是如何作品的。你完全在正确的轨道上。如果需要,缩小图像的大小,如128x128,以保持性能。

然后,您需要将RGB值转换为使用C#的彩色角度。
现在,您需要创建任何颜色计数的排序。我完全建议缩小颜色角度从360°= 360项目到大约36个颜色项目,例如。现在,您可以只拾取排序列表中的第一种颜色,其颜色计数最多。
发布于 2013-11-08 06:21:00
我认为您应该使用一些图像处理库,比如Imagemagick或Opencv.There,它们是提取这些libraries.You中像素颜色的方法,只需将这些库链接到项目中即可。我使用了imagemagick从图像中提取主要颜色,但这是cpp应用程序,我认为.net接口也是用于imagemagick
谢谢
https://stackoverflow.com/questions/19808743
复制相似问题