当前位置: 首页 > 知识库问答 >
问题:

对于一个jpg图像文件获得3-4平均主色

曾阳飙
2023-03-14

我想能够检测出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

    }
  • example1.jpg的输出是(#FF6E8C,#FF6482,#FA6E8C)-3种红色/粉红色-应该是红色,黑色和白色
  • example2.jpg的输出是(#F0C8C8,#C8DC6E,#E6C8C8)-2种颜色的粉红色和绿色-应该是浅粉色,绿色,白色
  • example3.jpg的输出是(#FFDC50,#640A28,#8C1E3C)-3种蓝色-应该是蓝色,黄色,黑色

理想情况下需要忽略背景颜色(#FFFFFF)和黑色轮廓/阴影。

可以在这里复制粘贴html颜色

共有3个答案

安毅
2023-03-14

我认为你应该使用一些图像处理库,比如Imagemagick或Opencv。这些库中有提取像素颜色的方法。您只需要将这些库链接到您的项目。我使用imagemagick从图像中提取主要颜色,但那是一个cpp应用程序。我想。net interfece也为imagemagick提供了支持

谢啦

沃阳飙
2023-03-14

非常感谢您的提示和本文。

以下是解决方案:

>

  • 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;
    }
    

  • 陆涵畅
    2023-03-14

    我做过这样的任何颜色分析器应用程序,你可以看到它是如何工作的。你完全在正确的轨道上。如果需要,将图像缩小到128x128等小尺寸以保持性能。

    然后,需要使用C#将RGB值转换为颜色角度。

    现在需要创建颜色计数的任何排序。例如,我完全建议将颜色角度从360°=360个项目缩小到大约36个颜色项目。现在,您只需在具有大多数颜色计数的排序列表中选择第一种颜色。

     类似资料:
    • 问题内容: 我希望能够拍摄图像并找出平均颜色是多少。意思是如果图像是半黑半白,我会在两者之间得到一些…灰色阴影。它可能是最常见的单色或中间值。任何平均值都可以。 我该如何在android中做到这一点。 问题答案:

    • 我想知道我是否正确理解了图像的平均归一化。 据我所知,您计算所有像素的平均值(假设它是灰度)。然后,对于每个像素,减去该平均值。 但是,人们应该如何处理可能出现的负值呢?例如,整个图像的平均值为100,但一个特定像素的强度为90。在这个标准化之后,像素的值将是-10。

    • 我不能得到熊猫的平均值或平均值。有一个数据框。下面我尝试的东西都没有给我列的平均值 以下内容返回多个值,而不是一个值: 这也是:

    • 问题内容: 不确定是否可行,但希望编写一个脚本来返回图像的平均值或值。我知道可以在AS中完成,但希望在JavaScript中完成。 问题答案: AFAIK,做到这一点的唯一方法是… 请注意,这仅适用于相同域中的图像以及支持HTML5 canvas的浏览器:

    • 问题内容: 我的表中有一列具有FLOAT类型的值。如何获得此列中所有元素的平均值? 问题答案: 这将平均所有行。要平均子集,请使用子句。要平均每个组(某物),请使用by子句。

    • 问题内容: 我需要获得fname,lname,比平均工资低400.00美元的员工薪水,即使在加薪10%之后。 我能够使薪水低于平均薪水的员工,但不确定如何使加薪后的薪水低于400美元的员工。 我正在使用MySQL。谢谢你。 这给了我工资低于平均工资的员工: 我当时在想这样的事情,但这是行不通的。未知专栏新闻: 问题答案: 您有一个正确的想法,就是不能在这样的子句中使用别名。只需直接使用公式,就可以