通常,平滑图像的目的是为了减少噪声和伪影。OpenCv提供5种不同的平滑操作。
目录
1. 简单模糊cv::blur()和方框型滤波器cv::boxFilter()
2. 中值滤波器cv::medianBlur()
3. 高斯滤波器cv::GaussianBlur()
4. 双边滤波器cv::bilateralFilter()
cv::blur()函数实现了简单模糊,目标图像中的每个值都是源图像中相应位置一个(核)中像素的平均值。函数原型如下:
void cv::blur(
cv::InputArray src, // input image
cv::OutputArray dst, // result image
cv::Size ksize, // kernel size
cv::Point anchor = cv::Point(-1, -1), // location of anchor point
int borderType = cv::BORDER_DEFAULT // border extrapolation to use
);
窗口尺寸由ksize声明,anchor指定计算时核与源图像的对齐方式,默认anchor为cv::Point(-1,-1),表示核相对于滤波器居中。如果源图像是一幅多通道图像,分别对每个通道进行计算。
方框型滤波器是一种矩形的并且滤波器中所有值k[i][j]全部相等的滤波器。通常所有的k[i][j]为1或者1/A,A是滤波器的面积。简单模糊是方框型滤波器的一种特殊形式,也称为归一化方框型滤波器,函数为cv::bocFilter(),函数原型如下:
void cv::boxFilter(
cv::InputArray src, // input image
cv::OutputArray dst, // result image
int ddepth, // output depth
cv::Size ksize, // kernel size
cv::Point anchor = cv::Point(-1,-1), // location of anchor point
bool normalize = true, // if true divide by box area
int borderType = cv::BORDER_DEFAULT // border extrapolation to use
);
cv::boxFilter()是一种一般化的形式,cv::blur()是一种特殊化的形式。区别是前者可以非归一化形式调用,并且输出图像深度可以控制。如果ddepth=-1,目标图像的深度与源图像保持一致。
如下分别是原图、简单平滑、方框型滤波的比较:
中值滤波器将每个像素替换为围绕这个像素的矩形邻域内的中值或“中值”像素(相对于平均像素)。
平均的简单模糊对噪声图像,特别是由较大孤立的异常值非常明暗,少量具有较大偏差的点也会影响均值滤波。中值滤波可以采用取中间点的方式消除异常值。
函数原型:
void cv::medianBlur(
cv::InputArray src, // input image
cv::OutputArray dst, // result image
cv::Size kszie // kernel size
);
中值滤波器是一种非线性核的实例。cv::medianBlur的参数本质上与简单模糊的基本相同:源数组src、目标数组dst和内核大小ksize。cv::medianBlur()默认核的中心点为锚点。
如下分别是原图和中值滤波后图片的比较:
高斯滤波器对输入数组进行以此规范化的高斯核滤波,然后输出目标数组。
函数原型:
void cv::GaussianBlur(
cv::InputArray src, // input image
cv::OutputArray dst, // result image
cv::Size ksize, // kernel size
double sigmaX, // gaussian half-width in x-direction
double sigmaY = 0.0, // Gaussian half-width in y-direction
int borderType = cv::BORDER_DEFAULT // border extrapolation to use
);
参数ksize指定滤波器窗口的宽度和高度;sigmaX表示高斯核在x方向上的sigma值(最大值的半宽);sigmaY表示y方向上的sigma值,如果只给定了x,同时设置y为0,那么y=x。如果两者都设为0,那么高斯参数将根据下列公式确定:
OpenCv实现的高斯平滑为几个常用的内核提供性能上的优化,3x3、5x5以及7x7的标准sigma核(sigmaX=0.0)相对其他核性能更优。高斯模糊支持单通道/三通道的8位/32位浮点型图像。
如下分别是原图和高斯滤波后图片的比较:
双边滤波器是一种比较大的图像分析算子,也就是边缘保持平滑。
高斯模糊的过程是减缓像素在空间上的变化,因此与邻域的关系紧密,而随机噪声在像素间的变化幅度会非常的大(即噪声不是空间相关的)。基于这种前提高斯平滑很好地减弱了噪声并且保留了小信号。但是,这种方式破坏了边缘信息,最终结果是高斯模糊把边缘也模糊了。
双边滤波对每个像素及其领域内的像素进行了加权平均。其权重由两部分组成,第一部分同高斯平滑,第二部分也是高斯权重,不同的是它不是基于空间距离而是色彩强度差计算来的。
多通道图像上图像上强度差由各分量的加权累加代替。
可以把双边滤波当作是高斯平滑,只是相似程度更高的像素权值更高,边缘更明显,对比度更高。双边滤波的效果就是将源图像变成一幅水彩画。这在图像分割领域十分有用。
函数原型:
void cv::bilateralFilter(
InputArray src,
OutputArray dst,
int d,
double sigmaColor,
double sigmaSpace,
int borderType =BORDER_DEFAULT
);
参数sigmaColor越大,平滑时所包括的强度越大,图像的不连续性会更显著。
参数d对算法的效率影响很大,通常视频处理时不大于5,在非实时应用方面可以为9。如果该值设置-1,函数会自动为图像计算sigmaSpace变量的值。
实际情况中,小的sigmaSpace值比如10会带来一个轻微但也明显的效果,而大的sigmaSpace值比如150会对图像产生非常显著的影响,使图像有一种卡通的效果。
使用示例:
// OpenCv中的平滑处理
std::string strFilename = "rocket.jpg";
cv::Mat image = cv::imread(strFilename);
if (image.empty()){
printf("ERROR:image is empty!!!\n");
return;
}
cv::Mat dst;
cv::Size ksize(3, 3); // 窗口尺寸
cv::Point anchor(-1, -1); // 核与源图像的对齐方式,(-1,-1)表示核相对于滤波器居中
int border_type = cv::BORDER_DEFAULT;
cv::blur(image, dst, ksize, anchor, border_type); // 简单模糊 归一化方框型滤波器,方框型滤波器的一种
cv::Mat dst1;
int ddepth = -1;
bool normalize = true;
ksize = cv::Size(3, 3);
cv::boxFilter(image, dst1, ddepth, ksize, anchor, normalize, border_type); // 方框型滤波器
int nSize = 3;
cv::Mat dst2;
cv::medianBlur(image, dst2, nSize); // 中值滤波
cv::Mat dst3;
double sigmaX, sigmaY;
sigmaX = sigmaY = 0.0;
cv::GaussianBlur(image, dst3, ksize, sigmaX, sigmaY, border_type); // 高斯滤波
cv::Mat dst4;
int d = 9;
double sigmaColor = 80;
double sigmaSpace = 150;
cv::bilateralFilter(image, dst4, d, sigmaColor, sigmaSpace, border_type); // 双边滤波
cv::imshow("src", image);
cv::imshow("blur", dst);
cv::imshow("boxFilter", dst1);
cv::imshow("medianFilter", dst2);
cv::imshow("GaussianFilter", dst3);
cv::imshow("bilateralFilter", dst4);
cv::waitKey(0);