• 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() 遍历,使用指针遍历,以及使用迭代器遍历。推荐使用指针的方式遍历图像,其效率最高,在编写图像处理的算法时,效率是我们不可忽视的要素。

  • 相关阅读:
    Springboot使用ehcache缓存
    Tomcat启用HTTPS协议配置过程
    细说document.ready和window.onload
    科技创新
    SpringBoot的ApplicationRunner
    禁用Chrome的“请停用以开发者模式运行的扩展程序”提示
    论文排版问题
    mathType换行等号对齐
    内部类调用外部类的成员,同名时怎么调用?
    Tomcat的manager app管理web项目
  • 原文地址:https://www.cnblogs.com/shuiyj/p/13185145.html
Copyright © 2020-2023  润新知