c# - 查找图像中的主色

标签 c# colors

我正在尝试找到图像的主色。我正在使用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;
        }
    }

这里的两个主要函数是GetDominantColorFindNearestColor 。第一个加载位图中的图像文件并迭代每个像素,找到最接近的颜色并递增该颜色的计数。一旦遍历完所有像素,它就会计算每种颜色的出现百分比,并将它们以列表形式返回给调用者,并按颜色百分比排序。

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/

相关文章:

c# - 通过计时器以 xamarin 形式重复异步任务

c# - 从非抽象类继承

linux - Eclipse 悬停和文档对话框具有深色背景

ios - 如何在 Swift 中选择随机颜色

c# - 如何将 SURF 兴趣点与图像数据库匹配

c# - 如何使用 EF DbContext 对查找表建模

C# ExecuteNonQuery 不更新数据库

javascript - 使用变量更改 ListView 的背景颜色

colors - Julia Plots.heatmap 颜色的日志比例不起作用

java - 如何在 Java 中制作形状 "blink"或更改颜色?