我正在尝试找到图像的主色。我正在使用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 值减半,结果有所改善,但还没有达到准确的程度。例如,黄色图像将主色返回为白色。深绿色图像返回主色为黑色等。
我怎样才能完成这项工作
编辑:我不想找到图像的平均颜色。我正在寻找一种方法,将每个像素的颜色分类/映射到特定的预定义颜色,然后找到最重复的颜色。
最佳答案
我必须做类似的事情。作为输入颜色,我使用了 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);
}
}
关于c# - 查找图像中的主色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30103425/