OpenCV中高效的像素遍历方法,写出工程级像素遍历代码

OpenCV学堂 2021-04-25

栏目: 精品阅读 ·

来源: OpenCV学堂

简介  这篇文章主要介绍了OpenCV中高效的像素遍历方法,写出工程级像素遍历代码以及相关的经验技巧,文章约16660字,浏览量423,点赞数9,值得推荐!

三种Mat对象遍历方法比较,像素高效遍历代码

Mat对象结构

初次接触OpenCV的开发者,必须过的第一道坎就是学会如何遍历访问Mat对象中每个像素,实现像素级别的图像操作,这个是最级别的编程技能,但是不同的像素遍历方法效率有云泥之别,相差特别大,甚至可能成为算法运行的瓶颈之一,因此找到一种速度快的遍历方法对大图像处理是很关键的。在开始寻找高效遍历方法之前,先来了解一下Mat对象的数据组织形式与像素块数据的存储方式,Mat对象由两个部分组成,元数据头部加像素数据块部分,图示如下:

在OpenCV C++中Mat对象的内存管理由OpenCV框架自动负责内存分配与回收,基于智能指针实现内存管理。

三种遍历方法

方法一

基于Mat对象的随机像素访问API实现,通过行列索引方式遍历每个像素值。代码实现如下

void method_1(Mat &image) {
    double t1 = getTickCount();
    int w = image.cols;
    int h = image.rows;
    for (int row = 0; row < h; row++) {
        for (int col = 0; col < w; col++) {
            Vec3b bgr = image.at<Vec3b>(row, col);
            bgr[0] = 255 - bgr[0];
            bgr[1] = 255 - bgr[1];
            bgr[2] = 255 - bgr[2];
            image.at<Vec3b>(row, col) = bgr;
        }
    }
    double t2 = getTickCount();
    double t = ((t2 - t1) / getTickFrequency()) * 1000;
    ostringstream ss;
    ss << "Execute time : " << std::fixed << std::setprecision(2) << t << " ms ";
    putText(image, ss.str(), Point(2020), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(00255), 28);
    imshow("result", image);
}


方法二

基于Mat对象的行随机访问指针方式实现对每个像素的遍历,代码实现如下:

void method_2(Mat &image) {
    double t1 = getTickCount();
    int w = image.cols;
    int h = image.rows;
    for (int row = 0; row < h; row++) {
        Vec3b* curr = image.ptr<Vec3b>(row);
        for (int col = 0; col < w; col++) {
            Vec3b bgr = curr[col];
            bgr[0] = 255 - bgr[0];
            bgr[1] = 255 - bgr[1];
            bgr[2] = 255 - bgr[2];
        }
    }
    double t2 = getTickCount();
    double t = ((t2 - t1) / getTickFrequency()) * 1000;
    ostringstream ss;
    ss << "Execute time : " << std::fixed << std::setprecision(2) << t << " ms ";
    putText(image, ss.str(), Point(2020), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(00255), 28);
    imshow("result", image);
}


除了上述的行指针遍历方式,常见的行指针还有如下:

CV_8UC1: 灰度图像
uchar* ptr = image.ptr<uchar>(row_index);

CV_8UC3: 彩色图像
Vec3b* ptr = image.ptr<cv::Vec3b>(row_index);

CV_32FC1: 单通道浮点数图像
float* ptr = image.ptr<float>(row_index);

CV_32FC3: 三通道浮点数图像
Vec3f* ptr = image.ptr<cv::Vec3f>(row_index);

方法三

直接获取Mat对象的像素块的数据指针,基于指针操作,实现快速像素方法,代码实现如下:

void method_3(Mat &image) {
    double t1 = getTickCount();
    int w = image.cols;
    int h = image.rows;
    for (int row = 0; row < h; row++) {
        uchar* uc_pixel = image.data + row*image.step;
        for (int col = 0; col < w; col++) {
            uc_pixel[0] = 255 - uc_pixel[0];
            uc_pixel[1] = 255 - uc_pixel[1];
            uc_pixel[2] = 255 - uc_pixel[2];
            uc_pixel += 3;
        }
    }
    double t2 = getTickCount();
    double t = ((t2 - t1) / getTickFrequency()) * 1000;
    ostringstream ss;
    ss << "Execute time : " << std::fixed << std::setprecision(2) << t << " ms ";
    putText(image, ss.str(), Point(2020), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(00255), 28);
    imshow("result", image);
}

实验对比结果

系统信息与软件版本

输入图像大小为:1280x720, 彩色
操作系统:win10
OpenCV版本:OpenCV4.1
CPU:core i7 8th

OpenCV中高效的像素遍历方法,写出工程级像素遍历代码

OpenCV中高效的像素遍历方法,写出工程级像素遍历代码

实事证明,唯一正确的选择是直接使用data指针直接访问,但是这个在OpenCV官方的教程都没有明确说明,官方教程代码都是基于第一种方式,我想主要是让初学者容易理解与入门,这个也导致一些人在做开发的时候直接使用第一种方式做遍历,然后就是代码运行太慢,以后请用正确方式打开Mat对象遍历....

OpenCV中高效的像素遍历方法,写出工程级像素遍历代码
OpenCV中高效的像素遍历方法,写出工程级像素遍历代码

往期精选

告诉大家你 在看




知不足者好学

耻下问者自满


扫码加入OpenCV研习社

系统化学习OpenCV4,解锁更多技能!


以上就是本文的全部内容,希望对大家的学习有所帮助,本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

相关文章

opencv亚像素级角点检测(示例代码)

OpenCV学习C++接口 Mat像素遍历详解(示例代码)

opencv之访问图像像素(示例代码)

opencv core组件进阶(示例代码)

Qt 5.3 下OpenCV 2.4.11 开发(5)最高效的像素引用

Opencv 中图片像素操作的应用实例——计算图片某一种颜色区域大小所占比

opencv2中访问像素的简单方法

转载【OpenCV】访问Mat中每个像素的值(新)