#OpenCV源码阅读#
抱着学习的态度,阅读OpenCV源码。我阅读的版本是OpenCV2.4.8
,其实2.X在思路上是很相似的。OpenCV自带了详尽的文档。其中:
opencv_tutorials.pdf
是OpenCV入门文档,该文档中有大量的示例;opencv2refman.pdf
是函数手册。
这两个文档是重要的参考资料,使用好两本文档就能使用OpenCV最重要的功能里。
##第一章 Mat##
本章主要内容:Mat类的结构
、内存管理
、运算
、_InputArray类
Mat是OpenCV中最关键的类之一,破解Mat类对把握OpenCV有重要作用,同时通过这部分阅读可以了解OpenCV的设计理念。
Mat是Matrix的简称,中文含义是矩阵,OpenCV2.x摒弃了1.x中区别对待IplImage、CvMat等结构的思路,将所有的问题划归到数学概念中去,图像在线性空间中的表达就是矩阵。
另外,OpenCV中定义了Matx(小矩阵)的结构,Vec(向量)是Matx的子类。他们通过_InputArray(输入数组)类实现相互转换。在矩阵运算、图像处理等函数中,通过以InputArray类为代理,访问Mat或Vec。Mat
本章主要涉及文件有:
Path | File | Description |
---|---|---|
include/opencv2/core/ | core.hpp | 其中有Mat类定义 |
mat.hpp | 其中有Mat类实现 | |
types_c.h | C语言类型定义和部分函数 | |
modules/core/src/ | arithm.cpp | 算法实现 |
matop.cpp | Mat的运算 |
###1.1 Mat的结构###
【core.hpp 1475-2010行】【opencv2refman.pdf 25-44页】
####1.1.1 Mat中成员变量####
|
|
- (1)flag 标记,由五部分组成:
1、0-2位 depth 深度,在types_c.h中深度值如下:
宏 | 10 | 2 |
---|---|---|
CV_8U | 0 | 0x000 |
CV_8S | 1 | 0x001 |
CV_16U | 2 | 0x010 |
CV_16S | 3 | 0x011 |
CV_32S | 4 | 0x100 |
CV_32F | 5 | 0x101 |
CV_64F | 6 | 0x110 |
CV_USRTYPE1 | 7 | 0x111 |
2、3-11位 channel 通道数(减1)
灰度图像(1通道)时3-11位是0x000000000,彩色图像(3通道)时3-11位是0x000000010
3、14位:MAT_CONT_FLAG 连续标记
矩阵的数据存储是否连续的标记,1表示连续,0表示不连续
4、15位:SUBMAT_FLAG,子矩阵标记
Mat支持从大矩阵中取出子矩阵,数据没有复制。子矩阵为1,否则为0。
例如,假设Mat A是3×3的矩阵
|
|
则
B的数据并没有新增加,而是直接指向了A的数据,B的datastart和dataend表明了起止位置,rows和cols表明了尺寸。具体将在Mat的内存管理中说明。
5、16-31位:MAGIC_VAL 魔法值,矩阵类型
由于矩阵有很多种类型。图像处理函数中以_InputArray为输入图像,此时就需要依赖这个量来判断数据原始类型。
查看源码可以知道:
类型 | 说明 | MAGIC_VAL值 |
---|---|---|
SparseMat | 系数矩阵 | 0x42FD0000 |
Mat | 矩阵 | 0x42FF0000 |
cvMat | C矩阵 | 0x42420000 |
CvMatND | C多维矩阵 | 0x42430000 |
CvSparseMat | C稀疏矩阵 | 0x42440000 |
CvHistogram | C直方图 | 0x42450000 |
CvMemStorage | C内存存储 | 0x42890000 |
CvSeq | C队列 | 0x42990000 |
CvSet | C集合 | 0x42980000 |
IPLImage | IPL图像 | 0x00000070 |
他们都是类或结构体的前两个字节(int)。IPLImage来自以往的库,他的前两个字节是int nSize,是结构体的大小,所以他的MAGIC_VAL是0x00000070
(2)dims是维度(一般是2),rows是行数,cols是列数
当维度不为2时,rows=cols=-1
(3)data指针指向了数据;refcount指针指向了一个计数器;allocator是动态内存申请器。
计数器记录着多少个Mat指向了同一块data,当计数为0时,释放data
(4)step保存了一行的宽度
完整连续的图像step.p[0]与cols相等,子矩阵的step.p[0]与原始图像的cols相等。
####1.1.2 Mat的构造函数、赋值运算符、数据类型转换运算符####
构造函数、赋值运算、类型转换都有数据转换能力:
- (1)构造函数
1、空构造函数【1690行】
2、指定尺寸和类型【1692行】,或由Scalar结构定义尺寸和类型【1696行】
3、高维【1700行】
4、从其他Mat拷贝【1704行】
5、从数据块拷贝并指定尺寸和类型【1706行】
6、只定义一个头,数据指向其他Mat中一部分(行列范围、ROI)【1711行】
7、从老式的CvMat、CvMatND、IplImage转换成Mat【1715-1719行】
8、从新式的std::vector、cv::Vec、cv::Matx、2D point、3D point、comma initializer转换成Mat【1722-1731行】
- (2)赋值运算
9、const Mat& m从另一个Mat转换【1740行】
10、const MatExpr& expr从矩阵表达式转换成Mat【1741行】
矩阵表达式MatExpr,构造了一个运算结构,具体在Mat的计算中解释
11、const Scalar& s从Scalar转换成Mat,是用一种颜色将整个图像填充【1774行】
- (3)数据转换运算
12、括号运算符:截取子矩阵【1842-1844行】
13、数据转换:由Mat转换成老式结构CvMat、CvMatND、IplImage【1846-1851行】
14、数据转换:由Mat转换成vector<_tp>、Vec<_tp, n="">、Matx<_tp, m,="" n="">【1853-1855行】