1、Mat对象的作用
Mat类用于表示一个多维的单通道或者多通道的稠密数组(稠密与稀疏矩阵的稀疏相对)。它能够用来保存实数或复数的向量、矩阵、灰度或彩色图像,三维像素(voxel volumes),向量场(vector fields),点云(point clouds),张量(tensors),直方图(高维的直方图用SparseMat保存比较好)。
其实Mat就是存储多维矩阵的
2、Mat对象常用的属性
- data uchar型的指针。Mat类分为了两个部分,矩阵头和指向矩阵数据部分的指针,data就是指向矩阵数据的指针
- rows 矩阵的行数
- cols 矩阵的列数
- channels 矩阵元素具有的通道数
- dims 矩阵的维度二维矩阵为2
- size 矩阵的大小,size(cols,rows),Mat.size()返回的是[columu_number,row_number];注意返回的数据顺序是先列后行。
如果矩阵的维度大于2,则是返回size(-1,-1) - type表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量。
其命名规则是
CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
CV_ [每个通道的位数] [符号或无符号] [数据类型前缀] C [通道数]
下面是OpenCV中的宏定义:
CV_8UC1 - 0 | CV_8UC2 - 8 | CV_8UC3 - 16 | CV_8UC4 - 24 |
---|---|---|---|
CV_8SC1 - 1 | CV_8SC2 - 9 | CV_8SC3 - 17 | CV_8SC4 - 25 |
CV_16UC1 - 2 | CV_16UC2 - 10 | CV_16UC3 - 18 | CV_16UC4 - 26 |
CV_16SC1 - 3 | CV_16SC2 - 11 | CV_16SC3 - 19 | CV_16SC4 - 27 |
CV_32SC1 - 4 | CV_32SC2 - 12 | CV_32SC3 - 20 | CV_32SC4 - 28 |
CV_32FC1 - 5 | CV_32FC2 - 13 | CV_32FC3 - 21 | CV_32FC4 - 29 |
CV_64FC1 - 6 | CV_64FC2 - 14 | CV_64FC3 - 22 | CV_64FC4 - 30 |
附:- i i的值为该类型计算出来的值。
注意:
1. F是浮点型数据,其中的C是固定的字符而不是char的C
2. 例如:CV_32SC2含义是32位有符号整数,通道数位2.
3. type一般是在创建Mat对象时设定,如果取得Mat元素的类型,则使用depth;如果是创建Mat则使用type。
type源码:
inline
int Mat::type() const
{
return CV_MAT_TYPE(flags);
}
- depth 矩阵中一个通道的数据类型,这个值衍生出type;
将type的预定义值去掉通道信息就是depth的值
例如:
CV_64F、CV_32S、CV_16U、CV_8U
depth的源码
int Mat::depth() const
{
return CV_MAT_DEPTH(flags);
}
elemSize: 矩阵中一个元素占用的字节数。
如果矩阵的类型是CV_8UC3,那么elemSize = 8/8*3=3 byteselemSize1: 矩阵中一个通道占用的字节数。
如果矩阵的类型是CV_8UC3,那么elemSize = 8/8=1 bytesdatastart和dataend:返回的是矩阵数据存储位置的头指针与尾指针。
上面属性的测试代码
Mat src(4, 5, CV_8UC4, Scalar_<uchar>(1, 2, 3, 4));
cout << src << endl;
cout << "src.channels:" << src.channels() << endl;
cout << "src.type:" << src.type() << " CV_16UC3:" << CV_8UC4 << endl;
cout << "src.depth:" << src.depth() << " CV_16UC:" << CV_8U << endl;
cout << "compute:" <<(((CV_8U)&((1 << 3) - 1)) + (((4)-1) << 3)) << endl;//+、-的优先级有按位操作的优先级高
cout << "src.elemSize:" << src.elemSize() << " elemSize1:" <<src.elemSize1()<< endl;
cout << "src.data:" << hex << (int *)src.data << endl;
cout << "src.datastart:" << hex << (int *)src.datastart << "src.dataend:" << hex << (int *)src.dataend << endl;
上面的compute 是根据
MAKETYPE的宏定义得出来的公式
#define CV_CN_SHIFT 3
#define CV_DEPTH_MAX (1 << CV_CN_SHIFT)
#define CV_8U 0
#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1)
#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK)
#define CV_MAKETYPE(depth,
cn
) (CV_MAT_DEPTH(depth)+(((cn)-1)<<CV_CN_SHIFT))
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
CV_8UC3 的值为: ((CV_8U)&((1<<3)-1)+((cn)-1)<<3)=16
CV_8UC2 的值为:8
CV_8UC1 的值为:0
其中CV_8U是depth,cn是channels;
3、flags属性
flags:这个标志看它的注释,
/*! includes several bit-fields:
- the magic signature
- continuity flag
- depth
- number of channels
*/
int flags;
这个标志包含了the magic signature、submat flag、continuity flag、number of channels、depth。
flags是占32个bit,从低到高:
- 0~2 bit 表示depth,OpenCV中的数据类型共有8个,7个预定义类型,一个用户自定义类型。
#define CV_8U 0
#define CV_8S 1
#define CV_16U 2
#define CV_16S 3
#define CV_32S 4
#define CV_32F 5
#define CV_64F 6
#define CV_USRTYPE1 7
- 3~11 bit 表示channels,OpenCV默认最大通道数为512,所以只需要9-bit就可以表示。
- 0~11 bit 共同表示type。
- 12~13 bit 暂时没有发现用处…
- 14 bit 表示Mat的内存是否连续。一般有create创建的Mat均是连续的,如果是连续,将加快对数据的访问。
- 15 bit 代表Mat是否为某一Mat的submatrix,一般通过ROI以及row(),col(),rowRange(),colRange()等得到的mat均为submatrix。
- 16-31 bit 代表magic signature,暂理解为用来区分Mat的。
(1). 得到depth:
inline
int Mat::depth() const
{
return CV_MAT_DEPTH(flags);
}
定义的宏
#define CV_CN_MAX 512
#define CV_CN_SHIFT 3
#define CV_DEPTH_MAX (1 << CV_CN_SHIFT)
#define CV_8U 0
#define CV_8S 1
#define CV_16U 2
#define CV_16S 3
#define CV_32S 4
#define CV_32F 5
#define CV_64F 6
#define CV_USRTYPE1 7
#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1)
#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK)
由Mat.depth()调用该宏,**这组操作实际上就是取flags,0~2位来计算depth的。这个宏是把flags作为变量传入宏里的flags(值为图片类型的数据),与上面的compute的flags的值不一样(值是CV_8U)。
(2). 得到channels:
inline
int Mat::channels() const
{
return CV_MAT_CN(flags);
}
定义的宏:
#define CV_CN_MAX 512
#define CV_CN_SHIFT 3
#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT)
#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1)
CV_CN_MAX - 1将通道的可能值变为[0,511],这样就能够用9位来表示所有的可能值,左移三位是为了关闭depth位
(3). 获取type:
inline
int Mat::type() const
{
return CV_MAT_TYPE(flags);
}
定义的宏
#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
#define CV_MAKE_TYPE CV_MAKETYPE
//注释掉的是具体类型
/*
#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))
#define CV_8SC1 CV_MAKETYPE(CV_8S,1)
#define CV_8SC2 CV_MAKETYPE(CV_8S,2)
#define CV_8SC3 CV_MAKETYPE(CV_8S,3)
#define CV_8SC4 CV_MAKETYPE(CV_8S,4)
#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))
#define CV_16UC1 CV_MAKETYPE(CV_16U,1)
#define CV_16UC2 CV_MAKETYPE(CV_16U,2)
#define CV_16UC3 CV_MAKETYPE(CV_16U,3)
#define CV_16UC4 CV_MAKETYPE(CV_16U,4)
#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n))
#define CV_16SC1 CV_MAKETYPE(CV_16S,1)
#define CV_16SC2 CV_MAKETYPE(CV_16S,2)
#define CV_16SC3 CV_MAKETYPE(CV_16S,3)
#define CV_16SC4 CV_MAKETYPE(CV_16S,4)
#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n))
#define CV_32SC1 CV_MAKETYPE(CV_32S,1)
#define CV_32SC2 CV_MAKETYPE(CV_32S,2)
#define CV_32SC3 CV_MAKETYPE(CV_32S,3)
#define CV_32SC4 CV_MAKETYPE(CV_32S,4)
#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))
#define CV_32FC1 CV_MAKETYPE(CV_32F,1)
#define CV_32FC2 CV_MAKETYPE(CV_32F,2)
#define CV_32FC3 CV_MAKETYPE(CV_32F,3)
#define CV_32FC4 CV_MAKETYPE(CV_32F,4)
#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n))
#define CV_64FC1 CV_MAKETYPE(CV_64F,1)
#define CV_64FC2 CV_MAKETYPE(CV_64F,2)
#define CV_64FC3 CV_MAKETYPE(CV_64F,3)
#define CV_64FC4 CV_MAKETYPE(CV_64F,4)
#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))*/
#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1)
#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK)
计算方式上述相似,开启0~11 bit的开关(8*512-1),得到flags低12位的值。
(4). 是否Continuous:
bool Mat::isContinuous() const
{
return (flags & CONTINUOUS_FLAG) != 0;
}
定义与操作:
//枚举类型
enum { MAGIC_VAL = 0x42FF0000, AUTO_STEP = 0, CONTINUOUS_FLAG = CV_MAT_CONT_FLAG, SUBMATRIX_FLAG = CV_SUBMAT_FLAG };
enum { MAGIC_MASK = 0xFFFF0000, TYPE_MASK = 0x00000FFF, DEPTH_MASK = 7 };
//宏定义的操作
#define CV_MAT_CONT_FLAG_SHIFT 14
#define CV_MAT_CONT_FLAG (1 << CV_MAT_CONT_FLAG_SHIFT)
#define CV_IS_MAT_CONT(flags) ((flags) & CV_MAT_CONT_FLAG)
#define CV_IS_CONT_MAT CV_IS_MAT_CONT
方式与上相同。
(5). 是否为Submatrix:
inline
bool Mat::isSubmatrix() const
{
return (flags & SUBMATRIX_FLAG) != 0;
}
定义与操作:
//定义在上面的那个枚举那
#define CV_SUBMAT_FLAG_SHIFT 15
#define CV_SUBMAT_FLAG (1 << CV_SUBMAT_FLAG_SHIFT)
#define CV_IS_SUBMAT(flags) ((flags) & CV_MAT_SUBMAT_FLAG)
isContinuous和isSubmartix的用法
cout << "src.isContinuous: " << src.isContinuous() << endl;
cout << "src.isSubmatrix: " << src.isSubmatrix() << endl;
这里介绍了channels,depth,type怎么得到。