文章目录
- 1. cv::Mat类的成员变量
-
- 1.1 flags
- 1.2 cv::Mat::step
- 2 存储方式,存储位置计算
-
- 2.1 存储方式
- 2.2 🌈存储位置计算
-
- 2.2.1 基本计算公式
- 2.2.1 step代码说明
- 2.2.3 内存地址计算代码说明
- 3 创建数据
-
- 3.0 Mat的构成
-
- 3.0.1 3.0版本之后的Mat
- 3.0.2 cvMat
- 3.1 构造函数
- 3.2 🌈构造函数总结
- 4 Mat访问(at<>, 迭代器和ptr)
-
- 4.0 🌈数据类型(CV_16F)等
- 4.1 🌈模板函数at<>()访问
-
- 4.1.1 基本使用示例
- 4.1.2 构造函数
- 4.2 🌈数组迭代器访问
-
- 4.2.1 示例(对比ptr效果,ptr一个小trick)
- 4.2.2 构造函数MatConstIterator_和MatIterator_
- 4.2.3 NAryMatIterator迭代器构造函数
- 4.3 🌈ptr/指针访问(内存地址)
-
- 4.3.1 示例
- 4.3.2 构造函数
- 4.4 三种访问方式速度比较
-
- 4.4.1 基本说明
- 4.4.2 代码
OpenCV库中的大部分函数,要么是cv::Mat
类的成员,要么是使用cv::Mat
类作为参数,要么就是把cv::Mat
作为返回值,很少有函数和这三种都没有关系。
OpenCV中的cv::Mat
就相当于Numpy中的array类型,是整个库最核心的概念,其它内容都是围绕这个概念建立起来的。
cv::Mat类表示N维稠密数组,cv::SparsesMat表示N维稀疏数组
1. cv::Mat类的成员变量
OpenCV2.x版本中的CvMat结构,与现在OpenCV3.x之后的还是有很大不同的。
现在的cv::Mat类的成员变量:
- int flags,包括下面四种标志,
- the magic signature,魔法标识
- continuity flag,连续性标志
- depth,深度
- number of channels,通道数
- int dims,表示矩阵的维度,>=2
- int rows和int cols表示矩阵的高/行和宽/列,当维度>2时,这两个值无效,返回(-1,-1)
- uchar * data,一个数据指针,指向数据真正存储的地方
- MatStep step,定义矩阵的数据布局
- MatSize size: Size(cols, rows) ,这是因为在Size的构造器里,rows和columns的参数顺序是相反的,如下:
typedef Size2i cv::Size typedef Size_<int> cv::Size2i Size_ (_Tp _width, _Tp _height) size指定的先是宽cols,再是高rows
1.1 flags
以下回答来自chatGPT:
在 OpenCV 中,cv::Mat
类有一个特殊的成员变量 flags
,它是一个整数,表示 cv::Mat
对象的属性和标志。
flags
的值是通过对不同的标志位进行按位或操作得到的,不同的标志位表示不同的属性和行为。以下是一些常用的 flags
标志和它们的作用:
cv::Mat::CONTINUOUS_FLAG
:表示矩阵是连续的,即数据在内存中是按行存储的,没有间隔。cv::Mat::DEPTH_MASK
:表示矩阵的深度(数据类型),可以通过与cv::Mat::DEPTH_MASK
进行按位与操作来提取深度值。cv::Mat::CHANNELS_MASK
:表示矩阵的通道数,可以通过与cv::Mat::CHANNELS_MASK
进行按位与操作来提取通道数值。cv::Mat::MAGIC_MASK
:用于检测错误或非法的cv::Mat
对象。cv::Mat::TYPE_MASK
:用于提取矩阵的类型信息,flags
中除去上述标志位以外的部分。
此外,还有一些特定的标志位,如 cv::Mat::CONTINUOUS
、cv::Mat::CV_32S
等,用于表示特定的属性。
你可以使用 cv::Mat::flags
成员变量来获取 cv::Mat
对象的标志位,也可以使用 cv::Mat::type()
函数来获取矩阵的类型。例如:
cv::Mat image = cv::imread("image.jpg");
int flags = image.flags;
int type = image.type();
注意,通过 flags
获取的是一个整数,你可以通过按位与与按位右移等操作来提取具体的属性值。而通过 type()
函数获取的是一个表示类型的整数,通过与 CV_
系列常量进行比较,可以获知矩阵的具体类型。
参考:
- OpenCV学习之路(二)——Mat对象
- 【OpenCV4】cv::Mat.isContinuous() 函数判断内存是否连续(c++
- OpenCV】从Mat的flags中可以读到的信息,以及相关宏定义
1.2 cv::Mat::step
详见OpenCV:Mat中的step、elemSize和任意内存访问
2 存储方式,存储位置计算
2.1 存储方式
cv::Mat
可以用来表示任意维度的数组,数组中数据的存储和n维光栅扫描顺序
的类似。
如果是一维数组,其存储就是连续的;
如果是二维数组,数据被组织成行,然后按照行排列(以前数据结构里,数组排列的行优先)
如果是三维数组(plane),那就是每个plane先被逐行填满,然后plane再一个接一个。
例如:
有一维数组: [1,3,5,2,7]
其存储:①③⑤②⑦
有二维数组(OpenCV里打印2d数组结果是这样的):
[1,3,5,2,7;
1,3,5,2,7;
1,3,5,2,7]
其存储:①③⑤②⑦|①③⑤②⑦|①③⑤②⑦
一个|代表一行
三维数组。。。无法直接使用std::cout打印,可以理解为
其存储:
①③⑤②⑦|①③⑤②⑦|①③⑤②⑦||①③⑤②⑦|①③⑤②⑦|①③⑤②⑦||①③⑤②⑦|①③⑤②⑦|①③⑤②⑦
一个|代表一行,一个||表示一个plane
2.2 🌈存储位置计算
2.2.1 基本计算公式
从1.1 成员变量中可以知道,对于一个矩阵 M M M,其布局是由数组M.step[]
所定义的,因此索引为 [ i 0 , i 1 . . . , i M . d i m s − 1 ] [i_0,i_1...,i_{M.dims-1}] [i0,i1...,iM.dims−1]的元素(其中 0 ≤ i k ≤ M . s i z e [ k ] 0\leq i_k \leq M.size[k] 0≤ik≤M.size[k])的地址可以通过下式计算:
a d d r ( M i 0 , i 1 . . . , i M . d i m s − 1 ) = M . d a t a + M . s t e p [ 0 ] ∗ i 0 + M . s t e p [ 1 ] ∗ i 1 + . . . . + M . s t e p [ M . d i m s − 1 ] ∗ i M . d i m s − 1 addr(M_{i_0,i_1...,i_{M.dims-1}})=M.data+M.step[0]*i_0+M.step[1]*i_1+....+M.step[M.dims-1]*i_{M.dims-1} addr(