Lecture 3 opencv2系列之遍历Mat

码途追梦人
• 阅读 7409

阅读本节内容,建议先阅读Lecture 2 opencv2系列之初识Mat,了解图像像素数据在Mat中的存储方式。

《The OpenCV Tutorials》给出3种遍历Mat中图像像素矩阵的方法,分别是指针遍历(ptr)、迭代器(MatIterator)、
at函数,前两者亦分别称作高效方法、安全方法。其中最为高效的是指针方法。
本文只介绍指针方法。

以下代码实现对图像像素数据的遍历,我们打印图像的红色分量。

代码

#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"

using namespace std;
using namespace cv;

int main(int argc, const char *argv[])
{
    if (argc != 2)
    {
        cout<<"Number of Parameters is Wrong!"<<endl;
        return -1;
    }

    Mat src = imread(argv[1],IMREAD_COLOR);

    int channels = src.channels();

    int nRows = src.rows;
    //图像数据列需要考虑通道数的影响;
    int nCols = src.cols * channels;    

    if (src.isContinuous())//连续存储的数据,按一行处理
    {
        nCols *= nRows;
        nRows = 1;
    }

    int i,j;
    uchar* p;
    for( i = 0; i < nRows; ++i)
    {
        p = src.ptr<uchar>(i);
        for ( j = 2; j < nCols; j+=3)//注意通道顺序为BGR,红色为第三个数据;
        {
            cout<<int(p[j])<<" ";   
        }
        cout<<endl;
    }


    return 0;
}

释义

  1. 如果只是单纯打印图像数据的话,可以直接用cout<<src来实现,OpenCV2重定义了<<运算符,实现
    了矩阵的格式化输出。
    详细内容参见The OpenCV Tutorials Release 2.4.9.0,p.148。
  2. 图像坐标系和像素矩阵。
    图像左上角作为原点,按行和列展开。故图像左上角像素对应矩阵的0行0列数据,这里列不计通道。
  3. OpenCV默认使用BGR的通道顺序。
  4. 行数据的填补。
    宽W高H的真彩色图像,像素数据存储需要WxHx3个uchar构成的内存块,但是出于效率考虑,每行可能
    会填补一些额外像素,亦即存储像素数据的宽度不一定是W,往往填补为4或8的倍数,因为这样一些多
    媒体处理芯片可以更高效的处理图像。
    图像的宽高分别由colsrows给出,行像素个数由cols*channels()给出,实际行的字节数由step[0]
    给出。对于有额外填补的行数据,cols!= step[0]/elemSize(),反之,cols==step[0]/elemSize()
    我们可以用成员函数isContinuous()判断图像是否对行进行了填补,对于没有进行填补的图像,我们视其
    像素数据为一个长为WxHxchannels()的一维数组,加快循环速度。
  5. 行首地址。
    Mat的成员函数ptr(int j)返回第j行的首地址。
  6. 如果仔细阅读过Lecture 2 opencv2系列之初识Mat,对于遍历Mat,自然想到用data+step+elemSize()
    实现,这也是基于指针的方法。
    核心循环代码为:
   int i,j;
   uchar *p;
   for (i = 0; i < nRows; i++)
   {
       p = src.<uchar>data + i * src.step[0];
       for (j = 2; j < nCols; j += 3)
       {            
           cout<<int(p[j*src.elemSize1()])<<" ";//本例中,src.elemSize1()=1;故可简写为p[j]。
       }
   }

本质上是因为src.ptr(i) == src.data + i * src.step[0]
在《OpenCV2 计算机视觉编程手册》一书中,Laganiere不建议用这种方法,原因是:容易出错,并且不适用于带“感兴趣
区域”的图像。

参考文献

  1. The OpenCV Reference Manual Release 2.4.9.0。
  2. The OpenCV Tutorials Release 2.4.9.0。
  3. 加拿大, Laganiere, R., & 张静. OpenCV2 计算机视觉编程手册.
点赞
收藏
评论区
推荐文章
Chase620 Chase620
4年前
Dubbo 源码分析 - 集群容错之 LoadBalance
Dubbo源码分析集群容错之LoadBalance注:本系列文章已捐赠给Dubbo社区,你也可以在Dubbo中阅读本系列文章。1.简介LoadBalance中文意思为负载均衡,它的职责是将网络
Stella981 Stella981
3年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Easter79 Easter79
3年前
TiKV 源码解析系列文章(十四)Coprocessor 概览
作者:Shirly本文将简要介绍TiKVCoprocessor的基本原理,面向想要了解TiKV数据读取执行过程的同学,同时也面向想对该模块贡献代码的同学。阅读本文前,建议读者对TiDB整体架构有所了解,先阅读三篇文章了解TiDB技术内幕:说存储(https://www.oschina.net/action/GoToLink?url
Stella981 Stella981
3年前
Mat 的几种初始化和赋值方法
这几天用到了由cv::Point3f和std::vector<float到cv::Mat数据类型的转换。本质上就是换一下容器。今晚做个小总结。由Point3f到Mat有两种方法,一种使用cv::Mat_<cv::Point3f(),另一种是在声明时使用{}初始化。\\注意:
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
thinkphp整合系列之友盟消息推送
上篇文章 thinkphp集成系列之phpmailer批量发送邮件(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fbaijunyao.com%2Farticle%2F69)讲过的;邮件有着零成本、内容丰富的优点;但是一个非常硬的硬伤;这家伙的及时性太差了;尤其是随着90、00
Stella981 Stella981
3年前
OpenCV常用库函数[典]
_一、core_ 模块1、Mat基本图像容器     Mat 是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不同的维数)的指针。        创建Mat对象方法:1.1Mat()构造函数:
Wesley13 Wesley13
3年前
FMDB源码阅读(二)
随笔31文章0评论101【原】FMDB源码阅读(二)阅读目录1.前言2.executeUpdate:系列函数3.executeStatements:系列函数4.executeQueryWithFormat:和executeUpdateWithFormat:函数5.(void)bindObje
Stella981 Stella981
3年前
OpenCV访问像素点
三种方法迭代器创建一个Mat::Iterator对象it,通过itMat::begin()来的到迭代首地址,递增迭代器知道itMat::end()结束迭代;while(it!Scr.end<Vec3b()){//(it)00;//蓝色通道置零;
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
4个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
码途追梦人
码途追梦人
Lv1
梦里相思,故国王孙路。
文章
4
粉丝
0
获赞
0