本篇内容参考 朱伟 主编 OpenCV图像处理编程实例

图像的掩码操作是指通过掩码核算子重新计算图像中各个像素的值,掩码核子刻画邻域像素点对新像素值的影响程度,同时根据掩码算子中权重因子对原像素点进行加权平均。图像掩码操作常常用于图像的平滑,边缘检测和特征分析等不同的领域。

在OpenCV中常用的计算图像掩码的操作有下面两种。

1.基于像素邻域遍历

对于原图像数据f(x,y),卷积核算子为3x3,计算原图像四邻域均值掩码可以通过下面的式子得到:

f(x,y) = (f(x-1,y)+f(x+1,y),f(x,y-1),f(x,y+1))/4

对于图像矩阵来说,上式可以用下面的式子代替:

f(x,y) = f(x,y) * Mask

其中,Mask为下面的矩阵


所以说,基于图像的邻域遍历就是通过对源数据矩阵进行操作,利用上面的公式以当前像素点为计算中心目标点,逐像素移动掩码核算子模板,对原图像数据进行遍历,进而更新新图像对应的每个像素点值。具体代码将会在下面进行实现。


2.filter2D函数

在OpenCV中提供了filter2D函数用来专门应用于计算图像卷积的操作,首先简单介绍一下这个函数:

void filter2D( InputArray src, OutputArray dst, int ddepth,InputArray kernel, 
              Point anchor=Point(-1,-1),double delta=0, int borderType=BORDER_DEFAULT );
这个函数基本上是用来实现图像的卷积操作,前两个参数分别表示输入图像和输出图像,第三个参数ddepth表示的是图像的深度,如果这个值设置为负数,则这个图像的深度与输入的源图像的深度相同,否则就需要根据源图像的深度进行相关的设置

例如,若src.depth()=CV_8U,则ddepth=-1 / CV_16S / CV_32F / CV_64F,若src.depth() = CV_16U/CV_16S,则ddepth = -1 / CV_32F / CV_64F,若src.depth() =CV_32F,则ddepth= -1 / CV_32F / CV_64F,若src.depth() = CV_64F,则ddepth = -1 / CV_64F.

第四个参数kernel是卷积核算子,为单通道浮点矩阵,如果对多通道应用不同的卷子核算子计算,需要首先分离成为单通道后在进行单通道上的操作。参数anchor是卷积核锚点,默认值是(-1,-1)表示的是卷积核中心。参数delta是平滑系数,目标图像生成前可已通过设定这个值用于目标图像的平滑操作。最后一个参数表示的是边界类型,有默认值BORDER_DEFAULT)

需要说明的是,这个函数常常应用于线性滤波技术中,当使用卷积核算子计算的图像目标点在图像外部时,需要对指定边界进行插值运算。这个函数实际上计算的是图像的相关性,而非卷积操作,它的计算公式如下:


其中0<= x' < kernel.cols,0<= y' < kernel.rows

相关的程序如下:

//图像掩码操作的两种实现

#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace std;
using namespace cv;

Mat Myfilter2D(Mat srcImage);
Mat filter2D_(Mat srcImage);

int main()
{
	Mat srcImage = imread("2345.jpg");
	if (!srcImage.data)
	{
		cout << "读入图片失败" << endl;
		return -1;
	}
	Mat srcGray;
	cvtColor(srcImage, srcGray, CV_BGR2GRAY);
	imshow("srcGray", srcGray);
	Mat resultImage = Myfilter2D(srcGray);
	imshow("resultImage1", resultImage);
	resultImage = filter2D_(srcGray);
	imshow("resultImage2", resultImage);
	waitKey();
	return 0;
}

//基于像素邻域的掩码操作
Mat Myfilter2D(Mat srcImage)
{
	const int nChannels = srcImage.channels();
	Mat resultImage(srcImage.size(), srcImage.type());
	for (int j = 1; j < srcImage.rows - 1; j++)
	{
		//获取邻域指针
		const uchar* previous = srcImage.ptr<uchar>(j - 1);
		const uchar* current = srcImage.ptr<uchar>(j);
		const uchar* next = srcImage.ptr<uchar>(j + 1);
		uchar * output = resultImage.ptr<uchar>(j);
		for (int i = nChannels; i < nChannels*(srcImage.cols - 1); ++i)
		{
			//进行4-邻域掩码操作
			*output++ = saturate_cast<uchar>(current[i - nChannels] + current[i + nChannels]
				+ previous[i] + next[i]) / 4;
		}
	}

	//进行边界处理
	resultImage.row(0).setTo(Scalar(0));
	resultImage.row(resultImage.rows - 1).setTo(Scalar(0));
	resultImage.col(0).setTo(Scalar(0));
	resultImage.col(resultImage.cols - 1).setTo(Scalar(0));
	return resultImage;
}

//使用自带掩码库进行操作
Mat filter2D_(Mat srcImage)
{
	Mat resultImage(srcImage.size(), srcImage.type());
	//构造核函数因子
	Mat kern = (Mat_<float>(3, 3) << 0, 1, 0,
								1, 0, 1,
								0, 1, 0) / (float)(4);
	filter2D(srcImage, resultImage, srcImage.depth(), kern);
	return resultImage;
}


GitHub 加速计划 / opencv31 / opencv
77.38 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:2 个月前 )
c3747a68 Added Universal Windows Package build to CI. 6 天前
9b635da5 - 6 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐