【问题标题】:Ordered Dithering - Color Values Per Channel有序抖动 - 每个通道的颜色值
【发布时间】:2020-06-12 17:45:45
【问题描述】:

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

这是伪代码

k - 每个通道的颜色值数

n - 阈值拜耳矩阵的大小

我的代码在 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));
    }
}

【问题讨论】:

    标签: c# image-processing dithering


    【解决方案1】:

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

    但如果你只是出于好奇而玩,并且想改进你的算法,这里有一些 cmets:

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

    随意探索链接的代码库。 Dither 扩展方法是就地抖动Bitmap 的起点,这里是OrderedDitherer constructorstrength calibration 用于矩阵的最小/最大值和相当快的nearest color search RGB 通道或亮度。

    【讨论】:

    • 感谢您的回复。我已经稍微更改了代码,但我不确定它现在是否返回正确的图像。关于您的 cmets:是的,没有办法获得更多颜色,我现在已将其更改为新逻辑,现在可以看到更多灰色阴影。 ColorsNum 变量是来自输入的值,即每个通道的颜色值数量(命名不好)。真的需要使用最近的颜色搜索吗?
    • 如果您可以使用快速直接映射,您可以避免最近的颜色搜索。 grayscale palette 很容易。自定义映射函数可以传递给我在答案中链接的Palette 类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-26
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多