我想能够检测出jpg图像文件的3-4种主要颜色。
下面是示例图像和示例代码:
我已经修改了一些代码来获得下面的内容,但是仍然无法对颜色进行分组。
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颜色
我认为你应该使用一些图像处理库,比如Imagemagick或Opencv。这些库中有提取像素颜色的方法。您只需要将这些库链接到您的项目。我使用imagemagick从图像中提取主要颜色,但那是一个cpp应用程序。我想。net interfece也为imagemagick提供了支持
谢啦
非常感谢您的提示和本文。
以下是解决方案:
>
GetWebColors()-填充所有命名Web颜色的列表(http://www.w3schools.com/html/html_colornames.asp)
GetNamedWebColor_NearestMatch(颜色)-对于任何给定的颜色(有16,777,216!)返回最近的命名网页颜色(1/140)
调整:在代码值下面加一个(例如,对于色调,我们希望颜色之间的变化最小为10度)
float minHueDiff = (float)10; // 0 to 360
float minBrightDiff = (float)0.1; // 0 to 1
float minSatDiff = (float)0.1; // 0 to 1
现在输出
>
例如输出2。jpg是:Gainsboro,DarkKhaki,粉色:现在接近白色,绿色,粉色
代码:
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;
}
我做过这样的任何颜色分析器应用程序,你可以看到它是如何工作的。你完全在正确的轨道上。如果需要,将图像缩小到128x128等小尺寸以保持性能。
然后,需要使用C#将RGB值转换为颜色角度。
现在需要创建颜色计数的任何排序。例如,我完全建议将颜色角度从360°=360个项目缩小到大约36个颜色项目。现在,您只需在具有大多数颜色计数的排序列表中选择第一种颜色。
问题内容: 我希望能够拍摄图像并找出平均颜色是多少。意思是如果图像是半黑半白,我会在两者之间得到一些…灰色阴影。它可能是最常见的单色或中间值。任何平均值都可以。 我该如何在android中做到这一点。 问题答案:
我想知道我是否正确理解了图像的平均归一化。 据我所知,您计算所有像素的平均值(假设它是灰度)。然后,对于每个像素,减去该平均值。 但是,人们应该如何处理可能出现的负值呢?例如,整个图像的平均值为100,但一个特定像素的强度为90。在这个标准化之后,像素的值将是-10。
我不能得到熊猫的平均值或平均值。有一个数据框。下面我尝试的东西都没有给我列的平均值 以下内容返回多个值,而不是一个值: 这也是:
问题内容: 不确定是否可行,但希望编写一个脚本来返回图像的平均值或值。我知道可以在AS中完成,但希望在JavaScript中完成。 问题答案: AFAIK,做到这一点的唯一方法是… 请注意,这仅适用于相同域中的图像以及支持HTML5 canvas的浏览器:
问题内容: 我的表中有一列具有FLOAT类型的值。如何获得此列中所有元素的平均值? 问题答案: 这将平均所有行。要平均子集,请使用子句。要平均每个组(某物),请使用by子句。
问题内容: 我需要获得fname,lname,比平均工资低400.00美元的员工薪水,即使在加薪10%之后。 我能够使薪水低于平均薪水的员工,但不确定如何使加薪后的薪水低于400美元的员工。 我正在使用MySQL。谢谢你。 这给了我工资低于平均工资的员工: 我当时在想这样的事情,但这是行不通的。未知专栏新闻: 问题答案: 您有一个正确的想法,就是不能在这样的子句中使用别名。只需直接使用公式,就可以