OpenCV学习(三):矩阵的掩模的操作

来源:互联网 发布:双十一淘宝的书降价吗 编辑:程序博客网 时间:2024/04/30 15:17

上一篇介绍了OpenCV中imread,cvtColor,imshow,imwrite的使用,这一篇打算介绍Mat的像素指针,以及掩模操作。

像素指针

对图像操作,基本都是对图像的每个像素操作,在OpenCV中Mat.ptr<uchar>(int i=0)可以获取像素的指针,i表示第i行,从第0列开始操作。

这样获取当前行的像素指针const uchar* current = myImage.ptr<uchar>( row ),那么获取像素点P(row, col)的像素值p(row, col) = current[col]

eg:

Mat inMat = imread("1.png");uchar u = inMat.ptr<uchar>(0)[0];

上面先载入一张图片到inMat中,然后从inMat中获取第1行第1列的像素并赋给uchar类型的u。


掩模操作

知道了获取图像的像素方法,接下来就可以对图像进行掩模操作,从而提高图片的对比度。

这里写图片描述

接下来就根据上面图片的公式,来实现图片像素的操作。

    Mat inMat = imread("1.png");    if (!inMat.data) {  //判断图像是否读取成功        cout << "图像读取失败" << endl;        return;    }    imshow("原图像", inMat);    int channel = inMat.channels(); //获取图像的通道数    int row = inMat.rows;    int col = inMat.cols;    Mat outMat = Mat(inMat.size(), inMat.type());    for (int i = 1; i < row-1; i++) {        for (int j = channel; j < (col-1)*channel; j++) {            outMat.ptr<uchar>(i)[j] = 5 * inMat.ptr<uchar>(i)[j]-                                                                (inMat.ptr<uchar>(i - 1)[j] +                                                                  inMat.ptr<uchar>(i + 1)[j] +                                                                 inMat.ptr<uchar>(i)[j-channel] +                                                                  inMat.ptr<uchar>(i)[j+channel]);        }    }    imshow("掩模之后的图像", outMat);}

注意:
< 1 >我们在显示图片的时候,可以不用调用namedwindow来创建窗口,可以直接调用imshow,来创建并显示窗口图像。
< 2 >像素计算操作时,不能直接从原点(0, 0)到最大点(col, row)来计算计算像素值,否则计算就会超过范围 。
< 3 >在对列进行操作时,别忘了图像的通道值。


运行结果

这里写图片描述

可以看见掩模之后的图片失真很严重,这是因为我们像素计算之后的值可能为负数或者超过了范围。

此时我们可以用到一个函数saturate_cast< uchar >,当计算的值为负数,或者很大时,可以使我们计算的像素值保证在0~255之间。

更改之后的代码如下

outMat.ptr<uchar>(i)[j] = saturate_cast<uchar>(5 * inMat.ptr<uchar>(i)[j]-                                                                (inMat.ptr<uchar>(i - 1)[j] +                                                                  inMat.ptr<uchar>(i + 1)[j] +                                                                 inMat.ptr<uchar>(i)[j-channel] +                                                                  inMat.ptr<uchar>(i)[j+channel]));

此时运行的结果如下:

这里写图片描述

可以看见结果好多了


filter2D

对于上面的代码显然是最原始的像素计算方式,此时我们可以使用filter2D达到最简洁的像素计算方式。

< 1 >定义掩模

Mat kernel = (Mat_< char >(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);

< 2 >调用filter2D

filter2D(inMat, outMat, inMat.depth(), kernel);

(1)参数一:输入的图像
(2)参数二:输出的图像
(3)参数三:输出的图像深度,一般和输入图像的深度一样,也可以直接填-1,和前面一样


此时附上完整代码

void test4(){    Mat inMat = imread("1.png");    if (!inMat.data) {  //判断图像是否读取成功        cout << "图像读取失败" << endl;        return;    }    imshow("原图像", inMat);    int channel = inMat.channels(); //获取图像的通道数    int row = inMat.rows;    int col = inMat.cols;    Mat outMat = Mat(inMat.size(), inMat.type());    for (int i = 1; i < row-1; i++) {        for (int j = channel; j < (col-1)*channel; j++) {            outMat.ptr<uchar>(i)[j] = saturate_cast<uchar>(5 * inMat.ptr<uchar>(i)[j]-                                                                (inMat.ptr<uchar>(i - 1)[j] +                                                                  inMat.ptr<uchar>(i + 1)[j] +                                                                 inMat.ptr<uchar>(i)[j-channel] +                                                                  inMat.ptr<uchar>(i)[j+channel]));        }    }    imshow("掩模之后的图像", outMat);    Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);    filter2D(inMat, outMat, inMat.depth(), kernel);    imshow("filter2D变化之后的图像", outMat);}

运行结果:

这里写图片描述

可以看见,filter2D和前面的计算结果显示的样子基本一样。