我试图找到图像的主色。我正在使用ColorMine进行颜色比较。基本上我有一个颜色模板,我比较每个像素。
距离最少的颜色从模板中选出,作为该像素的代表。
public class ColorItem
{
public enum Colors
{
White ,
Black ,
Gray ,
Red ,
Orange ,
Yellow ,
Green ,
Cyan ,
Blue ,
Magenta,
Pink ,
Brown ,
None,
}
public ColorItem(Color color, Colors colorType)
{
this.color = color;
this.colorType = colorType;
}
public Colors colorType;
public Color color;
}
//The color template that I am comparing against, which I cannot help but to
//Think that this is the issue
public class ColorTemplate
{
public static Color white = Color.FromArgb(255,255,255);
public static Color black = Color.FromArgb(0, 0, 0);
public static Color gray = Color.FromArgb(150, 150, 150);
public static Color red = Color.FromArgb(255, 0, 0);
public static Color orange = Color.FromArgb(255, 150, 0);
public static Color yellow = Color.FromArgb(255, 255, 0);
public static Color green = Color.FromArgb(0, 255, 0);
public static Color cyan = Color.FromArgb(0, 255, 255);
public static Color blue = Color.FromArgb(0, 0, 255);
public static Color magenta = Color.FromArgb(255, 0, 255);
public static Color pink = Color.FromArgb(255, 150, 255);
public static Color brown = Color.FromArgb(150, 90, 25);
}
private static List<ColorItem> _template = new List<ColorItem>
{
new ColorItem(ColorTemplate.black, ColorItem.Colors.Black),
new ColorItem(ColorTemplate.blue, ColorItem.Colors.Blue),
new ColorItem(ColorTemplate.brown, ColorItem.Colors.Brown),
new ColorItem(ColorTemplate.cyan, ColorItem.Colors.Cyan),
new ColorItem(ColorTemplate.gray, ColorItem.Colors.Gray),
new ColorItem(ColorTemplate.green, ColorItem.Colors.Green),
new ColorItem(ColorTemplate.magenta, ColorItem.Colors.Magenta),
new ColorItem(ColorTemplate.orange, ColorItem.Colors.Orange),
new ColorItem(ColorTemplate.pink, ColorItem.Colors.Pink),
new ColorItem(ColorTemplate.red, ColorItem.Colors.Red),
new ColorItem(ColorTemplate.white, ColorItem.Colors.White),
new ColorItem(ColorTemplate.yellow, ColorItem.Colors.Yellow)
};
public bool GetDominantColor(string filePath, out List<ColorPercentages> domColor)
{
domColor = new List<ColorPercentages>();
Bitmap bmp = null;
try
{
bmp = new Bitmap(filePath);
}
catch (Exception)
{
}
if (bmp == null)
return false;
//Used for tally
var total = 0;
var countWhite = 0;
var countBlack = 0;
var countGray = 0;
var countRed = 0;
var countOrange = 0;
var countYellow = 0;
var countGreen = 0;
var countCyan = 0;
var countBlue = 0;
var countMagenta = 0;
var countPink = 0;
var countBrown = 0;
for (var x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
total++;
var clr = bmp.GetPixel(x, y);
var near = FindNearestColor(clr);
switch (near)
{
case ColorItem.Colors.Black:
countBlack++;
break;
case ColorItem.Colors.Blue:
countBlue++;
break;
case ColorItem.Colors.Brown:
countBrown++;
break;
case ColorItem.Colors.Cyan:
countCyan++;
break;
case ColorItem.Colors.Gray:
countGray++;
break;
case ColorItem.Colors.Green:
countGreen++;
break;
case ColorItem.Colors.Magenta:
countMagenta++;
break;
case ColorItem.Colors.Orange:
countOrange++;
break;
case ColorItem.Colors.Pink:
countPink++;
break;
case ColorItem.Colors.Red:
countRed++;
break;
case ColorItem.Colors.White:
countWhite++;
break;
case ColorItem.Colors.Yellow:
countYellow++;
break;
}
}
}
domColor.Add(new ColorPercentages((int)(((double)countWhite / (double)total) * 100), ColorItem.Colors.White));
domColor.Add(new ColorPercentages((int)(((double)countBlack / (double)total) * 100), ColorItem.Colors.Black));
domColor.Add(new ColorPercentages((int)(((double)countGray / (double)total) * 100), ColorItem.Colors.Gray));
domColor.Add(new ColorPercentages((int)(((double)countRed / (double)total) * 100), ColorItem.Colors.Red));
domColor.Add(new ColorPercentages((int)(((double)countOrange / (double)total) * 100), ColorItem.Colors.Orange));
domColor.Add(new ColorPercentages((int)(((double)countYellow / (double)total) * 100), ColorItem.Colors.Yellow));
domColor.Add(new ColorPercentages((int)(((double)countGreen / (double)total) * 100), ColorItem.Colors.Green));
domColor.Add(new ColorPercentages((int)(((double)countCyan / (double)total) * 100), ColorItem.Colors.Cyan));
domColor.Add(new ColorPercentages((int)(((double)countBlue / (double)total) * 100), ColorItem.Colors.Blue));
domColor.Add(new ColorPercentages((int)(((double)countMagenta / (double)total) * 100), ColorItem.Colors.Magenta));
domColor.Add(new ColorPercentages((int)(((double)countPink / (double)total) * 100), ColorItem.Colors.Pink));
domColor.Add(new ColorPercentages((int)(((double)countBrown / (double)total) * 100), ColorItem.Colors.Brown));
domColor.Sort(new SortColorPercentagesDescending());
return true;
}
private ColorItem.Colors FindNearestColor(Color input)
{
ColorItem.Colors nearest_color = ColorItem.Colors.None;
var distance = 255.0;
Rgb inColoRgb = new Rgb {R = input.R, G = input.G, B = input.B};
Lab inColorLab = inColoRgb.To<Lab>();
foreach (var colorItem in _template)
{
Rgb templateColorRgb = new Rgb {R = colorItem.color.R, G = colorItem.color.G, B = colorItem.color.B};
Lab templateColorLab = templateColorRgb.To<Lab>();
var target = new CieDe2000Comparison();
var tempRes = inColoRgb.Compare(templateColorRgb, target);
if (tempRes == 0.0)
{
nearest_color = colorItem.colorType;
break;
}
else if (tempRes < distance)
{
distance = tempRes;
nearest_color = colorItem.colorType;
}
}
return nearest_color;
}
public class SortColorPercentagesDescending : Comparer<ColorPercentages>
{
public override int Compare(ColorPercentages x, ColorPercentages y)
{
if (x == null || y == null)
return -1;
if (x.Percentage > y.Percentage)
return -1;
if (x.Percentage < y.Percentage)
return 1;
return 0;
}
}
public class ColorPercentages
{
public int Percentage;
public ColorItem.Colors Color;
public ColorPercentages(int percentage, ColorItem.Colors color)
{
Percentage = percentage;
Color = color;
}
}
此处的两个主要功能是GetDominantColor
和FindNearestColor
。第一个将图像文件加载到位图中并迭代每个像素,找到最接近的颜色并增加该颜色的计数。一旦它遍历所有像素,它就会计算每种颜色的出现百分比,并将它们按列表返回给调用者按颜色百分比排序。
FindNearestColor
函数使用ColorMine的CieDe2000Comparison实现将每个像素与硬编码模板进行比较,并返回最接近的模板颜色作为像素的颜色。
现在,我不禁想到问题在于我使用的颜色模板。我不知道如何调整这些来给出准确的结果。我尝试将RGB值减半,结果有所改善,但还没有达到准确的程度。例如,黄色图像将主色返回为白色。深绿色图像将主色返回为黑色,依此类推。
我该如何开展这项工作
编辑:我不是要找到图像的平均颜色。我正在寻找的是一种方法来将每个像素的颜色分类/映射到特定的预定义颜色,然后找到最重复的颜色。
答案 0 :(得分:1)
在我看来,ColourTemplate
的起始值与您预期的相差无几。
一种解决方案是对所有颜色进行分类(尝试谷歌搜索&#34; CIE颜色&#34;),并查看您同意和不同意您的节目分类的位置。
伪代码:
Image CategoriseImage (Image input) {
Image result = new Image(input.height, image.width);
foreach (pixel in input) {
colour c = FindNearestColour(pixel);
result.SetColour(c, pixel.x, pixel.y);
}
return result;
}
然后您可以保存图像或显示图像。它可能涉及一些试验和错误,但您应该能够在ColourTemplate
周围移动种子值,直到您对它们对每种颜色分类的内容感到满意为止。
答案 1 :(得分:1)
很难解释什么是主导色彩&#39;在你的问题中真正意味着没有更精确的定义或知道应用程序是什么。
Image Color Summarizer网络服务示例显示直接像素平均值非常好。 您可以尝试在该网站上使用的一些图片,以了解平均/中位数统计数据是否足以达到您的目的。
This answer建议使用k-means量化,看起来也很不错。
答案 2 :(得分:0)
我必须做类似的事情。作为输入颜色,我使用了System.Drawing.KnownColor中的所有值,但您可以非常轻松地更改该部分。
下面的代码获取图像中最常用的颜色,然后尝试将其与已知颜色匹配。
class Program
{
static void Main(string[] args)
{
var image = (Bitmap)Image.FromFile(@"C:\temp\colorimage3.bmp");
var mostUsedColor = GetMostUsedColor(image);
var color = GetNearestColor(mostUsedColor);
Console.WriteLine(color.Name);
Console.ReadKey();
}
private static Color GetNearestColor(Color inputColor)
{
var inputRed = Convert.ToDouble(inputColor.R);
var inputGreen = Convert.ToDouble(inputColor.G);
var inputBlue = Convert.ToDouble(inputColor.B);
var colors = new List<Color>();
foreach (var knownColor in Enum.GetValues(typeof(KnownColor)))
{
var color = Color.FromKnownColor((KnownColor) knownColor);
if (!color.IsSystemColor)
colors.Add(color);
}
var nearestColor = Color.Empty;
var distance = 500.0;
foreach (var color in colors)
{
// Compute Euclidean distance between the two colors
var testRed = Math.Pow(Convert.ToDouble(color.R) - inputRed, 2.0);
var testGreen = Math.Pow(Convert.ToDouble(color.G) - inputGreen, 2.0);
var testBlue = Math.Pow(Convert.ToDouble(color.B) - inputBlue, 2.0);
var tempDistance = Math.Sqrt(testBlue + testGreen + testRed);
if (tempDistance == 0.0)
return color;
if (tempDistance < distance)
{
distance = tempDistance;
nearestColor = color;
}
}
return nearestColor;
}
public static Color GetMostUsedColor(Bitmap bitMap)
{
var colorIncidence = new Dictionary<int, int>();
for (var x = 0; x < bitMap.Size.Width; x++)
for (var y = 0; y < bitMap.Size.Height; y++)
{
var pixelColor = bitMap.GetPixel(x, y).ToArgb();
if (colorIncidence.Keys.Contains(pixelColor))
colorIncidence[pixelColor]++;
else
colorIncidence.Add(pixelColor, 1);
}
return Color.FromArgb(colorIncidence.OrderByDescending(x => x.Value).ToDictionary(x => x.Key, x => x.Value).First().Key);
}
}