对于JPG图像文件获得3-4的平均主色调 [英] For an jpg image file get 3-4 average main colors

查看:109
本文介绍了对于JPG图像文件获得3-4的平均主色调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想能够检测一个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色调 - 应蓝色,黄色,黑色

  • 理想情况下需要忽略背景色(#FFFFFF)和黑概述/阴影。

    Ideally needs to ignore background color (#FFFFFF) and black outlining/shading.

    可以在这里复制粘贴HTML色彩在线

    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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆