首页 > 解决方案 > 颜色量化 - 流行度算法

问题描述

我应该编写一个负责使用流行度算法方法的颜色量化的算法。但是我找不到任何好的解释。

所以我理解的步骤如下:

  1. 获取 K 种最常出现的颜色

    • 要获得它们,需要创建 RGB 直方图
    • 然后检查直方图局部最大值处的颜色
  2. 对于每个像素,找到最接近的颜色并用新颜色替换它的颜色

这些步骤正确吗?

如果是这样,那么我仍然需要。我已经创建了一个负责获取 3 个直方图(R、G、B)的方法,据我所知,现在是时候使用它们来获取 K 种最常出现的颜色了。如果我是正确的,那么应该通过找到局部最大值来完成?那么我应该为每个直方图独立找到它们,然后将所有这些值收集在一起,对它们进行排序并将它们分组到一个包含 K 种颜色的较小组中吗?

目前我不知道如何找到最接近的最出现的颜色,但首先我想我需要在前面的步骤中取得成功。

谢谢你。

更新

好吧,这是我当前版本的算法。有用。我已对其进行了更改,因此它使用不安全代码而不是 SetPixel(...)/GetPixel(...)。它现在以某种方式更快地完成它的工作。有一次,我遇到了某种类型的内存错误,但不记得到底是什么。

但是,当输入中有更多 K 种颜色时,处理像素仍然需要一些时间(这也取决于要量化的图像)。你有什么方法可以让代码运行得更快吗?我观察到最消耗的部分是最后一个,主要是更改位图,因为获得 K 种最常见的颜色工作得非常快。

class PopularityQuantization
{
    public unsafe BitmapImage PopularityQuantizationApply(BitmapImage FilteredImage, int colorsNum)
    {
        Bitmap bitmap = ImageConverters.BitmapImage2Bitmap(FilteredImage);

        Dictionary<Color, long> histogram = Histogram.GetHistogram(bitmap);

        List<KeyValuePair<Color, long>> myList = histogram.ToList();
        myList.Sort((pair1, pair2) => pair1.Value.CompareTo(pair2.Value));     

        List<Color> topColors = new List<Color>();
        int i = myList.Count() - 1;
        int counter = 0;
        while (counter < colorsNum)
        {
            topColors.Add(myList[i].Key);

            counter++;
            i--;
        }

        #region lockbits
        BitmapData bData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);

        int bitsPerPixel = Bitmap.GetPixelFormatSize(bitmap.PixelFormat);

        byte* scan0 = (byte*)bData.Scan0.ToPointer();
        #endregion // lockbits

        for (int x = 0; x < bitmap.Width; ++x)
            for(int y = 0; y < bitmap.Height; ++y)
            {
                int r, g, b;

                byte* data = scan0 + x * bData.Stride + y * bitsPerPixel / 8;

                r = data[2];
                g = data[1];
                b = data[0];

                Color currentColor = Color.FromArgb(r, g, b);
                Color newColor = FindNearestNeighborColor(x, y, currentColor, topColors);

                data[2] = newColor.R;
                data[1] = newColor.G;
                data[0] = newColor.B;
            }

        bitmap.UnlockBits(bData);

        return ImageConverters.Bitmap2BitmapImage(bitmap);
    }

    private Color FindNearestNeighborColor(int x, int y, Color currentColor, List<Color> candidateColors)
    {
        int dMin = int.MaxValue;
        Color nearestCandidate = currentColor;

        foreach(Color candidateColor in candidateColors)
        {
            int distance = CalculateDistance(currentColor, candidateColor);
            if (distance < dMin)
            {
                dMin = distance;
                nearestCandidate = candidateColor;
            }
        }

        return nearestCandidate;
    }

    private int CalculateDistance(Color currentColor, Color candidateColor)
    {
        int distR = candidateColor.R - currentColor.R;
        int distG = candidateColor.G - currentColor.G;
        int distB = candidateColor.B - currentColor.B;

        return (int)(Math.Pow(distR, 2) + Math.Pow(distG, 2) + Math.Pow(distB, 2));
    }
}

标签: c#image-processingquantization

解决方案


推荐阅读