学习OpenCV(三)用filter2D实现矩阵掩码操作

本文介绍了数字图像处理中空间域滤波的基本概念和技术,包括图像强度变换与空间域图像滤波的区别,并通过OpenCV库实现了图像增强和平滑滤波。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在对数字图像进行处理时,我们一般都会在空间域(spatial domain)或者频域(frequency domain)中进行。所谓“空间域”,实际上指的是图像本身,在空间域上的操作常常是改变像素点的值,也就是经过一个映射(我们所做的变换,如滤波等),将原来的f(x,y)变换为新的g(x,y)。而“频域”,它的数学基础是法国学者傅里叶提出的傅里叶级数和随后发展起来的傅里叶变换。在这其中起到重要作用的,就是电子计算机的不断完善和快速傅里叶变换(FFT)算法的提出。这些使得傅里叶变换成为了一中有力的分析和变换工具。就像一列波,我们在时间上观察,每个时刻的幅值是一个时间的函数。而当我们变换角度,从频率域上去看,又会发现它是一系列正弦波的叠加,而这些正弦波的频率都会是某个基波频率的整数倍。可谓“横看成岭侧成峰”!

在空间域的操作主要可以分为两类:第一类是所谓的“图像强度变换”(Intensity Transform),另一类是所谓的“空间域图像滤波”(Spatial Filtering)。这两者的区别主要是处理方法的不同。前者对单个像素点进行操作,例如通过阈值函数实现图形的二值化,实现灰度平均等。而后者建立在邻域(neighborhood)的概念上,讲究的是利用一个矩阵核(Kernel)对一个小区域进行操作。今天这篇文章主要介绍的是后者,以及如何用OpenCV中的函数去实现。

我们先来看下面的这个公式,以及它的矩阵表示形式:


这个公式到它的矩阵表示形式的转换相信并不复杂,稍有线性代数知识就可以看懂。而这种操作可以用来进行图像增强。那么我们如何来使用OpenCV中的函数进行操作呢?我们要用到filter2D这个函数。可以在帮助文档中查到,filter2D函数的功能是:Convolves an image with the kernel,即如何实现图像的卷积运算。其函数原型如下:

void filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT ),可以用下面这个公式来说明:




让我们用代码来说明:

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv/cv.hpp>

using namespace std;
using namespace cv;
int main()
{
	string picName="lena.jpg";
	Mat A=imread (picName,CV_LOAD_IMAGE_COLOR);
	
	Mat mask=(Mat_<char>(3,3)<<0,-1,0,
							  -1,5,-1,
							  0,-1,0);	
	
	Mat B;
	filter2D (A,B,A.depth (),mask);
	
	imshow("A的图像",A);
	imshow("B的图像",B);
	
	waitKey ();
	return 0;
}


比较上面这两幅图片,是否感觉处理后的图像对比度更加强烈了呢?


接下来让我们用这个函数实现一个平滑滤波的功能,我们只要把矩阵核写成下面这样:

所以代码改成了:

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv/cv.hpp>

using namespace std;
using namespace cv;
int main()
{
	string picName="board.jpg";
	Mat A=imread (picName,CV_LOAD_IMAGE_COLOR);
	
	//构造矩阵核
	Mat mask=Mat::ones (3,3,CV_32FC1);
	mask/=9;
	
	Mat B;
	filter2D (A,B,A.depth (),mask);
	
	//使用了OpenCV提供的平滑滤波函数
	Mat C;
	Size s=Size(3,3);
	blur(A,C,s);
	
	imshow("A的图像",A);
	imshow("B的图像",B);
	imshow("C的图像",C);
	waitKey ();
	return 0;
}

运行结果为:

可以看出,图像的边缘变得模糊不清,左上角芯片上的字迹已经不易识别了。


### OpenCV 掩码操作中常见错误及其解决方案 在使用 OpenCV 进行掩码操作时,可能会遇到一些常见的问题。以下是针对这些问题的具体分析和解决方案。 #### 1. 定义掩码矩阵时的数据类型不匹配 当定义掩码矩阵 `kernel` 时,如果数据类型与后续操作不符,可能导致计算结果异常或报错。应确保掩码矩阵的数据类型与其他参与运算的矩阵一致。 ```cpp // 正确的方式是使用浮点型或其他适合类型的矩阵 Mat kernel = (Mat_<float>(3, 3) << 0, -1, 5, -1, 0, -1, 0); ``` #### 2. 边界处理不当引发越界访问 对于位于图像边缘的像素,在应用卷积核时容易超出边界范围,从而导致程序崩溃或未定义行为。可以采用多种方法来规避此风险: - **填充边界**:通过指定合适的边界填充模式(如复制最近邻、反射镜像等),使输入图像尺寸保持不变。 ```cpp int ddepth = CV_32F; Point anchor = Point(-1,-1); double delta = 0; int borderType = BORDER_DEFAULT; filter2D(src, dst, ddepth , kernel, anchor, delta, borderType); ``` - **手动设定边界值**:直接将靠近边界的区域设为特定数值,比如全零填充。 ```cpp result.row(0).setTo(Scalar(0)); result.row(result.rows-1).setTo(Scalar(0)); result.col(0).setTo(Scalar(0)); result.col(result.cols-1).setTo(Scalar(0)); ``` #### 3. 卷积核大小不合适影响性能及效果 过大的卷积核会增加不必要的计算负担并可能引入过多噪声;而太小则无法有效捕捉特征信息。通常情况下,奇数阶次的小尺度卷积核更为常用且高效。 #### 4. 输入输出深度参数配置失误 调用 `filter2D()` 函数时需注意设置合理的输出图像位深 (`ddepth`) 参数,以防止溢出或精度损失等问题发生。一般建议至少选用单精度浮点数表示法(`CV_32F`)作为中间结果存储格式。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值