滤波功能在图像处理方面特别常用,我们这一篇来熟悉openCV滤波的函数,当然我们从概念看起。
官网地址:https://docs.opencv.org/master/d7/d37/tutorial_mat_mask_operations.html
上一篇:Mat数据的遍历和图像数据操作(如果不熟悉遍历方法的话,看这部分代码会不理解)
openCV滤波功能
这边官网还是在介绍filter2D函数之前,给我们介绍了通过差值权重的方式处理Mat数据的公式
增强对比度(锐化)的公式:
官网的描述是:根据掩码矩阵(就是下面那个三维矩阵) 重新计算图像中每个像素的值,掩码矩阵中的值表示相邻像素值(包括像素自身的值)对新像素值有多大影响。从数学观点看,我们用自己设置的权值,对像素邻域内的值做了个加权平均。
第一次看这块内容,没看明白,后来琢磨了一会,看了看其他资料终于明白是什么意思了,我们在这里分析一下,搞清原理后再动手编码不迟。
首先看第一个公式:从结构上看I(i,j)应该是Mat矩阵中的数据,它的值乘以5倍然后减去上下左右的邻居,这样算出来的平均值成为了新的值,这有什么用呢?
我们假设一下,如果这个点(I(i,j))是个很艳丽的点,周围四个像素不是很艳丽,那么它通过这个公式计算出来的新值一定比之前的颜色更加艳丽,反之会更加黯淡,那这个就是图片锐化的原理。
搞清楚上面的公式了,下面的公式就也通了,它是以一个矩阵为数据域与原数据做权重运算,我们可以设置掩码矩阵来实现更多其他的效果。
我们来看官方给的原始实现代码:
/**
锐化图片
@param mat mat description
@param outMat outMat description
*/
void sharpImage(const Mat& mat,Mat& outMat){
CV_Assert(mat.depth() != sizeof(uchar));
const int channels = mat.channels();
//初始化outMat,分配空间,但是不初始化它
outMat.create(mat.size(),mat.type());
for(int i = 1; i < mat.rows-1; i++){
const uchar* previous = mat.ptr<uchar>(i-1);
const uchar* current = mat.ptr<uchar>(i);
const uchar* next = mat.ptr<uchar>(i+1);
uchar* output = outMat.ptr<uchar>(i);
for(int j = channels; j < channels*(mat.cols-1); ++j){
*output++ = saturate_cast<uchar>(5*current[j] - current[j-channels]-current[j+channels] - previous[j]-next[j]);
}
}
//处理边界
outMat.row(0).setTo(Scalar(0));
outMat.row(outMat.rows-1).setTo(Scalar(0));
outMat.col(0).setTo(Scalar(0));
outMat.col(outMat.cols-1).setTo(Scalar(0));
}
如果看不太懂没关系,我准备了一张图,比较直观的反应上面代码做的事情
就是每个像素点根据上下左右的邻居通过一定的权重计算出新的数据。
上面的内容搞清楚了,我们就可以真正的来认识下openCV给我们提供的函数:filter2D
这个方法的参数描述如下:
CV_EXPORTS_W void filter2D( InputArray src, OutputArray dst, int ddepth,
InputArray kernel, Point anchor=Point(-1,-1),
double delta=0, int borderType=BORDER_DEFAULT );
InputArray src: 输入图像
OutputArray dst: 输出图像,和输入图像具有相同的尺寸和通道数量
int ddepth: 目标图像深度,如果没写将生成与原图像深度相同的图像。原图像和目标图像支持的图像深度如下:
当ddepth输入值为-1时,目标图像和原图像深度保持一致。
InputArray kernel: 卷积核(或者是相关核),一个单通道浮点型矩阵。如果想在图像不同的通道使用不同的kernel,可以先使用split()函数将图像通道事先分开。
Point anchor: 内核的基准点(anchor),其默认值为(-1,-1)说明位于kernel的中心位置。基准点即kernel中与进行处理的像素点重合的点。
double delta: 在储存目标图像前可选的添加到像素的值,默认值为0
int borderType: 像素向外逼近的方法,默认值是BORDER_DEFAULT,即对全部边界进行计算。
我写了一个小栗子:
执行效果如下:
openCV滤波功能基本熟悉好了,后面我们继续熟悉其他API。
下一篇:改变图像的对比度和亮度