OpenCV源码阅读——1.1 Mat的结构

抱着学习的态度,阅读OpenCV源码。我阅读的版本是OpenCV2.4.8,其实2.X在思路上是很相似的。OpenCV自带了详尽的文档。其中opencv_tutorials.pdf是OpenCV入门文档,该文档中有大量的示例;opencv2refman.pdf是函数手册。这两个文档也是重要的参考资料。


第一章 Mat

本章主要内容:Mat类的结构、内存管理、运算、_InputArray类

主要涉及文件有:

include         |  opencv2  |  core  |  core.hpp                     其中有Mat类定义

                                                    |  mat.hpp                     其中有Mat类实现

                                                    |  types_c.h                   C语言类型定义和部分函数

modules      |       core    |    src   |  arithm.cpp                 算法实现

                                                    |  matop.cpp                 Mat的运算


Mat是OpenCV中最关键的类之一,破解Mat类对把握OpenCV有重要作用,同时通过这部分阅读可以了解OpenCV的设计理念。

Mat是Matrix的简称,中文含义是矩阵,OpenCV2.x摒弃了1.x中区别对待IplImage、CvMat等结构的思路,将所有的问题划归到数学概念中去,图像在线性空间中的表达就是矩阵。

另外,OpenCV中定义了Matx(小矩阵)的结构,Vec(向量)是Matx的子类。他们通过_InputArray(输入数组)类实现相互转换。在矩阵运算、图像处理等函数中,通过以_InputArray类为代理,访问Mat或Vec。Mat_<T>是Mat的子类,是Mat的模板化。


1.1 Mat的结构

【core.hpp 1475-2010行】【opencv2refman.pdf 25-44页】

1.1.1 Mat中成员变量

    /*! includes several bit-fields:
         - the magic signature
         - continuity flag
         - depth
         - number of channels
     */
    int flags;
    //! the matrix dimensionality, >= 2
    int dims;
    //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
    int rows, cols;
    //! pointer to the data
    uchar* data;

    //! pointer to the reference counter;
    // when matrix points to user-allocated data, the pointer is NULL
    int* refcount;

    //! helper fields used in locateROI and adjustROI
    uchar* datastart;
    uchar* dataend;
    uchar* datalimit;

    //! custom allocator
    MatAllocator* allocator;

    MSize size;
    MStep step;

(1) flag是标记,他由五部分组成:


1、0-2位:深度,在types_c.h中深度值如下:

CV_8U
00x000
CV_8S
10x001
CV_16U
20x010
CV_16S
30x011
CV_32S
40x100
CV_32F
50x101
CV_64F
60x110
CV_USRTYPE1
70x111

2、3-11位:通道数减1,因为即灰度图像(1通道)时3-11位是0x000000000,彩色图像(3通道)时3-11位是0x000000010

3、14位:MAT_CONT_FLAG,矩阵的数据存储是否连续的标记,1表示连续,0表示不连续

4、15位:SUBMAT_FLAG,子矩阵标记,Mat支持从大矩阵中取出子矩阵,数据没有复制。

例如,假设Mat A是3×3的矩阵

      | 1  2  3 |

A = | 4  5  6 |

      | 7  8  9 |

Mat B = A.rowRange(1,2);//B取A的第2到3行,行号以0开始

则 B = | 4  5  6 |  

           | 7  8  9 |, 

B的数据并没有新增加,而是直接指向了A的数据,B的datastart和dataend表明了起止位置,rows和cols表明了尺寸。具体将在Mat的内存管理中说明。

5、16-31位:默认的标记MAGIC_VAL,由于矩阵有很多种类型,_InputArray代理所有的数据输入时,需要依赖这个量来判断数据类型,这个值就表达了该类的类型。

查看源码可以知道

类型MAGIC_VAL
SparseMat(系数矩阵)0x42FD0000
Mat0x42FF0000
cvMat0x42420000
CvMatND0x42430000
CvSparseMat0x42440000
CvHistogram0x42450000
CvMemStorage0x42890000
CvSeq0x42990000
CvSet0x42980000
IPLImage0x00000070

他们都是类或结构体的前两个字节(int)。IPLImage来自以往的库,他的前两个字节是int  nSize,是结构体的大小,也就是说他的MAGIC_VAL是0x00000070。

(2)dims是维度(一般是2);rows是行数;cols是列数。

(3)data指针指向了数据;refcount指针指向了一个计数器,这个计数器记录着多少个Mat指向了同一个data,当计数为0时,释放data;allocator是动态内存申请器。

(4)step保存了一行的宽度,完整连续的图像step.p[0]与cols相等,子矩阵的step.p[0]与原始图像的cols相等。

代码注释非常给力,以下几行注释清楚地表现了Mat的结构:


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转换成Mat1715-1719

8、从新式的std::vector、cv::Vec、cv::Matx、2D point、3D point、comma initializer转换成Mat1722-1731

(2)赋值运算

9、const Mat& m从另一个Mat转换【1740行】

10、const MatExpr& expr从矩阵表达式转换成Mat【1741行】

        矩阵表达式MatExpr,构造了一个运算结构,具体在Mat的计算中解释

11、const Scalar& s从Scalar转换成Mat,是用一种颜色将整个图像填充【1774行】

(3)数据转换运算

11、括号运算符:截取子矩阵【1842-1844行】

12、数据转换:由Mat转换成老式结构CvMat、CvMatND、IplImage【1846-1851行】

13、数据转换:由Mat转换成vector<_Tp>、Vec<_Tp, n>、Matx<_Tp, m, n>【1853-1855行】

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值