本文是对OpenCV2.4.13文档的部分翻译,作个人学习之用,并不完整。
理论:
平滑(Smoothing),也叫做模糊(blurring),是一种简单常用的图像处理操作。
平滑有很多原因,在这里我们专注于为了减少噪声。
为了执行平滑操作,我们对图像采用一个滤波器。最常见的滤波器是线性的,输出像素的值是输入像素值的加权和。
h(k,l)叫做“核”(kernel),也就是滤波器的系数。它帮助我们将滤波器看作一个扫过图像的系数滑动窗口。
有许多种滤波器,这里我们提及最常用的:
归一化块滤波器 (Normalized Box Filter)
最简单的滤波器,每个输出的像素都是核的邻近元素的平均值,且权重都一样。
核:
高斯滤波器(Gaussian Filter)
最常用的滤波器(尽管不是最快的),通过使用高斯核卷积输入数组的每个点并且将他们求和来产生输出数组。
假设图像是一维,中间的像素有最大权重,邻近像素的权重随着他们和中央像素空间距离的增加而减少。
二维高斯函数可以这样表示:
μ是平均值(峰),σ是方差(对于每个变量x和y)
中值滤波器(Median Filter)
经过信号(图像)所有的点,用它邻近像素(位于该像素的方形邻域内)的中值来替换它。
双边滤波器(Bilateral Filter)
滤波器有时不仅会消除噪点,还会用于平滑边缘,为了避免这样,我们可以使用双边滤波器。
和高斯滤波器相似,双边滤波器也考虑邻近像素的权重,这些权重有两部分:第一部分和高斯滤波器使用的相同,第二部分考虑和邻近像素之间强度的不同。
#include <iostream>
#include <vector>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/features2d/features2d.hpp"
using namespace std;
using namespace cv;
/// Global Variables
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;
Mat src; Mat dst;//原图和目标图
char window_name[] = "Smoothing Demo";
/// Function headers
int display_caption( const char* caption );
int display_dst( int delay );
int main()
{
namedWindow( window_name, WINDOW_AUTOSIZE );
/// Load the source image
src = imread( "lena.png", 1 );
if( display_caption( "Original Image" ) != 0 ) { return 0; }
dst = src.clone();//先将数据复制到目标图像中
if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; }
/// 使用均匀模糊 Homogeneous blur
if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; }//提示
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
//blur(原图,目标图,核大小(宽,高),锚点位置)锚点位置和邻域相关,如果有负值则核的中心就是锚点
{ blur( src, dst, Size( i, i ), Point(-1,-1) );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// 使用高斯模糊 Gaussian blur
if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
//GaussianBlur(原图,目标图,核大小,x的标准差,y的标准差)0表示用核大小来计算标准差
{ GaussianBlur( src, dst, Size( i, i ), 0, 0 );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// 使用中值模糊 Median blur
if( display_caption( "Median Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
//mediaBlur(原图,目标图,核大小)使用方形窗口,核大小必须是奇数;目标图类型必须和原图一致
{ medianBlur ( src, dst, i );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// 使用双边模糊 Bilateral Filter
if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; }
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
//bilateralFilter(原图,目标图,每个像素邻域的直径,颜色空间的标准差,坐标空间的标准差(像素级别))
{ bilateralFilter ( src, dst, i, i*2, i/2 );
if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
/// 等待用户按键
display_caption( "End: Press a key!" );
waitKey(0);
return 0;
}
/**
* @function display_caption
*/
//提示下一种滤波器的名称
int display_caption( const char* caption )
{
dst = Mat::zeros( src.size(), src.type() );
putText( dst, caption,
Point( src.cols/4, src.rows/2),
FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );//显示文字
imshow( window_name, dst );
int c = waitKey( DELAY_CAPTION );
if( c >= 0 ) { return -1; }
return 0;
}
/**
* @function display_dst
*/
//显示滤波效果
int display_dst( int delay )
{
imshow( window_name, dst );
int c = waitKey ( delay );
if( c >= 0 ) { return -1; }
return 0;
}
结果:
原图:
归一化块
高斯
中值
双边