八、模糊图像(滤波)
1、模糊原理
- Smooth/Blur是图像处理中最简单和常用的操作之一
- 使用该操作的原因之一就是为了给图像预处理时候降低噪声
- 使用Smooth/Blur操作其背后是数学的卷积计算
- 通常这些卷积算子计算都是线性操作,所以又叫线性滤波
卷积过程示意如下:
(灰色代表图片,黄色部分代表卷积算子,红色中心部分代表正在处理的像素)
2、有关模糊(滤波)的API(Application Programming Interface 预先定义函数)
- 均值模糊(各像素权重一样):用像素即周围像素的平均值代替该像素值,通过blur()函数实现,由于每一个像素都由周围的像素取平均值获得,所以会使原本层次分明的部分变得平均化,减少像素值间差异,即变得模糊。
blur(src, dst, Size(11, 11), Point(-1, -1));//均值模糊,参数分为为待处理图像,处理后图像,卷积模板x方向和y方向窗口的大小(只能为正的奇数,值越大,对应方向模糊程度越明显),模板中间像素位置一般固定为Point(-1,-1)
- 高斯模糊(各像素权重不一样,按高斯分布):周围像素通过按权(通过高斯分布获得)相加代替该像素值,通过GaussianBlur()函数实现。
GaussianBlur(src, gblur, Size(11, 11), 11, 11);//高斯模糊,参数分别为待处理图像,处理后图像,卷积模板x方向和y方向窗口的大小(只能为正的奇数,值越大,对应方向模糊程度越明显),高斯公式的两个方向的sigma值(用来调节正态分布)
对比:高斯滤波会保留像素原有的特征值,若原像素值很大,根据高斯分布按权相加,越靠近中心权重越大,待处理像素位置有最大的权值,经过高斯滤波仍会是一个较大的像素值。而在均值滤波中,一个较大像素值周围都是小的像素值,平均后会变小,所以均值模糊获得的图像会更模糊一些。
示例代码(均值模糊与高斯模糊):
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("添加图片路径");
if (src.empty()) {
cout << "could not load image..." << endl;
return -1;
}
blur(src, dst, Size(11, 11), Point(-1, -1));
imshow("blur image demo", dst);
Mat gblur;
GaussianBlur(src, gblur, Size(11, 11), 11, 11);
imshow("GaussianBlur image demo", gblur);
waitKey(0);
destroyAllWindows();
return 0;
}
输出结果显示:
3、中值滤波
- 统计排序滤波器
- 中值对椒盐噪声有很好的抑制作用(椒盐噪声即图片中偶尔会出现的极大极小值)
对模板下所对应的像素值进行从小到大排序,取中间位置的像素值做为模板中央像素的像素值。若取最小位置的像素值则为最小值滤波,若取最大位置像素值则为最大值滤波。
medianBlur(Mat src, Mat dest, ksize);//src为待处理图像,dest为处理后图像, ksize为卷积模板的大小,其值必须大于1且为奇数
中值滤波效果图:(左为原图,右为中值滤波处理后图片)
4、双边滤波
- 均值模糊无法克服边缘像素信息丢失缺陷。原因是均值滤波是基于平均权重。
- 高斯模糊部分克服了该缺陷,但是无法完全避免,因为没有考虑像素值的不同。
例如边界处像素值差别会比较大,对其进行高斯滤波时,边界处像素值受周围像素值的影响较大。(虽然周围像素值所占权重较小,但也会受影响) - 高斯双边模糊,是边缘保留的滤波方法,避免了边缘信息丢失,保留了图像轮廓不变。(设定一个阈值,若周围像素值与其模板中心像素值的差值大于某一个阈值,不参与计算)利用双边滤波,可以消除微小差异,保留图像轮廓,类似磨皮的效果。
bilateralFilter(src, dest, d = 15, 150, 3);//src为待处理图像,dest为处理后图像,d为计算的半径(半径之内的像素都会被纳入计算),150为设定的阈值(像素差值在阈值内才可以参与运算),3为高斯分布的sigma值(若d的值大于0则声明无效,否则根据它计算d值)
双边滤波效果图:(左为原图,右为双边滤波处理后图片)
双边滤波与高斯滤波对比图:(左为原图,中为双边滤波处理后图片,右为高斯滤波处理后图片)
示例代码(双边高斯滤波加对比度提升):
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("添加图片地址");
if (!src.data) {
cout << "could not load image..." << endl;
return -1;
}
imshow("input", src);
bilateralFilter(src, dst, 5, 150, 3);//双边滤波
imshow("bilateralFilter image demo", dst);
Mat m1;//在双边滤波的基础上提高对比度
Mat kernel = (Mat_<int>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(dst, m1, dst.depth(), kernel, Point(-1, -1), 0);
imshow("final result", m1);
waitKey(0);
destroyAllWindows();
return 0;
}
输出结果如下所示:(左为原图,中为双边滤波处理后图片,右为提高对比度后的图片)