首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

计算机视觉核心Mat数组的逐元素访问

01

利用at()成员函数访问数组元素

最基础的直接访问手段是通过模板成员函数at(),对数组元素进行访问。因为是模板函数,所以该函数可以接受各种类型和维度的参数。使用该函数访问数组元素的例子如下:

代码输出结果如图:

结果分析:上述代码有三个部分。

部分一:访问的是二维,单通道数组。

cv::Mat::eye(10,10,CV_32FC1):定义了一个10乘以10的32float的一维单位数组(CV_32FC1)

m_1.at(3,3):模板成员函数m_1.at,输入模板参数float,(3,3)表示访问的是一维数组中第四行第四列的元素,如下图所示。

部分二:访问的是二维,三通道数组

Mat m_2 = cv::Mat::eye(3,3,CV_32FC3):定义了一个3乘以3的32float的三维单位数组(CV_32FC3)

m_2.at(i, j)[0]:模板成员函数m_2.at,输入模板参数cv::Vec3f,(i,j)[0]表示访问的是三维数组中第i+1行,第j+1列,通道一的元素。

m_2.at(i, j)[1]:模板成员函数m_2.at,输入模板参数cv::Vec3f,(i,j)[0]表示访问的是三维数组中第i+1行,第j+1列,通道二的元素。

m_2.at(i, j)[2]:模板成员函数m_2.at,输入模板参数cv::Vec3f,(i,j)[0]表示访问的是三维数组中第i+1行,第j+1列,通道三的元素。

cv::Vec3f:对于访问多通道(本例中为3通道)数组而言,不能直接用float作为模板参数,因为正如上面三个访问元素语句所示,其实对于当前类型而言直接访问的不是单个元素,而是所有通道中的第i+1行,j+1列的元素向量(m_2.at(i, j)),空间示意图如下图所示。因此在访问多通道数组时,需要传入固定向量类型作为模板参数。

部分三:访问的是三维,三通道数组。

该部分通过直接访问的手段,让我们能够进一步感受到,多维度和多通道的区别。下图之前也有用到过,多维度和多通道的概念切记不要混淆(上一篇文章最后利用两张图很形象的告诉大家维度和通道的区别)。

m_3.at(i, j,k):上述注释中也有提到,当数据类型为单通道的时候,需要用float访问,多通道的时候需要用固定向量类的对应格式的别名来访问(此例中是三通道浮点数所以用Vec3f)。

02

利用ptr()成员函数访问数组元素

要访问二维数组,还可以提取指向数组特定行的C样式指针。 这是通过cv :: Mat的ptr ()模板成员函数完成的(回想一下,数组中的数据是连续的,因此以这种方式访问特定列是没有意义的; 我们很快就会看到正确的方法。)

与at>()一样,ptr ()是一个使用类型名称实例化的模板函数。 它需要一个整数参数来指示您希望获得指针的行。 该函数返回一个指向构造数组的基本类型的指针(即,如果数组类型是CV_32FC3,则返回值的类型为float *)。因此,给定float类型的三通道矩阵mtx,构造mtx.ptr (3)将返回指向mtx第3行中第一个元素的第一个(浮点)通道的指针。这通常是 访问数组元素的最快方法,因为一旦有了指针,就可以找到数据。

因此有两种方法可以在矩阵mtx中获得指向数据的指针。 一种是上述的使用ptr ()成员函数。 另一种是直接使用成员指针数据,并使用成员数组step []来计算地址。后一种选择类似于C接口中常用的选项,但在at(),ptr ()和迭代器访问数组的过程中,通常不再优先 。 话虽如此,直接地址计算可能仍然是最有效的,特别是当您处理大于两个维度的数组时。

关于C风格的指针访问,最终要的一点是, 如果要访问数组中的所有内容,您可能希望能够一次迭代一行; 这是因为行不一定会在数组中连续打包(packed?)。但是成员函数isContinuous()会告诉你行是否在数组中连续打包(packed)。如果判断完了之后,当前数组中行是连续的,那么你只需要找到第一行中第一个元素的指针,那么你就可以访问真个数组,就好像这个多维数组是个巨大的一维数组一样。

Note:这部分访问涉及到data和step计算地址,因此后续会单独介绍这部分详解,本文不作过多讨论。

03

利用迭代器访问数组元素

顺序访问的另一种形式是使用cv :: Mat中内置的迭代器机制。这种机制和STL标准库中的提供的机制非常的类似。基本思想是OpenCV提供了迭代器模板。cv :: Mat成员函数begin()和end()返回此类型的对象。这种迭代方法很方便,因为迭代器足够智能,可以自动处理连续打包和非连续打包,以及处理数组中的任意数量的维度。

必须声明每个迭代器,并在声明阶段将其指定为构造数组对象的类型。以下是迭代器的一个简单示例。

cv::randu(m, -1.0f, 1.0f):随机生成-1到1的值,并填满多维多通道数组。

Mat_::iterator it = m.begin():利用begin成员函数,返回Vec3f类型的指针(迭代器),指向数组的头部。

Mat_::iterator itend = m.end():利用end成员函数,返回Vec3f类型的指针(迭代器),指向数组的尾部。

(*it)[0] = 255;

(*it)[1] = 255;

(*it)[2] = 255:对每一个位置的三个通道作一个相同的操作。

在对整个数组执行操作时,通常会使用基于迭代器的访问,或者在多个数组之间执行一些基于元素级的操作(Elementwise)。比如将两个数组相加或将数组从RGB颜色空间转换为HSV颜色空间这样的案例中,对于每个像素位置而言,进行的都是相同精确操作,正如上述代码所示,此时使用迭代器会比较方便。

迟到的圣诞快乐~,昨晚四个人搭了4个小时的成果。能坚持下来不容易~~

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181226G0FSDN00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券