opencv学习(六)之掩膜版

可以通过掩模矩阵(通常来讲叫核)对图像的每个图像像素值重新计算。这个掩模板能够调整临近像素包括当前像素对新像素的影响程度。从数学的角度来讲,我们用特殊的值对当前的值做了一个加权平均的操作。举个例子,设想一个图像对比度增强的方法,基本上,我们要将下面的公式应用到每一个像素上:
opencv学习(六)之掩膜版_第1张图片
第一个公式是用数学公式,第二个是用一个掩模板。将掩模板中心放到你想计算像素上,将像素值累加并乘以与重叠矩阵值想成。对于较大的矩阵来看,后一种表达方式更容易理解。

#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;

void Sharpen(const Mat& myImage, Mat& Result);

int main()
{
    Mat srcImage = imread("lena.jpg");

    //判断图像是否加载成功
    if(srcImage.data)
        cout << "图像加载成功!" << endl << endl;
    else
    {
        cout << "图像加载失败!" << endl << endl;
        return -1;
    }
    namedWindow("srcImage", WINDOW_AUTOSIZE);
    imshow("srcImage", srcImage);

    Mat dstImage;
    dstImage.create(srcImage.size(), srcImage.type());
    Sharpen(srcImage, dstImage);
    namedWindow("dstImage",WINDOW_AUTOSIZE);
    imshow("dstImage",dstImage);

    waitKey(0);

    return 0;
}

void Sharpen(const Mat& myImage, Mat& Result)
{
    CV_Assert(myImage.depth() == CV_8U);        //判断函数CV_Assert
    const int nChannels = myImage.channels();

    for(int j = 1; j < myImage.rows - 1; ++j)
    {
        const uchar* precious = myImage.ptr(j - 1);      //当前像素上一行指针
        const uchar* current = myImage.ptr(j);           //当前像素行指针
        const uchar* next = myImage.ptr(j + 1);          //当前像素下一行指针

        uchar* output = Result.ptr(j);

        //利用公式和上下左右四个像素对当前像素值进行处理
        for(int i = nChannels; i < nChannels * (myImage.cols - 1); ++i)
        {
            *output++ = saturate_cast(5 * current[i]
            -current[i-nChannels]-current[i+nChannels]-precious[i]-next[i]);
        }
    }
    Result.row(0).setTo(Scalar(0));                 //设置第一行所有元素值为0
    Result.row(Result.rows-1).setTo(Scalar(0));     //设置最后一行所有元素值为0
    Result.col(0).setTo(Scalar(0));                 //设置第一列所有元素值为0
    Result.col(Result.cols-1).setTo(Scalar(0));     //设置最后一列所有元素值为0
}

运行结果如图所示:
opencv学习(六)之掩膜版_第2张图片
对上述程序简单做个分析。
(1). main()函数中加载图像后一定要判断图像是否加载成功,这是良好的编程习惯。判断图像是否加载成功有两种方式如下:

//图像为空即加载失败
if(srcImage.empty())
{
    //...处理方法...
}
else        //图像加载成功
{
    //...图像加载成功...
}

//图像是否有数据
if(srtImage.data)
{
    //...处理方法...
}
else        //即图像加载失败
{
    //...处理方法...
}

注意:在使用empty()函数时其带后面的”()”而使用data判断时不带”()”,这是两者的区别。
(2). 加载图像成功后使用CV_Assert()函数判断图像是否unsigned char 类型。
(3). 通过create()函数创建一个和原图像尺寸和类型相同的目标图像。对于create()等函数的用法可以参考opencv学习(一)之Mat类,里面有具体叙述,在此不过多介绍!
(4). 此程序是利用上述第一个数学公式对图像像素进行重新计算和处理,通过其上下左右四个邻域像素和其本身像素值通过计算得到新的像素值。在本程序中利用C语言[]操作符来读取像素。因为我们需要同事读取多行,所以提前获取当前行,上一行和下一行的指针(previous、current、next).行指定完后还需要定义一个指针存储计算结果(output).
(5). 对于列的处理先获取当前图像的通道数,然后对每个像素的每个通道上的数值进行计算: current[i - nChannels]和current[i + nChannels]两个为当前像素左右两个像素相同通道的值,而previous[i]和next[i]为上下两个像素值相同通道的像素值.
(6). 利用本方法计算时,对于图像的上下左右四条边最外面的像素点无法计算,故在最后利用四行代码对其进行认为赋值为0,这样得到的计算结果与原图像相比,四周会出现黑线!!!

你可能感兴趣的:(OpenCV基础,opencv2/3基础教程)