灰值转换
这里通过6种计算得到不同的灰阶图像。
( r + g + b ) / 3 (r+g+b)/3 (r+g+b)/3
0.3 ∗ r + 0.59 ∗ g + 0.11 ∗ b 0.3*r+0.59*g+0.11*b 0.3∗r+0.59∗g+0.11∗b
相比红色和绿色,人们更能察觉明亮的绿色,为了显示真实的明度,这样表示各通道的区别。
( m a x ( r , g , b ) + m i n ( r , g , b ) ) / 2 (max(r,g,b)+min(r,g,b))/2 (max(r,g,b)+min(r,g,b))/2
m a x ( r , g , b ) max(r,g,b) max(r,g,b)
m i n ( r , g , b ) min(r,g,b) min(r,g,b)
r o u n d ( ( r + g + b ) / 3 / 255 ) ∗ 255 round((r+g+b)/3/255)*255 round((r+g+b)/3/255)∗255
图像抖动
加入抖动让点的密度接近原图的灰度,画面的扁平突兀增加了细节之后会变得更重更有质感。
Floyd–Steinberg dithering
用
r
o
u
n
d
(
(
r
+
g
+
b
)
/
3
/
255
)
∗
255
round((r+g+b)/3/255)*255
round((r+g+b)/3/255)∗255计算的二阶黑白图像抖动之后出现了更多细节。
同理这里以JavaScript关键代码演示Floyd–Steinberg dithering算法来实现彩色图像抖动。
for(var i=0;i<imagedata.data.length/4;++i)
{
var oldred,oldgreen,oldblue,newred,newgreen,newblue,dividen,factor,imagewidth=720;
oldred=imagedata.data[i*4];
oldgreen=imagedata.data[i*4+1];
oldblue=imagedata.data[i*4+2];
dividen=2;
factor=255/(dividen-1);
newred=Math.round(oldred/factor)*factor;
newgreen=Math.round(oldgreen/factor)*factor;
newblue=Math.round(oldblue/factor)*factor;
imagedata.data[i*4]=newred;
imagedata.data[i*4+1]=newgreen;
imagedata.data[i*4+2]=newblue;
quanterrr=oldred-newred;
quanterrg=oldgreen-newgreen;
quanterrb=oldblue-newblue;
imagedata.data[i*4+4]=imagedata.data[i*4+4]+((i+1)%imagewidth!=0)*quanterrr*7/16;
imagedata.data[i*4+5]=imagedata.data[i*4+5]+((i+1)%imagewidth!=0)*quanterrg*7/16;
imagedata.data[i*4+6]=imagedata.data[i*4+6]+((i+1)%imagewidth!=0)*quanterrb*7/16;
imagedata.data[(i+imagewidth-1)*4]=imagedata.data[(i+imagewidth-1)*4]+quanterrr*3/16;
imagedata.data[(i+imagewidth-1)*4+1]=imagedata.data[(i+imagewidth-1)*4+1]+quanterrg*3/16;
imagedata.data[(i+imagewidth-1)*4+2]=imagedata.data[(i+imagewidth-1)*4+2]+quanterrb*3/16;
imagedata.data[(i+imagewidth)*4]=imagedata.data[(i+imagewidth)*4]+quanterrr*5/16;
imagedata.data[(i+imagewidth)*4+1]=imagedata.data[(i+imagewidth)*4+1]+quanterrg*5/16;
imagedata.data[(i+imagewidth)*4+2]=imagedata.data[(i+imagewidth)*4+2]+quanterrb*5/16;
imagedata.data[(i+imagewidth+1)*4]=imagedata.data[(i+imagewidth+1)*4]+((i+1)%imagewidth!=0)*quanterrr*1/16;
imagedata.data[(i+imagewidth)*4+1]=imagedata.data[(i+imagewidth)*4+1]+((i+1)%imagewidth!=0)*quanterrg*1/16;
imagedata.data[(i+imagewidth)*4+2]=imagedata.data[(i+imagewidth)*4+2]+((i+1)%imagewidth!=0)*quanterrb*1/16;
}
这里称一次抖动为一次采样,当前像素被采样之后所产生的量化误差转移给未被采样的临近的四个像素,如果当前像素向下取整,临近的像素向上取整的概率就更大,平均下来量化误差接近0。
如果给一张50%灰度图,红黄蓝三通道值都为127或者都为128,用Floyd–Steinberg dithering算法抖动之后会呈现出黑白棋盘的模样。
算法《https://wswmsword.github.io/2019/05/17/A-floyd-steinberg-dithering/》
参见Seven grayscale conversion algorithms (with pseudocode and VB6 source code)
YUV
A little more detail about Histograms
Dither
抖动 (数字信号处理)
Floyd–Steinberg dithering
噪点插画的六种绘制方法
Coding Challenge #90: Floyd-Steinberg Dithering