OpenCV-图像的遍历

计算机使用 0/1 编码存储图像,数字图像在计算机中同样也使用 0/1 编码来存储。在计算机看来图像是一堆亮度不同的点组成的矩阵。一般灰度图用 2 维矩阵来表示,彩色图片是多通道的,则用 3 维矩阵来表示。

灰度图像

我们一般接触的图像都是 8 位整数(CV_8U),所以灰度图像包含 0~255 灰度,其中 0 代表最⿊,1表⽰最⽩。

彩色图像

彩色图像比如 RGB 图像,每个像素用三个字节来表示,而 OpenCV 中存储 RGB 图像以 BGR 的顺序存储图像,所以存储方式如上所示。

本文将介绍遍历灰度图像和彩色图像的方法,其本质即为遍历图像矩阵,可以对比二维数组的遍历来学习。

使用 at() 遍历图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main()
{
    // 使用构造器创建 Mat,注意类型
    cv::Mat grayImage(400, 500, CV_8UC1);
    cv::Mat colorImage(400, 500, CV_8UC3);

    for(int i = 0; i < grayImage.rows; i++)
    {
        for(int j = 0; j < grayImage.cols; j++)
        {
            // 灰度图像是单通道的
            grayImage.at<uchar>(i, j) = (i + j) % 255;
        }
    }

    for(int i = 0; i < colorImage.rows; i++)
    {
        for(int j = 0; j < colorImage.cols; j++)
        {
            // 三通道用向量来表示
            cv::Vec3b pixel;
            pixel[0] = i % 255;
            pixel[1] = j % 255;
            pixel[2] = 0;
            colorImage.at<cv::Vec3b>(i, j) = pixel;
        }
    }

    cv::imshow("1. GrayImage", grayImage);
    cv::imshow("2. ColorImage", colorImage);

    cv::waitKey(0);

    return 0;
}

效果图

at() 的优点在于可读性强,缺点在于效率不高。图像遍历操作时常用且开销很大的操作,所以不推荐使用 at() 做图像的遍历操作。

使用指针遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main()
{
    cv::Mat grayImage(400, 500, CV_8UC1);
    cv::Mat colorImage(400, 500, CV_8UC3);

    for(int i = 0; i < grayImage.rows; i++)
    {
        uchar *p = grayImage.ptr<uchar>(i);
        
        for(int j =0; j < grayImage.cols; j++)
        {
            p[j] = (i + j) % 255;
        }
    }

    for(int i = 0; i < colorImage.rows; i++)
    {
        
        cv::Vec3b *p = colorImage.ptr<cv::Vec3b>(i);
    
        for(int j =0; j < colorImage.cols; j++)
        {
            p[j][0] = i % 255;
            p[j][1] = j % 255;
            p[j][2] = 0;
        }
    }

    cv::imshow("1. GrayImage", grayImage);
    cv::imshow("2. ColorImage", colorImage);

    cv::waitKey(0);

    return 0;
}

效果图

程序是用 image.ptr() 返回矩阵每一行的头指针,紧接着遍历这一行的元素。

指针的优点在于访问速度快,缺点在于指针较为复杂,不熟悉指针的朋友容易犯错且不易查找错误。

迭代器遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main()
{
    cv::Mat grayImage(400, 500, CV_8UC1);
    cv::Mat colorImage(400, 500, CV_8UC3);

    cv::MatIterator_<uchar> grayit, grayend;

    for (grayit = grayImage.begin<uchar>(), grayend = grayImage.end<uchar>();
         grayit != grayend; grayit++)
    {
        *grayit = rand() % 255;
    }

    cv::MatIterator_<cv::Vec3b> colorit, colorend;
    for (colorit = colorImage.begin<cv::Vec3b>(), colorend = colorImage.end<cv::Vec3b>();
         colorit != colorend; colorit++)
    {
        (*colorit)[0] = rand() % 255;
        (*colorit)[1] = rand() % 255;
        (*colorit)[2] = rand() % 255;
    }

    cv::imshow("1. GrayImage", grayImage);
    cv::imshow("2. ColorImage", colorImage);

    cv::waitKey(0);

    return 0;
}

迭代器遍历

在 C++ 的 STL 库,或者 Java, Python 等语言中都提供了对迭代器的支持,OpenCV 也支持使用迭代器的方式进行遍历,代码如上所示。


本文介绍了遍历 Mat 的三种方式: 使用 at() 遍历,使用指针遍历,以及使用迭代器遍历。推荐使用指针的方式遍历图像,其效率最高,在编写图像处理的算法时,效率是我们不可忽视的要素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值