对于JPG图像文件获得3-4的平均主色调 [英] For an jpg image file get 3-4 average main colors
问题描述
我想能够检测一个jpg图像文件的3-4主色调。
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
我修改了一些的code~~V 得到以下,但仍然有麻烦分组的颜色。
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
}
- 对于example1.jpg输出(#FF6E8C,#FF6482,#FA6E8C) - 红色/粉红色深浅3 - 应该是红色,黑色和白色
- 对于example2.jpg输出(#F0C8C8,#C8DC6E,#E6C8C8) - 2深浅pinkand绿色的 - 应该是淡粉色,绿色,白色
- 对于example3.jpg输出(#FFDC50,#640A28,# 8C1E3C) - 蓝3色调 - 应蓝色,黄色,黑色
-
GetWebColors() - 填充所有命名为网页颜色
名单(的 http://www.w3schools.com/html/html_colornames.asp )
理想情况下需要忽略背景色(#FFFFFF)和黑概述/阴影。
Ideally needs to ignore background color (#FFFFFF) and black outlining/shading.
Can copy paste html colors online here
推荐答案
非常感谢你的暗示,而这种的文章
Many thanks to your hints, and this article.
下面是解决方法:
GetNamedWebColor_NearestMatch(彩色) - 对于任何给定的颜色(有16777216!)返回最接近命名为Web颜色(140 1)
GetNamedWebColor_NearestMatch(Color) - For any given color (there are 16,777,216!) returns nearest 'Named' web color (1 of 140)
调整:ammend下面的代码值这个<一个HREF =http://upload.wikimedia.org/wikipedia/commons/0/0d/HSV_color_solid_cylinder_alpha_lowgamma.png相对=nofollow>(即色调,我们要的颜色之间的10度分钟的变化。)
Tuning: ammend below code values for this (i.e for hue, we want 10 degree min change between colors.)
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输出为:亮灰,深红,深青灰:现在接近白色,红色,黑色
output for example1.jpg is: Gainsboro, Crimson, DarkSlateGray : now close to white, red, black
对于example2.jpg输出为:亮灰,深卡其色,粉红色:现在接近白色,绿色,粉红色
output for example2.jpg is: Gainsboro, DarkKhaki, Pink : now close to white, green, pink
代码:
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;
}
这篇关于对于JPG图像文件获得3-4的平均主色调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!