【从零学习OpenCV 4】方框滤波
重磅干货,第一时间送达
经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。 |
方框滤波是均值滤波的一般形式,在均值滤波中,将滤波器中所有的像素值求和后的平均值作为滤波后结果,方框滤波也是求滤波器内所有像素值的之和,但是方框滤波可以选择不进行归一化,就是将所有像素值的和作为滤波结果,而不是所有像素值的平均值。
OpenCV 4中提供了boxFilter()函数实现方框滤波,该函数的函数原型在代码清单5-10中给出。
代码清单5-10 boxFilter()函数原型
void cv::boxFilter(InputArray src,
OutputArray dst,
int ddepth,
Size ksize,
Point anchor = Point(-1,-1),
bool normalize = true,
int borderType = BORDER_DEFAULT
)
src:输入图像。 dst:输出图像,与输入图像具有相同的尺寸和通道数。 ddepth:输出图像的数据类型(深度),根据输入图像的数据类型不同拥有不同的取值范围,具体的取值范围在表5-1给出,当赋值为-1时,输出图像的数据类型自动选择。 ksize:卷积核尺寸。 anchor:内核的基准点(锚点),其默认值为(-1,-1)代表内核基准点位于kernel的中心位置。基准点即卷积核中与进行处理的像素点重合的点,其位置必须在卷积核的内部。 normalize:是否将卷积核进行归一化的标志,默认参数为true,表示进行归一化。 borderType:像素外推法选择标志,取值范围在表3-5中给出,默认参数为BORDER_DEFAULT,表示不包含边界值倒序填充。
该函数的使用方式与均值滤波函数blur()几乎一样,但是该函数可以选择输出图像的数据类型,除此之外,该函数的第六个参数表示是否对滤波器内所有的数值进行归一化操作,参数默认状态下需要对滤波器内所有的数值进行归一化。此时,在不考虑数据类型的情况下,框滤波函数boxFilter()和均值滤波函数blur()会具有相同的滤波结果。
除了对滤波器内每个像素值直接求和外,OpenCV 4还提供了sqrBoxFilter()函数实现对滤波器内每个像数值的平方求和,之后根据输入参数选择是否进行归一化操作,该函数的函数原型在代码清单5-11中给出。
代码清单5-11 sqrBoxFilter()函数原型
void cv::sqrBoxFilter(InputArray src,
OutputArray dst,
int ddepth,
Size ksize,
Point anchor = Point(-1, -1),
bool normalize = true,
int borderType = BORDER_DEFAULT
)
该函数是在boxFilter()函数功能基础上进行扩展功能,因此两者具有相同的输入参数需求,这里对函数的参数不再进行逐一解释。CV_8U数据类型的图像像素值从0到255,计算平方后数据会变得更大,即使归一化操作也不能保证像素值不会超过最大值,但是CV_32F数据类型的图像像素值是从0到1之间的小数,在0到1之间的数计算平方会变得更小,但是始终保持在0到1之间。因此该函数在处理图像滤波的任务时主要针对的是CV_32数据类型的图像,而且根据计算关系可知,在归一化后图像在变模糊的同时亮度也会变暗。
为了更加了解方框滤波的计算原理,清楚归一化操作和未归一化操作对滤波结果的影响,在代码清单5-12中给出了分别利用方框滤波处理矩阵数据和图像的示例程序。程序中我们创建了一个Mat类型的数据,之后用sqrBoxFilter()函数进行方框滤波,并在图5-13给出归一化后和未归一化后的结果,同时使用boxFilter()函数和sqrBoxFilter()对图像进行方框滤波操作,处理结果如图5-12中所示。
代码清单5-12 myBoxFilter.cpp图像方框滤波
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat equalLena = imread("equalLena.png", IMREAD_ANYDEPTH); //用于方框滤波的图像
if (equalLena.empty())
{
cout << "请确认图像文件名称是否正确" << endl;
return -1;
}
//验证方框滤波算法的数据矩阵
float points[25] = { 1,2,3,4,5,
6,7,8,9,10,
11,12,13,14,15,
16,17,18,19,20,
21,22,23,24,25 };
Mat data(5, 5, CV_32FC1, points);
//将CV_8U类型转换成CV_32F类型
Mat equalLena_32F;
equalLena.convertTo(equalLena_32F, CV_32F, 1.0 / 255);
Mat resultNorm, result, dataSqrNorm, dataSqr, equalLena_32FSqr;
//方框滤波boxFilter()和sqrBoxFilter()
boxFilter(equalLena, resultNorm, -1, Size(3,3), Point(-1, -1), true); //进行归一化
boxFilter(equalLena, result, -1, Size(3, 3), Point(-1, -1), false); //不进行归一化
sqrBoxFilter(data, dataSqrNorm, -1, Size(3, 3), Point(-1, -1),
true, BORDER_CONSTANT); //进行归一化
sqrBoxFilter(data, dataSqr, -1, Size(3, 3), Point(-1, -1),
false, BORDER_CONSTANT); //不进行归一化
sqrBoxFilter(equalLena_32F, equalLena_32FSqr, -1, Size(3, 3), Point(-1, -1),
true, BORDER_CONSTANT);
//显示处理结果
imshow("resultNorm", resultNorm);
imshow("result", result);
imshow("equalLena_32FSqr", equalLena_32FSqr);
waitKey(0);
return 0;
}
图5-13 myBoxFilter.cpp程序中矩阵数据方框滤波结果
图5-14 myBoxFilter.cpp程序中图像方框滤波结果