第6章 图像处理
6.1 线性滤波:方框滤波、均值滤波、高斯滤波
6.1.1 图像滤波与滤波器
1.图像滤波:在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制
目的:
(1)抽出对象的特征作为图像识别的特征模式
(2)适应图像处理的要求,消除图像数字化时所混入的噪声
要求:
(1)不损坏图像的轮廓及边缘等重要信息
(2)使图像清晰视觉效果好
2.平滑滤波:消除图像中的噪声成分,低频增强的空间域滤波技术
目的:
(1)模糊
(2)消除噪音
3.滤波器种类
(1)方框滤波(boxFilter函数)
(2)均值滤波/领域平均滤波(blur函数)
(3)高斯滤波(GaussianBlur函数)
(4)中值滤波(medianBlur函数)
(5)双边滤波(bilateralFilter函数)
4.线性滤波器
(1)低通滤波器:允许低频率
(2)高通滤波器:允许高频率
(3)带通滤波器:允许一定范围频率
(4)带阻滤波器:阻止一定范围频率
(5)全通滤波:允许所有频率通过,仅改变相位关系
(6)陷波滤波器:组织一个狭窄频率范围通过
6.1.2 邻域算子与线性邻域滤波
1.邻域算子(局部算子):利用给定像素周围的像素值决定此像素的输出值的一种算子
用处:
(1)局部色调调整
(2)图像滤波
2.线性邻域滤波:一种常用的邻域算子,像素输出值g(i,j)取决于输入像素f(i+k,j+I)的加权和:
其中h(k,I)为滤波器加权系数
3.三种线性滤波操作
(1)方框滤波(BoxBlur函数)
(2)均值滤波/领域平均滤波(Blur函数)
(3)高斯滤波(GaussianBlur函数)
6.1.3 方框滤波(boxFilter)
1.封装函数:boxFilter函数
2.函数原型:
void boxFilter(InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-1,-1), boolnormalize=true, int borderType=BORDER_DEFAULT )
3.参数说明:
(1)输入图像,深度应为CV_8U、CV_16U、CV_16S、CV_32F、CV_64F之一
(2)目标图像,与输入图像尺寸类型一致
(3)输出图像深度,-1代表使用原图深度,即src.depth()
(4)内核大小,Size(w,h)表示w*h的核大小
(5)锚点,被平滑的那个点,默认值Point(-1,-1),点坐标为负值表示取内核中心为锚点
(6)标识符,默认值true,表示内核是否被其区域归一化了,归一化是把要处理的量缩放到一个范围内
(7)用于推断图像外部像素的某种边界模式,默认BORDER_DEFAULT
4.核表示:
其中:
6.1.4 均值滤波(blur)
1.滤波原理:输出图像的每一个像素值是核窗口内全体像素(除去目标像素本身)的平均值(所有像素加权系数相等),是归一化后的方框滤波
2.封装函数:blur函数
3.函数原型:
void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFALUT)
4.缺点:图像去噪的同时也破坏了图像细节部分
6.1.5 高斯滤波(GaussianBlur)
1.滤波原理:输出图像的每个像素值都是其本身和邻域内的其他像素值的加权平均值,具体为用一个模板(卷积/掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值替代模板中心像素点的值
(1)从数学角度,图像的高斯模糊过程就是源图像与指定的高斯分布函数做卷积运算,图像与圆形方框模糊做卷积会生成更加精确的焦外成像效果
(2)高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器,高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。
(3)一维零均值高斯函数:
其中,高斯分布参数Sigma决定了高斯函数的宽度
(4)二维零均值离散高斯函数:
2.封装函数:GaussianBlur函数
3.函数原型:
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFALUT)
4.参数说明:
(1)输入图像,深度应为CV_8U、CV_16U、CV_16S、CV_32F、CV_64F之一
(2)目标图像,与输入图像尺寸类型一致
(3)内核大小,Size(w,h)表示w*h的核大小,ksize.width和ksize.height都必须是正数和奇数或0,都由sigma计算而来
(4)高斯核函数在X方向的标准偏差
(5)高斯核函数在Y方向的标准偏差,若sigmaY为0,就将它设置为sigmaX,如果sigmaX和sigmaY都是0,就由ksize.width和ksize.height计算出来
(6)用于推断图像外部像素的某种边界模式,默认BORDER_DEFAULT
6.1.6 线性滤波OpenCV源码
(…\OpenCV3.4.1\opencv\sources\modules\imgproc\src\smooth.cpp)
FilterEngine类:OpenCV图像滤波核心引擎,使用FilterEngine类可以分块处理大量的图像,构建复杂的管线
1.boxFilter函数
(1)复制源图形参Mat数据到临时变量,定义一些临时变量
(2)处理ddepth小于0的情况
(3)处理borderType不为BORDER_CONSTANT且normalize为真的情况
(4)调用FilterEngine滤波引擎创建一个BoxFilter,正式开始滤波操作
2.blur函数
(1)调用boxFilter函数:boxFilter(src,dst,-1,ksize,anchor,true,borderType);
3.GaussianFilter函数
6.1.7 线性滤波示例
1.三种滤波调用
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
//载入原图
Mat srcImage = imread("love.jpg");
//显示原图
namedWindow("线性滤波【原图】");
imshow("线性滤波【原图】", srcImage);
//[1]方框滤波
Mat dstImage1;
boxFilter(srcImage, dstImage1, -1, Size(3, 3), Point(-1, -1), true);
namedWindow("方框滤波【效果图】");
imshow("方框滤波【效果图】", dstImage1);
//[2]均值滤波
Mat dstImage2;
blur(srcImage, dstImage2, Size(5, 5), Point(-1, -1));
namedWindow("均值滤波【效果图】");
imshow("均值滤波【效果图】", dstImage2);
//[3]高斯滤波
Mat dstImage3;
GaussianBlur(srcImage, dstImage3, Size(7, 7), 0, 0);
namedWindow("高斯滤波【效果图】");
imshow("高斯滤波【效果图】", dstImage3);
waitKey(0);
return 0;
}
2.滑动条控制滤波模糊度
#include<opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;
//全局变量声明
Mat g_srcImage, g_dstImage1, g_dstImage2, g_dstImage3;
int g_nBoxFilterValue;
int g_nMeanBlurValue;
int g_nGaussianBlurValue;
//全局函数声明
static void on_BoxFilter(int, void*);
static void on_MeanBlur(int, void*);
static void on_GaussianBlur(int, void*);
int main()
{
//改变console字体颜色
//system("color5E");
//载入原图
g_srcImage = imread("love.jpg");
if (!g_srcImage.data)
{
printf("读取srcImage错误~!\n");
return false;
}
//复制原图到三个Mat类型中
g_dstImage1 = g_srcImage.clone();
g_dstImage2 = g_srcImage.clone();
g_dstImage3 = g_srcImage.clone();
//初始化内核值
g_nBoxFilterValue = 3;
g_nMeanBlurValue = 3;
g_nGaussianBlurValue = 3;
//显示原图
namedWindow("【原图窗口】");
imshow("【原图窗口】", g_srcImage);
//=========================【<1>方框滤波】========================
//创建窗口
namedWindow("【<1>方框滤波】");
//创建轨迹条
createTrackbar("内核值:", "【<1>方框滤波】", &g_nBoxFilterValue, 40, on_BoxFilter);
on_BoxFilter(g_nBoxFilterValue, 0);
//================================================================
//=========================【<2>均值滤波】========================
//创建窗口
namedWindow("【<2>均值滤波】");
//创建轨迹条
createTrackbar("内核值:", "【<2>均值滤波】", &g_nMeanBlurValue, 40, on_MeanBlur);
on_MeanBlur(g_nMeanBlurValue, 0);
//================================================================
//=========================【<3>高斯滤波】========================
//创建窗口
namedWindow("【<3>高斯滤波】");
//创建滑动条
createTrackbar("内核值:", "【<3>高斯滤波】", &g_nGaussianBlurValue, 40, on_GaussianBlur);
on_GaussianBlur(g_nGaussianBlurValue, 0);
//================================================================
//输出一些帮助信息
cout << endl << "\t请调整滑动条观察图像效果~\n\n" << "\t按下\"q\"键时,程序退出~!\n";
//按下"q"键时,程序退出
while (char(waitKey(1)) != 'q') {}
return 0;
}
static void on_BoxFilter(int, void*)
{
boxFilter(g_srcImage, g_dstImage1, -1, Size(g_nBoxFilterValue+1, g_nBoxFilterValue+1), Point(-1, -1), true);
imshow("【<1>方框滤波】", g_dstImage1);
}
static void on_MeanBlur(int, void*)
{
blur(g_srcImage, g_dstImage2, Size(g_nMeanBlurValue+1, g_nMeanBlurValue+1), Point(-1, -1));
imshow("【<2>均值滤波】", g_dstImage2);
}
static void on_GaussianBlur(int, void*)
{
GaussianBlur(g_srcImage, g_dstImage3, Size(g_nGaussianBlurValue*2 + 1, g_nGaussianBlurValue*2 + 1), 0, 0);
imshow("【<3>高斯滤波】", g_dstImage3);
}