【OpenCV图像处理】八、图像的掩码操作
本篇内容参考 朱伟 主编 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)