显示图像中最常用的颜色

时间:2016-11-30 10:18:00

标签: c#

所以有人帮我制作了这段代码,告诉我照片中最常用的颜色:

class PictureAnalysis
{
    public static List<Color> TenMostUsedColors { get; private set; }
    public static List<int> TenMostUsedColorIncidences { get; private set; }

    public static Color MostUsedColor { get; private set; }
    public static int MostUsedColorIncidence { get; private set; }

    private static int pixelColor;

    private static Dictionary<int, int> dctColorIncidence;

    public static void GetMostUsedColor(Bitmap theBitMap)
    {
        TenMostUsedColors = new List<Color>();
        TenMostUsedColorIncidences = new List<int>();

        MostUsedColor = Color.Empty;
        MostUsedColorIncidence = 0;

        // does using Dictionary<int,int> here
        // really pay-off compared to using
        // Dictionary<Color, int> ?

        // would using a SortedDictionary be much slower, or ?

        dctColorIncidence = new Dictionary<int, int>();

        // this is what you want to speed up with unmanaged code
        for (int row = 0; row < theBitMap.Size.Width; row++)
        {
            for (int col = 0; col < theBitMap.Size.Height; col++)
            {
                pixelColor = theBitMap.GetPixel(row, col).ToArgb();

                if (dctColorIncidence.Keys.Contains(pixelColor))
                {
                    dctColorIncidence[pixelColor]++;
                }
                else
                {
                    dctColorIncidence.Add(pixelColor, 1);
                }
            }
        }

        // note that there are those who argue that a
        // .NET Generic Dictionary is never guaranteed
        // to be sorted by methods like this
        var dctSortedByValueHighToLow = dctColorIncidence.OrderByDescending(x => x.Value).ToDictionary(x => x.Key, x => x.Value);

        // this should be replaced with some elegant Linq ?
        foreach (KeyValuePair<int, int> kvp in dctSortedByValueHighToLow.Take(10))
        {
            TenMostUsedColors.Add(Color.FromArgb(kvp.Key));
            TenMostUsedColorIncidences.Add(kvp.Value);
        }

        MostUsedColor = Color.FromArgb(dctSortedByValueHighToLow.First().Key);
        MostUsedColorIncidence = dctSortedByValueHighToLow.First().Value;
    }

}

我试图像这样实施,但我不知道该怎么做才能向我展示最常用的颜色?

string filep = @"C:\Users\User\Desktop\Gallery\image" + NumberOfClick.ToString() + "cropped.png";

                Bitmap bMap = Bitmap.FromFile(filep) as Bitmap;

                PictureAnalysis.GetMostUsedColor(bMap);

我想确定一个&#34;真实&#34;中最常用的颜色。像这样的照片:I am cropping her "jacket" from the photo and I want a program that determines it as it is black

3 个答案:

答案 0 :(得分:0)

有两种方法:

<强>第一 将方法GetMostUsedColor的返回类型从void更改为int

public static int GetMostUsedColor(Bitmap theBitMap)
{
    TenMostUsedColors = new List<Color>();
    /*unchangeable code here*/
    return dctSortedByValueHighToLow.First().Value;
}

之后,此方法将返回最常用的颜色。

如果您在控制台中运行程序,

您可以将最后一行PictureAnalysis.GetMostUsedColor(bMap)替换为Console.WriteLine(PictureAnalysis.GetMostUsedColor(bMap)),以便获得最常用的颜色

第二种方式 (如果你使用控制台) 只需替换一行

public static void GetMostUsedColor(Bitmap theBitMap)
{
    /*unchangeable code here*/
     Console.WriteLine(dctSortedByValueHighToLow.First().Value);
}

答案 1 :(得分:0)

这个类是静态的,方法调用是静态的,结果也是......

所以要使用它:

string filep = @"C:\Users\User\Desktop\Gallery\image" + NumberOfClick.ToString() + "cropped.png";
Bitmap bMap = Bitmap.FromFile(filep) as Bitmap;
PictureAnalysis.GetMostUsedColor(bMap);

//Here you get the most used color
var Color MostUsed = PictureAnalysis.MostUsedColor;
//Here you get the ten most used colors
var List<Color> TenMostUsed = PictureAnalysis.TenMostUsedColor;

将颜色显示为字符串

在System.Drawing命名空间中,Microsoft在Color结构中定义了许多颜色。因此,可以从known color name创建颜色。

但是,您必须了解所有颜色都没有名称。因为它们很多。因此,并不总是可以在颜色上添加名称。

您可以尝试编写一种颜色并返回颜色名称的方法......但请记住,有超过1600万种可能性......

一种解决方案

我会做的是将颜色放在ColorDialog内。 然后,将其Color属性设置为最常用的颜色。

这样,用户至少可以查看颜色

另一种选择是在PropertyGrid中查看它,因为它们的ColorPicker也很好。

答案 2 :(得分:0)

有几种方法可以做到这一点。

以下是两个解决方案:

1

列出要比较的所有颜色。 我会列出颜色中的所有颜色。*

然后循环遍历所有像素并将每种颜色与列表进行比较以获取最接近的颜色,然后将该颜色保存为1出现的值,然后取下一个,依此类推,最后得到最主要颜色的列表列表中的那些。 然后只需获取该颜色并获取名称,因为它是真正的颜色。 像:

        var listOfColors = GetAllColors();

        var filename = @"D:\Nature-View.jpg";
        var image = Image.FromFile(filename);

        var smallImage = ResizeImage(image, 1, 1);

        var index = ClosestColor2(listOfColors, smallImage.GetPixel(0, 0));

        var closestColorName = listOfColors[index].Name;

要遍历图像中的所有像素,您可以使用GetPixel(),但这有点慢,因此您应该使用更快的方法,例如您可以在此处找到:https://github.com/realm/realm-dotnet

2

另一个应该起作用的简单解决方案是作弊并将图像调整为1x1像素的大小,然后在单个像素上获得最主要的颜色。这已经进行了一些简单的测试,它可能已经足够好了吗?否则使用第一个解决方案。

然后将该颜色与列表进行比较。

以下是最后一个解决方案的示例:

    private List<Color> GetAllColors() {
        var list = new List<Color>();
        var colorType = typeof(Color);
        var propInfos = colorType.GetProperties(BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Public);
        foreach (var propInfo in propInfos) {
            var color = Color.FromName(propInfo.Name);
            list.Add(color);
        }
        return list;
    }

    // closed match in RGB space
    private int ClosestColor2(List<Color> colors, Color target) {
        var colorDiffs = colors.Select(n => ColorDiff(n, target)).Min(n => n);
        return colors.FindIndex(n => ColorDiff(n, target) == colorDiffs);
    }

    // distance in RGB space
    private static int ColorDiff(Color c1, Color c2) {
        return (int) Math.Sqrt((c1.R - c2.R)*(c1.R - c2.R)
                               + (c1.G - c2.G)*(c1.G - c2.G)
                               + (c1.B - c2.B)*(c1.B - c2.B));
    }

    public static Bitmap ResizeImage(Image image, int width, int height) {
        var destRect = new Rectangle(0, 0, width, height);
        var destImage = new Bitmap(width, height);

        destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

        using (var graphics = Graphics.FromImage(destImage)) {
            graphics.CompositingMode = CompositingMode.SourceCopy;
            graphics.CompositingQuality = CompositingQuality.HighQuality;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

            using (var wrapMode = new ImageAttributes()) {
                wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
            }
        }

        return destImage;
    }

查找ClosestColor的方法取自此处:Travel through pixels in BMP

以下是其他方法:

{{1}}