欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-25 14:01:54
...

上一篇介绍了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。


掩模操作

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

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

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

    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 >在对列进行操作时,别忘了图像的通道值。


运行结果

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

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

此时我们可以用到一个函数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]));

此时运行的结果如下:

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

可以看见结果好多了


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);
}

运行结果:

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

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

相关标签: opencv