【OpenCV图像处理】八、图像的掩码操作

来源:互联网 发布:如何学java软件开发 编辑:程序博客网 时间:2024/04/29 00:21

本篇内容参考 朱伟 主编 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;}


0 0
原创粉丝点击