c++ opencv mat_10、OpenCV中图像和Mat类型(一)

Mat类型可以被认为是OpenCV库的核心。 OpenCV库中绝大多数的函数都是Mat类的成员,以Mat作为参数,或者Mat作为返回值。

7740f4192c325cda0441923b4078a980.png

Mat类用于表示任意维数的密集数组。即使对于数组中的该条目为零,也存在与该条目相对应的数据值。大多数图像都以密集阵列的形式存储。在稀疏数组的情况下,通常只存储非零条目。如果许多条目都是零,那么可以节省大量的存储空间。使用稀疏数组而不是密集数组的常见情况是直方图。对于许多直方图,大多数条目都是零,并且存储所有这些零不是必需的。对于稀疏数组的情况,OpenCV有另一种数据结构,SparseMat。

如果你熟悉OpenCV库的C接口(2.1之前的版本),您将会记住IplImage和CvMat的数据类型。 你也可能记得CvArr。 在C ++实现中,所有这些都消失了,用Mat代替。Mat类可以用于任何维数的数组。数据被存储在阵列中,被认为是"光栅扫描顺序"的n维数字。这意味着在一维数组中,元素是顺序的。在二维数组中,数据按行组织,每行依次出现。对于三维阵列,每个平面都是逐行填充的。

每个Mat都包含一个标志元素,指示数组内容,一个dims元素指示维数,rows和cols元素指示行数和列数,指向数据指针的位置数组数据被存储,一个类似于Ptr <>的的引用计数器。数据数组被布置成使得其索引由(i0,ii,...,iNd-1)给出的元素的地址是:

在二维数组的简单情况下,这可以简化为:

&(mtxi, j)= mtx.data +mtx.step 0 *i +mtx.step 1 *j

Mat中每个数据元素本身可以是单个数字,也可以是多个数字。在多个数字的情况下,这就是多通道数组。一个数组可能被认为是一个32位浮点数的二维三通道数组;在这种情况下,数组的元素是三个32位浮点数,大小为12个字节。在内存中布局时,数组的行可能不是绝对顺序的;在下一个之前可能会有小的间隙缓冲每一行。一个n维单通道阵列和一个(n-1)维多通道阵列之间的区别在于,这个填充将始终发生在整行的末尾,即元素中的通道将始终是连续的)。

可以简单地通过实例化一个类型为Mat的变量来创建一个数组。以这种方式创建的数组没有大小和数据类型。但是,可以使用create()等成员函数分配数据。 create()的一个变体将多个行,多个列和一个类型作为参数,并将该数组表示为一个二维对象。数组的类型决定了它具有哪种元素以及通道的数量。所有这些类型都在库中定义,并具有CV_ {8U,16S,16U,32S,32F,64F} C {1,2,3}的格式。例如,CV_32FC3意味着一个32位浮点三通道阵列。

也可以在首次分配矩阵时指定这些内容。Mat有许多构造函数,其中一个与create()具有相同的参数。例如:

cv::Mat m;

// 创建3行10列3通道32位浮点型数据

m.create( 3, 10, CV_32FC3 );

//设置第一个通道为1.0,第二个通道为0.0,第三个通道为1.0

m.setTo( cv::Scalar( 1.0f, 0.0f, 1.0f ) );

//上面的定义与下面的语句等价

Mat m( 3, 10, CV_32FC3, cv::Scalar( 1.0f, 0.0f, 1.0f ) );

Mat对象实际上是数据区域的头,原则上它是一个完全独立的东西。 例如,可以将一个矩阵n分配给另一个矩阵m(即,m = n)。 在这种情况下,m中的数据指针将被改变为指向与n相同的数据。 先前由m的数据元素指向的数据将被释放。同时,它们现在共享的数据区域的引用计数器将递增。同时将更新m成员的数据(如行,列和标志),以准确描述m中数据指向的数据。

表1是Mat的构造函数的完整列表。但事实上,大多数时候可能使用其中的一小部分。

ce2a05a5bd68187c3bdc003df4c892a8.png

表1列出了Mat对象的构造函数。除了默认的构造函数之外,它们分为三个基本类别:有些需要多行和多列来创建二维数组的类,有些使用Size对象创建,有些构造n维数组并要求指定维数并传入指定每个维的大小的整数数组的指针。此外,其中一些允许初始化数据,或者通过Scalar提供初始化值(这时整个数组将被初始化为该值),或者通过提供指向数据块的指针来指定。在后一种情况下,只是为现有数据创建一个数据头,不复制数据;将数据成员设置为指向由数据参数指示的数据)。

表2的复制构造函数显示了如何从另一个数组创建一个数组。除了基本的复制构造函数外,还有三种方法用于从现有数组的子区域构建数组,以及使用某个矩阵表达式的结果初始化新矩阵的构造函数。

171bbfd192ae7a8a2cbd33476e38c063.png

也可以从OpenCV2.1版之前的CvMat或IplImage结构创建新的C ++风格的Mat结构。在这种情况下,可以采用下面表3这种方式转换。

d90169d9b958c000af92a9e50978f984.png

这些构造函数可能比你刚开始认识OpenCV的时候要多得多。还有一种构造函数是模板构造函数。 这些被称为模板构造函数是因为它们从本身就是模板的东西构建了Mat的实例。 这些构造函数允许使用任意Vec <>或Matx <>来创建具有相应维数和类型的Mat数组,或者使用任意类型的STL向量<>对象来构造一个相同类型的数组。表4是这种构造方式。

020fbddca86cd6037d8bdc238c3831bf.png

Mat类还提供了许多静态成员函数来创建特定类型的常用数组(表4-5)。 这些函数包括zero(),ones()和eye()等函数,它们分别构造一个全是零的矩阵,一个全是1矩阵的矩阵和一个单位矩阵。表5是这种构造方式

d59012eee2c515e2ff340df4c19b8a9e.png

对于Mat中的数据访问方式可以参考第6部分的说明。

有时候我们需要访问数组中的某一块元素,可能是选择一行或一列,或原始数组的任何子区域。有很多方法可以做到这一点,表6是Mat类的成员函数,并返回调用它们的数组的子部分。

cffdc293f9e6a897bdcefbcef65231f5.png

这些方法中最简单的方法是row()和col()。与row()和col()紧密相关的是rowRange()和colRange()。这些函数基本上是一样的,只不过他们会提取一个具有多个连续行(或列)的数组。可以通过以下两种方式之一调用这两个函数:指定一个整数开始和结束行(或列),或者通过传递一个行(或列)的Range对象。范围包括开始索引但不包括结束索引。

除了从m.diag()返回的数组引用矩阵的对角线元素之外,成员函数diag()与row()或col()的作用相同。 m.diag()需要一个整数参数,用于指示要提取哪个对角线。如果该参数为零,那么它将是主对角线。如果是正数,则它将从阵列上半部分的主对角线偏移该距离。如果它是负数,那么它将来自阵列的下半部分。

提取子矩阵的最后一种方法是使用operator()。使用这个运算符,你可以传递一对范围(行的Range和列的Range)或者从Rect指定你想要的区域。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值