1

在推进我的有序抖动算法时,我遇到了一个问题,主要是我真的不知道 col[levels] 可能是什么。

这是伪代码

在此处输入图像描述

k - 每个通道的颜色值数量

n - 阈值 Bayers 矩阵的大小

我的代码在某种程度上适用于 K = 2,但是当 K = 3、K = 4 等时它不会返回正确的结果图像

更新代码

class OrderedDithering
{
    private float[,] bayerMatrix;

    private float[,] dither2x2Matrix =
        new float[,] { { 1, 3 },
                    { 4, 2 } };

    private float[,] dither3x3Matrix =
        new float[,] { { 3, 7, 4 },
                    { 6, 1, 9 },
                     { 2, 8, 5 } };

    public BitmapImage OrderedDitheringApply(BitmapImage FilteredImage, int valuesPerChannel, int thresholdSize)
    {
        Bitmap bitmap = ImageConverters.BitmapImage2Bitmap(FilteredImage);

        if (thresholdSize == 2)
        {
            bayerMatrix = new float[2, 2];
            for (int i = 0; i < 2; ++i)
                for (int j = 0; j < 2; ++j)
                    bayerMatrix[i,j] = dither2x2Matrix[i,j] / 5;
        }
        else
        {
            bayerMatrix = new float[3, 3];
            for (int i = 0; i < 3; ++i)
                for (int j = 0; j < 3; ++j)
                    bayerMatrix[i, j] = dither3x3Matrix[i, j] / 10;
        }

        for (int i = 0; i < bitmap.Width; ++i)
            for(int j = 0; j < bitmap.Height; ++j)
            {

                Color color = bitmap.GetPixel(i, j);
                double r = Scale(0, 255, 0, 1, color.R);
                double g = Scale(0, 255, 0, 1, color.G);
                double b = Scale(0, 255, 0, 1, color.B);

                int counter = 0;
                counter += Dither(valuesPerChannel, r, thresholdSize, i, j);
                counter += Dither(valuesPerChannel, g, thresholdSize, i, j);
                counter += Dither(valuesPerChannel, b, thresholdSize, i, j);

                if (counter == 0)
                    bitmap.SetPixel(i, j, Color.FromArgb(0,0,0));
                else
                    bitmap.SetPixel(i, j, Color.FromArgb(255/counter, 255/counter, 255/counter));
            }

        return ImageConverters.Bitmap2BitmapImage(bitmap);
    }

    public int Dither(int valuesPerChannel, double colorIntensity, int thresholdSize, int i, int j)
    {
        double tempValue = (double)(Math.Floor((double)((valuesPerChannel - 1) * colorIntensity)));
        double re = (valuesPerChannel - 1) * colorIntensity - tempValue;

        if (re >= bayerMatrix[i % thresholdSize, j % thresholdSize])
            return 1;
        else
            return 0;
    }

    public double Scale(double a0, double a1, double b0, double b1, double a)
    {
        return b0 + (b1 - b0) * ((a - a0) / (a1 - a0));
    }
}
4

1 回答 1

1

如果您只需要一个与System.Drawing有序抖动一起使用并支持有序抖动的抖动库,请随意使用的。它有一个易于使用的OrderedDitherer类。

但是如果你只是为了好奇而玩,并且想改进你的算法,这里有一些评论:

  • 您现在始终将像素设置为黑色或白色(顺便说一句,例如,您可以使用Color.Black代替FromArgb(0, 0, 0)),因此它不能用于更多颜色
  • 从提供的代码中不清楚目标调色板是否属于,colorsNum但基本上您需要将所有抖动像素量化为最接近的变换颜色。
  • 因此,您应该为每个像素的每个颜色通道(在 0..255 范围之间)应用有序矩阵,而不是按亮度工作,然后从目标调色板中选择一种颜色作为结果。“最近的颜色”可以有更多的解释,但通常欧几里得搜索会做到这一点。
  • 尽量避免使用Bitmap.SetPixel/ GetPixel,因为它们非常慢,SetPixel甚至不适用于具有索引调色板的位图PixelFormat
  • 您的代码未显示矩阵的值,但还应针对您使用的调色板校准这些值。典型的默认值适用于 BW 调色板,但它们对于 256 调色板来说可能太强了(抖动“跳过”更多的阴影并引入了噪声而不是漂亮的渐变)。有关更多信息,请参阅页面。

随意探索链接的代码库。Dither扩展方法是就地抖动的起点Bitmap,这里是OrderedDitherer 构造函数、矩阵的最小值/最大值的强度校准以及通过 RGB 通道或亮度进行的相当快的最近颜色搜索。

于 2020-06-12T20:37:55.387 回答