从本篇博客开始了解opencv中imgproc库。imgproc顾名思义就是image process即图像处理,像图像滤波、图像形态学(膨胀腐蚀、开运算、闭运算等)、图像缩放等一些图像处理相关知识。
图像平滑(smoothing)也称为图像模糊(blurring),是一种在图像处理中使用频率很高的操作,进行图像平滑的操作原因有很多,在这里重点介绍使用平滑操作降低图片噪声。因为在图像中,噪声的能量大都集中在幅度谱的低频和中频部分,而在较高的频段,一些重要的细节信息往往被噪声淹没。在一幅图像中,所谓的高频部分是指图像中像素值落差很大的部分,而低频则是指像素值与旁边的像素值相差不大甚至相同,而图像的一些细节的部分往往由高频信息来展现,图像中掺杂的噪声往往也处于高频段,这就造成了一些细节信息被噪声淹没,可以根据不同的噪声类型用不同的滤波器进行处理。
滤波的目的有两个即:1.抽出对象的特征作为图像识别的特征模式;2.为适应图像处理要求,消除数字图像所混入的噪声
对图像滤波有两个要求:1.不能损坏图像的轮廓和边缘等重要信息;2.使图像清晰视觉效果更好
为了进行图像平滑操作,通常在图像上加一个滤波器(filter),最常见的类型是线性的,输出像素值(g(i, j))最终由原像素值和加权值决定。其公式如下:
其中h(k, l)被称为核(kernel),是加到图像上滤波器(filter)的系数,它有助于把滤波器进行可视化为一个窗口在图像上滑动,这些设计到邻域的卷积操作。
邻域算子值利用给定像素周围像素的值决定此像素的最终输出。左边图像就是原像素的值,中间图像是滤波器(filter),filter的目的就是将滤波器的加权值进行这样的可视化窗口,最右边的图像是原图像和滤波器一起卷积生成,图像中的绿色部分是左图中青色和中间滤波器卷积计算得到的结果。所以可以看出图像像素最终的值不仅与原像素有关也可滤波器选取的kernel窗口大小有关。
方框滤波
在有了上述的理论基础之后,首先介绍一下方框滤波。
这是所有滤波器中最简单的一种滤波方式。每一个输出像素的是内核邻域像素值的平均值得到。
通用的滤波kernel如下:
这里是一个长宽分别为Kwidth和Kheight的窗口函数,在此区域内邻域中像素值叠加求平均即可求出位于kernel中心点像素的像素值。opencv中提供了方框滤波函数boxFilter()
C++: void boxFilter(InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-1,-1), bool normalize=true, int borderType=BORDER_DEFAULT )
参数解释:
. InputArray src: 输入图像,可以是Mat类型
. OutputArray dst: 经滤波后输出图像
. int ddepth: 目标图像的深度,若设置为-1,则深度与原图像深度相同
. Size ksize: Size类型,内核的大小,一般用Size(w, h)表示,如Size(3, 3)表示kernel窗口大小为3x3
. Point anchor = Point(-1,-1): 进行滤波操作的点,如果是默认值(-1, -1)说明对上述窗口中心点所对应的像素点进行操作
. bool normalize = true: 内核是否被归一化处理,有默认值true
. int borderType = BORDER_DEFAULT: 用于腿短图像外部像素的某种便捷模式,有默认值BORDER_DEFAULT.
方框滤波用的kernel如下:
其中
如果计算在kernel窗口中像素综合可以使用integral().
方框滤波示例代码如下:
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
const int g_nTrackBarMaxValue = 9; //轨迹条最大值
int g_nTrackBarValue; //轨迹条初始值
Mat g_srcImage, g_dstImage; //定义图像全局变量
int g_nKernelTrackbarValue; //定义轨迹条的值
void on_kernelTrackbar(int, void*);
int main()
{
g_srcImage = imread("lena.jpg");
//判断图像是否加载成功
if(g_srcImage.empty())
{
cout << "图像加载失败!" << endl;
return -1;
}
else
cout << "图像加载成功!" << endl << endl;
namedWindow("原图像",WINDOW_AUTOSIZE);
imshow("原图像", g_srcImage); //显示原图像
g_nTrackBarValue = 1; //初始化轨迹条初始值
namedWindow("方框滤波",WINDOW_AUTOSIZE); //轨迹条依附窗口
char kernelName[20];
sprintf(kernelName, "滤波kernel %d",g_nTrackBarMaxValue);
//创建轨迹条
createTrackbar(kernelName, "方框滤波", &g_nTrackBarValue,g_nTrackBarMaxValue,on_kernelTrackbar);
on_kernelTrackbar(g_nTrackBarValue, 0);
waitKey(0);
return 0;
}
void on_kernelTrackbar(int, void*)
{
//根据输入值重新计算kernel尺寸,见程序详解
g_nKernelTrackbarValue = g_nTrackBarValue * 2 + 3;
//方框滤波函数
boxFilter(g_srcImage, g_dstImage, -1, Size(g_nKernelTrackbarValue, g_nKernelTrackbarValue));
imshow("方框滤波", g_dstImage);
}
程序分析:
1. 关于轨迹条的创建和使用请参考《opencv(九)之Trackbar滑动条创建和使用》
2. kernel尺寸为3、5、7……这样的奇数,所以根据输入轨迹条的不同的值需要重新计算kernel的尺寸即:
g_nKernelTrackbarValue = g_nTrackBarValue * 2 + 3;
对于语句中最后参数加3是因为轨迹条默认最小值为0,所以在轨迹条在最小值时也可以形成一个3x3大小的kernel滤波器,如果语句改为:
g_nKernelTrackbarValue = g_nTrackBarValue * 2 + 1;
则当轨迹条位于最小值时,图像与原图像一致,无滤波效果