如何修复抖动方法以创建颜色渐变?

时间:2019-01-28 20:55:00

标签: c++ algorithm serialization graphics

有一个程序可以为从白色到黑色的颜色渐变构建矩阵。然后,将抖动算法应用于矩阵以消除“条纹”。实现了4种抖动方法:有序,随机,Floyd-Steinberg,Jarvis-Judice-Ninke。首先,我创建一个特定大小的矩阵,将其转换为渐变,然后将结果输出为文件格式.pgm,类型为P5。如果将文件转换为.png,则会得到以下图像:

enter image description here

但是,放大图像时,可以看到条纹(如果仔细观察的话):

enter image description here

这是程序没有抖动的结果。问题是,如果将抖动算法之一应用于矩阵,则条纹会保留在图像上。结果表明抖动不起作用。有什么事吗我需要先使用抖动,然后建立渐变吗?还是错误是您需要创建一个float或double类型的矩阵?我该如何解决?

代码:

  File "c:\users\waer8091\anaconda3\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "c:\users\waer8091\anaconda3\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\waer8091\Anaconda3\Scripts\virtualenv.exe\__main__.py", line 9, in <module>
  File "c:\users\waer8091\anaconda3\lib\site-packages\virtualenv.py", line 758, in main
    print("There must be only one argument: DEST_DIR (you gave {})".format(" ".join(args)))
  File "c:\users\waer8091\anaconda3\lib\encodings\cp1256.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode characters in position 52-53: character maps to <undefined>


1 个答案:

答案 0 :(得分:1)

有趣的是,您使用抖动消除了几乎看不到的频段-在过去,我们仅在必须每通道4位左右渲染时才会抖动。

无论如何...您的第一个问题是,在使用抖动将渐变降低到256级之前,必须以大于256级的更多渲染效果。 make_gradient可能应该在65536甚至是浮点处渲染渐变。

在我看来,您的第二个问题是您的抖动目前根本没有任何作用。 result[i][j]整数,因此,当您说类似result[i][j] = floor(result[i][j]);(我想您会忽略编译器有关转换的警告)时,它不会执行 。如果您在浮动中生成渐变,那么该问题也会消失。

如果您解决了这些问题,那么抖动就可以工作,但是这些抖动方法都不是在如此紧密间隔的水平上运行的最佳选择。完成后,可能仍然会残留某种形式的带状伪像(尽管您必须仔细地观察 才能看到它们)。为了使结果看起来尽可能好,您应该真正使用幅度等于两个量化级别的TPDF抖动。如果使用较粗的空间水平,则看上去比您的其他选择要嘈杂,但从统计学上讲,它是更均匀的,并且当水平间隔很小时,效果会更好。

这也很容易-只需在每个像素上添加两个介于-0.5和0.5之间的随机数,然后量化为整数即可。

这里提到了TPDF:https://en.wikipedia.org/wiki/Dither,但这是最重要的,因为它是用于信号处理的采样中的抖动类型,以确保量化不会引起任何一阶或二阶伪像。

编辑:

感谢您一直在努力,所以下面的代码一步一步即可创建最终形式的抖动渐变:

vector<vector<int>> make_dithered_gradient(int height, int width)
{
    assert(height > 0 && width > 0);

    vector<vector<int>> result(height, vector<int>(width));
    for (int i = 0; i < height; ++i)
    {
        // the target shade for each line of pixels is the average
        // ideal gradient value in that line, which is the same as the
        // ideal value in the middle of the line
        double target = ((double)i+0.5)*255.0/height;
        for (int j = 0; j < width; ++j)
        {
            double dither = ((double)rand()-(double)rand())/RAND_MAX;
            int val = (int)round(target+dither);
            if (val < 0)
                val = 0;
            if (val > 255)
                val = 255;
            result[i][j] = val;
        }
    }
    return result;
}

enter image description here