三 使用C++和Qt的涂鸦程序( 二 )


其中 M A X I MAX_{I} MAXI?在8位灰度模式下就是
M A X I = 2 8 ? 1 = 255 MAX_{I}=2^{8}-1=255 MAXI?=28?1=255 M S E = 1 m n ∑ i = 0 m ? 1 ∑ j = 0 n ? 1 [ I ( i , j ) ? K ( i , j ) ] 2 MSE=\frac{1}{mn}\sum_{i=0}^{m-1}\sum_{j=0}^{n-1}[I(i,j)-K(i,j)]^{2} MSE=mn1?i=0∑m?1?j=0∑n?1?[I(i,j)?K(i,j)]2
MSE的计算
忽略色彩的话计算特别简单,但是这里需要多种颜色信息的话怎么做呢?
关键在与MSE计算公式中的
I ( i , j ) ? K ( i , j ) I(i,j)-K(i,j) I(i,j)?K(i,j)这一部分在图像处理中可以理解为像素点间颜色的距离,在灰度模式下就是明暗差别 。
在彩色信息下如何衡量颜色距离是一个关键的问题 。其中的关键点在于颜色空间
衡量颜色距离的比较好的色彩空间是CIE Lab颜色空间,关于Lab颜色空间的描述网上有许多,这里不在大费笔墨 。CIE Lab颜色空间的一大特点是数值上变化带来颜色变化和感官上颜色变化是一致的,用来衡量色彩距离是再好不过 。
RGB颜色转到Lab颜色,再计算颜色距离是个复杂的过程,具体可以参考
在程序代码是
//默认是小端模式,0xAARRGGBB,则读出来第一个则是BBdouble getLABColorDistance(const unsigned char * c1,const unsigned char * c2){long rmean = ((c1[2] + c2[2]) / 2);long r = (c1[2] - c2[2]);long g = (c1[1] - c2[1]);long b = (c1[0] - c2[0]);return sqrt((((512 + rmean)*r*r) >> 8) + 4 * g*g + (((767 - rmean)*b*b) >> 8));}
Qt里图像的数据流格式,读出来的第一位是BB,程序里也延续这个做法比较方便 。这个颜色计算是每个像素点都要用到的,以这样的函数调用方式开销比较大 。因此改为内联的方式以提高速度
inline double getLABColorDistance(const unsigned char *c1, const unsigned char *c2){return sqrt((((512 + ((c1[2] + c2[2]) / 2))*(c1[2] - c2[2])*(c1[2] - c2[2])) >> 8) + 4 * (c1[1] - c2[1])*(c1[1] - c2[1]) + (((767 - ((c1[2] + c2[2]) / 2))*(c1[0] - c2[0])*(c1[0] - c2[0])) >> 8));}
压缩后不方便阅读,但是计算的方法是一样的 。
这样计算时就考虑到颜色信息,也考虑到空间信息了 。
M A X I MAX_{I} MAXI?的取值
还有另外一个问题是 M A X I MAX_{I} MAXI?,在单通道的灰度模式下是颜色数量,在采用了Lab颜色距离下忍采用颜色数量并不合理,RGB的颜色数量已经是 2 24 ? 1 =2^{24}-1= 224?1=种,一个这个数字计算下,即使两幅图像每一个像素都达到了最大差距,PSNR也能轻松破百 。而PSNR的值高于40就是说明图像非常接近原始图像了,显然不合适 。Lab颜色空间的种类比RGB、CMYK都要大得多,更加不合适
(笔者高等数学学得不太好,接下来这段纯属胡扯)
在灰度模式下,颜色是一维线性的,M A X I MAX_{I} MAXI?取颜色数量,仿照其中的物理意义将其扩展到Lab颜色空间,M A X I MAX_{I} MAXI?取RGB颜色转化成Lab后所能囊括的最大的颜色空间的的体积是个球体,其投影-圆的面积的特征长度直径D就是 M A X I MAX_{I} MAXI?的取值,约等于
M A X I ≈ 2113 MAX_{I}\ MAXI?≈2113
虽然是纯属臆测的取值方法,但是实际运用上还是能得出大致正确的结果
【三使用C++和Qt的涂鸦程序】这部分如果您有更好的方法,请在评论区留言