Opencv:通过Mat遍历图像的5种方法

Opencv:通过Mat遍历图像的5种方法

1. 图片在内存的存储形式
  • 灰度图(单通道):

在这里插入图片描述

  • RGB图(3通道):

在这里插入图片描述

2. Mat遍历的几种方法

分别是直接地址遍历访问连续空间(图片存储空间是连续的)、直接地址访问不连续空间、ptr<>()模板函数、at接口、以及迭代器,完整C++代码如下:

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void PrintMs(const char * text = "") {
    //定时器
    static long long last = 0;
    long long cur = getTickCount();
    if (last == 0) {
        last = cur;
        return;
    }
    long long ms = 0;
    ms = ((double)(cur - last) / getTickFrequency()) * 1000;
    if (* text != 0) {
        cout <<text<<":" << ms <<"ms"<<endl;
    }
    last = getTickCount();
}

void main() {
    Mat mat; 
    mat.create(3000, 4000, CV_8UC3); //创建Mat对象,3000*4000的RGB图像

    //直接地址遍历访问连续空间
    int es = mat.elemSize();
    int size = mat.rows * mat.cols * es; 

    PrintMs();
    for (int i = 0; i < size; i+=es)
    {
        mat.data[i] = 255;		//B
        mat.data[i+1] = 0;		//G
        mat.data[i+2] = 0;		//R
    }
    PrintMs("mat.data ms");

    //直接地址访问不连续空间
    for (int i = 0; i < mat.rows; i++)
    {
        for (int j = 0; j < mat.cols; j++)
        {
            (&mat.data[i * mat.step])[j * es] = 0; // B
            (&mat.data[i * mat.step])[j * es +1] = 0; // G
            (&mat.data[i * mat.step])[j * es +2] = 255; // R
        }
    }
    PrintMs("mat.step ms");

    //使用ptr模板函数遍历
    for (int row = 0; row < mat.rows; row++)
    {
        for (int col = 0; col < mat.cols; col++)
        {
            Vec3b* m = mat.ptr<Vec3b>(row, col);
            m->val[0] = 0;	//B
            m->val[1] = 255;	//G
            m->val[2] = 0;	//R
        }
    }
    PrintMs("mat.ptr ms");

    //使用at接口遍历
    for (int row = 0; row < mat.rows; row++)
    {
        for (int col = 0; col < mat.cols; col++)
        {
            mat.at<Vec3b>(row, col)[0] = 128;	//B
            mat.at<Vec3b>(row, col)[1] = 128;	//G
            mat.at<Vec3b>(row, col)[2] = 128;	//R
        }
    }
    PrintMs("mat.at ms");

    //通过迭代器遍历
    auto it = mat.begin<Vec3b>();
    auto it_end = mat.end<Vec3b>();
    for(;it!=it_end; it++)
    {
        (*it).val[0] = 0;	//B
        (*it).val[1] = 222;	//G
        (*it).val[2] = 0;	//R
    }
    PrintMs("mat iterator ms");
    namedWindow("mat");
    imshow("mat",mat);
    waitKey(0);
}

3. 时间开销

  • 3000*4000的RGB图像Mat遍历时间开销:
mat.data ms:18ms
mat.step ms:24ms
mat.ptr ms:19ms
mat.at ms:26ms
mat iterator ms:28ms
  • 10000*10000的RGB图像Mat遍历时间开销:
mat.data ms:166ms
mat.step ms:343ms
mat.ptr ms:236ms
mat.at ms:360ms
mat iterator ms:416ms

结论:直接地址访问连续地址>ptr>直接地址访问不连续地址>at>迭代器

  • 直接地址访问连续地址:速度最快,但是需要图片存储空间连续。
  • ptr:进行图像遍历更加高效,推荐使用。
  • 直接地址访问不连续地址:代码复杂,速度也不太行。
  • at:不适合用于像素遍历,速度太慢了,比较适合随机访问的方式。
  • 迭代器:不需要知道图像的行列大小,但速度最慢。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值