上一篇文章介绍了均值滤波、中值滤波、高斯滤波、双边滤波和引导滤波,均为局部滤波,即对周围邻域的点加权生成当前点,加权因子反应出周围点对当前点的影响。非局部滤波就意味着它使用图像中的所有像素,这些像素根据某种相似度进行加权平均。滤波后图像清晰度高,而且不丢失细节。
与上述算法思路不同,前者根据像素点之间的距离计算权重,后者根据块之间的相似度计算权重。其核心思路与高斯滤波很相似:计算矩形窗口内所有像素点的像素值加权和,权重服从高斯分布。区别在于:高斯滤波使用当前滤波点与矩形窗口内其它点的空间欧式距离来计算权重,距离越近权重越大;而非局部均值滤波则使用当前滤波点的邻域块与矩形窗口内其它点的邻域块的**相似度**来计算权重,相似度越大则权重越大。
左边是高斯滤波空间距离d,右边是非NLMeans相似度MSE。要衡量两个邻域块的相似度,有多种指标,均方误差(MSE)是最常用的相似度衡量指标之一。非局部均值滤波算法就是使用MSE来计算两个邻域块的相似度。邻域块的行列相同,假设均为m行n列,那么MSE的计算如下式,其中A(i,j)为点A邻域块中的点(i,j)的像素值,B(i,j)为点B邻域块中的相同位置点的像素值。
代码实现计算两个区域A,B的MSE:
//计算0~255的平方查找表floattable1[256]; staticvoidcal_lookup_table1(void) { for (inti=0; i<256; i++) { table1[i] = (float)(i*i); } } //计算两个0~255的数的绝对差值的查找表uchartable2[256][256]; staticvoidcal_lookup_table2(void) { for (inti=0; i<256; i++) { for (intj=i; j<256; j++) { table2[i][j] =abs(i-j); table2[j][i] =table2[i][j]; } } } floatMSE_block(MatA, MatB) { floatsum=0.0; for (intj=0; j<A.rows; j++) { uchar*data1=A.ptr<uchar>(j); uchar*data2=B.ptr<uchar>(j); for (inti=0; i<A.cols; i++) { sum+=table1[table2[data1[i]][data2[i]]]; } } sum=sum/ (A.rows*B.cols); returnsum; }

