c# - 颜色量化 - 流行度算法
问题描述
我应该编写一个负责使用流行度算法方法的颜色量化的算法。但是我找不到任何好的解释。
所以我理解的步骤如下:
获取 K 种最常出现的颜色
- 要获得它们,需要创建 RGB 直方图
- 然后检查直方图局部最大值处的颜色
对于每个像素,找到最接近的颜色并用新颜色替换它的颜色
这些步骤正确吗?
如果是这样,那么我仍然需要。我已经创建了一个负责获取 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));
}
}
解决方案
推荐阅读
- r - Highcharter Unlimited 使用 R 向下钻取
- android - 从 Android Studio 运行 Gradle 脚本时未加载 Bashrc
- javascript - 在 sequelize 范围内包含一对多关联
- woocommerce - 如何让 WooCommerce 变化价格具有两位小数(尾随零)?
- react-native - ReactNative:元素出现在顶部但不会触发 onPress
- c# - 如何判断数组中是否存在特定的短整型变量值?
- swift - 子类中的委托方法有时不使用 Swift 5 编译器调用
- c++ - cmake + qt + vtk:macOS Mojave 中的编译错误
- python - 如何训练具有不同频率的两个类的cnn?
- keras - Keras - 如何在不损害计算图的情况下删除无用的维度?