有一个程序可以为从白色到黑色的颜色渐变构建矩阵。然后,将抖动算法应用于矩阵以消除“条纹”。实现了4种抖动方法:有序,随机,Floyd-Steinberg,Jarvis-Judice-Ninke。首先,我创建一个特定大小的矩阵,将其转换为渐变,然后将结果输出为文件格式.pgm,类型为P5。如果将文件转换为.png,则会得到以下图像:
但是,放大图像时,可以看到条纹(如果仔细观察的话):
这是程序没有抖动的结果。问题是,如果将抖动算法之一应用于矩阵,则条纹会保留在图像上。结果表明抖动不起作用。有什么事吗我需要先使用抖动,然后建立渐变吗?还是错误是您需要创建一个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>
答案 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;
}