数字图像处理线性滤波:
输出图像fo(x,y)= T[ fi(x,y) ],T是线性算子,即:输出图像上每个像素点的值都是由输入图像各像素点值加权求和的结果。
非线性滤波的算子中包含了取绝对值、置零等非线性运算。
线性滤波器的原始数据与滤波结果是一种算术运算,即用加减乘除等运算实现,如均值滤波器(模板内像素灰度值的平均值)、高斯滤波器(高斯加权平均值)等。由于线性滤波器是算术运算,有固定的模板,因此滤波器的转移函数是可以确定并且是唯一的(转移函数即模板的傅里叶变换)。
非线性滤波器的原始数据与滤波结果是一种逻辑关系,即用逻辑运算实现,如最大值滤波器、最小值滤波器、中值滤波器等,是通过比较一定邻域内的灰度值大小来实现的,没有固定的模板,因而也就没有特定的转移函数(因为没有模板作傅里叶变换),另外,膨胀和腐蚀也是通过最大值、最小值滤波器实现的。
一、中值滤波:medianBlur函数
medianBlur函数使用中值滤波器来平滑(模糊)一张图片,对于多通道图片,对每一个通道都进行单独处理,并且支持就地操作(In-placeoperation),函数原型如下:
C++: void medianBlur(InputArray src,OutputArray dst,int ksize)
参数详解:
- 第一参数,InputArray类型的src,函数的输入参数,填1,3或者4通道的Mat类型的图像。当ksize为3或5的时候,图像深度需为CV_8U、CV_16U、CV_32F其中之一,而对于较大孔径尺寸的图片,只能是CV_8U;
- 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数需要和源图片有一样的尺寸和类型,我们可以用Mat::clone,以源图片为模板来初始化得到如假包换的目标图;
- 第三个参数,int类型的ksize,孔径的现行尺寸(aperture linear size),注意这个参数必须是大于1 的奇数(3、5、7、...)
<1>中值滤波代码示例:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main() {
//载入原图
Mat image = imread("1.jpg");
//创建窗口
namedWindow("中值滤波【原图】");
namedWindow("中值滤波【效果图】");
//中值滤波操作
Mat dst;
medianBlur(image, dst, 7);//第三个参数为int类型的ksize,必须为大于1的奇数(3、5、7....)
//显示
imshow("中值滤波【原图】", image);
imshow("中值滤波【效果图】", dst);
waitKey(0);
return 0;
}
运行结果:
二、双边滤波:bilateralFilter函数
此函数的作用是用双边滤波器来模糊处理一张图片,函数圆形如下:
C++: void bilateralFilter(InputArray src,OutputArray dst,int d,double sigmaColor,double sigmaSpace,int borderType=BORDER_DEFAULT)
参数详解如下:
- 第一个参数,InputArray类型的src,输入图像,即源图像,需要为8为或者浮点型单通道、三通道的图像;
- 第二个参数,OutputArray类型的dst,即目标图像,需要和源图像有一样的尺寸和类型;
- 第三个参数,int类型的d,表示在过滤过程中每个像素邻域的直径。如果这个参数被设置为负值,那么OpenCV会从第五个参数sigmaSpace来计算出它;
- 第四个参数,double类型的sigmaColor,颜色空间滤波器的sigma值,这个参数的值越大,就表明该像素邻域内有越宽广的颜色会被混合到一起,产生较大的半相等颜色区域;
- 第五个参数,double类型的 sigmaSpace,坐标空间中的sigma值,坐标空间的标注方差。它的数值越大,意味着越远的像素会相互影响,从而使更大区域中足够相似的颜色获取相同的颜色,当d>0时,d制定了邻域大小且与sigmaSpace无关,否则,d正比于sigmaSpace;
- 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT。
<2>双边滤波代码示例:
#include <opencv2/opencv.hpp>
using namespace cv;
int main() {
Mat src = imread("1.jpg");
Mat dst;
//双边滤波操作
bilateralFilter(src, dst, 25, 25 * 2, 25 / 2);
//显示
imshow("双边滤波【原图】", src);
imshow("双边滤波【效果图】", dst);
waitKey(0);
return(0);
}
运行结果:(手指花了?其他效果还可以吧)
三、非线性滤波综合实例:
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//全局变量声明部分
Mat g_srcImage, dstImage1, dstImage2;
int g_nMedianBlurValue = 10;//中值滤波参数
int g_nBilateralFilterValue = 10;//双边滤波参数
//全局函数声明
static void on_MedianBlur(int, void *);
static void on_BilateralFilter(int, void *);
int main() {
system("color5E");
g_srcImage = imread("1.jpg");
if (!g_srcImage.data) {
cout << "读取srcImage错误!" << endl;
return false;
}
imshow("原始图", g_srcImage);
//创建窗口
namedWindow("中值滤波【效果图】");
namedWindow("双边滤波【效果图】");
//==================【中值滤波】========================
createTrackbar("内核值:", "中值滤波【效果图】", &g_nMedianBlurValue, 50, on_MedianBlur);
on_MedianBlur(g_nMedianBlurValue, 0);
//======================================================
//===================【双边滤波】=======================
createTrackbar("内核值:", "双边滤波【效果图】", &g_nBilateralFilterValue, 50, on_BilateralFilter);
on_BilateralFilter(g_nBilateralFilterValue, 0);
//======================================================
while(char(waitKey(1))!='q'){}
return 0;
}
static void on_MedianBlur(int, void *) {
medianBlur(g_srcImage, dstImage1, g_nMedianBlurValue*2+1);
imshow("中值滤波【效果图】", dstImage1);
}
static void on_BilateralFilter(int, void *) {
bilateralFilter(g_srcImage, dstImage2, g_nBilateralFilterValue, g_nBilateralFilterValue * 2, g_nBilateralFilterValue / 2);
imshow("双边滤波【效果图】", dstImage2);
}
运行结果: