opencv中mat详细解析

1、起源

OpenCV作为强大的计算机视觉开源库,很大程度上参考了MatLab的实现细节和风格,比如说,在OpenCV2.x 版本以后,越来越多的函数实现了MatLab具有的功能,甚至干脆连函数名都一模一样(如 imread, imshow,imwriter等)。这一做法,不仅拉近了产品开发与学术研究的距离,并极大程度的提高了开发人员的研发效率,不得不说,Intel公司真的是一个伟大的公司。

在计算机内存中,数字图像以矩阵的形式存储和运算,比如,在MatLab中,图像读取之后对应一个矩阵,在OpenCV中,同样也是如此。

在早期的OpenCV1.x版本中,图像的处理是通过IplImage(该名称源于Intel的另一个开源库Intel Image Processing Library ,缩写成IplImage)结构来实现的。早期的OpenCV是用C语言编写,因此提供的借口也是C语言接口,其源代码完全是C的编程风格。IplImage结构是OpenCV矩阵运算的基本数据结构。

到OpenCV2.x版本,OpenCV开源库引入了面向对象编程思想,大量源代码用C++重写,Mat类 (Matrix的缩写) 是OpenCV用于处理图像而引入的一个封装类。从功能上讲,Mat类在IplImage结构的基础上进一步增强,并且,由于引入C++高级编程特性,Mat类的扩展性大大提高,Mat类的内容在后期的版本中不断丰富,如果你查看Mat类的定义的话(OpenCV3.1\sources\modules\core\include\opencv2\core\mat.hpp),会发现其设计实现十分全面而具体,基本覆盖计算机视觉对于图像处理的基本要求。
继承 inheritance:

mat_inheritance

2、构造函数

    // 默认构造函数 Mat A;
    Mat ()
    // 常用构造函数 Mat A(10,10,8UC3);
    Mat (int rows, int cols, int type)

    //Mat A(300, 400, CV_8UC3,Scalar(255,255,255));
    Mat (int ndims, const int *sizes, int type, const Scalar &s)

    Mat (Size size, int type)

    Mat (int rows, int cols, int type, const Scalar &s)

    Mat (Size size, int type, const Scalar &s)

    Mat (int ndims, const int *sizes, int type)

    Mat (const Mat &m)

    Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)

    Mat (Size size, int type, void *data, size_t step=AUTO_STEP)

    Mat (int ndims, const int *sizes, int type, void *data, const size_t *steps=0)

    Mat (const Mat &m, const Range &rowRange, const Range &colRange=Range::all())

    //Mat D (A, Rect(10, 10, 100, 100) );
    Mat (const Mat &m, const Rect &roi)

    Mat (const Mat &m, const Range *ranges)

3、初始化

初始化一个Mat文件出来一般有两种形式:

// 1、imread
Mat src = imread("csdn.png");

//2、create
Mat src;
if(src.empty())
{
    src.create(Size size, VC_8UC3);
}

3、Mat结构

我们先来看看Mat结构,在你初始化一个Mat结构时,它的全部结构是这样的。
Mat类可以分为两个部分:矩阵头和指向像素数据的矩阵指针。
MAT

1.flags

mat_flags
从定义可以看出flags是int类型,共占32位,结合上图可以看出各位所代表的意思。

从低位到高位:

0-2位代表depth即数据类型(如CV_8U),OpenCV的数据类型共7类,故只需3位即可全部表示。

3-11位代表通道数channels,因为OpenCV默认最大通道数为512,故只需要9位即可全部表示,可参照下面求通道数的部分。

0-11位共同代表type即通道数和数据类型(如CV_8UC3)

12-13位暂没发现用处,也许是留着后用,待发现了再补上。

14位代表Mat的内存是否连续,一般由creat创建的mat均是连续的,如果是连续,将加快对数据的访问。

15位代表该Mat是否为某一个Mat的submatrix,一般通过ROI以及row()、col()、rowRange()、colRange()等得到的mat均为submatrix。

16-31代表magic signature,暂理解为用来区分Mat的类型,如果Mat和SparseMat

更细致的分析推荐这篇文章flags

2.dims

int cv::Mat::dims   ()  const

the matrix dimensionality >= 2
矩阵的维数,但是这里一般结果都是2,因为opencv好像存储多维矩阵也是通过二维矩阵来计,它和基本的channels不一样。

3.channels

int cv::Mat::channels   ()  const

返回图像的通道数。

4.cols rows

int cv::Mat::cols; //返回矩阵的列数

int cv::Mat::rows // 返回矩阵行数

5.data

uchar* cv::Mat::data // 指向矩阵的数据单元的指针

6.refcount

refcount它记录了这个矩阵的数据被其他变量引用了多少次。在c++中矩阵的一些赋值操作往往只给新的变量赋予一个新的头文件,而数据部分只把数据指针指过去,而不重新分为内存,需要程序员来管理内存。这样的话就会有隐患,因为如果原始的变量的数据内存释放了,新的变量却还在,指向了已经被释放的内存区域,如果对新变量进行操作,很可能出现意想不到的问题。不过不用担心,OpenCV的开发者早就想到了这个问题,并为我们想到了一个解决方法,那就是靠这个refcount来记录该数据被多少变量共用,直到最后一个变量被释放时,才释放掉这个存储数据内存块。这也是为什么类定义中refcount为指针,让实际记录次数的变量跟在矩阵数据最后面。
保存图像像素数据的矩阵则会随着图像的大小而改变,通常数据量会很大,比矩阵头大几个数量级。这样,在图像复制和传递过程中,主要的开销是由存放图像像素的矩阵而引起的。因此,OpenCV使用了引用次数,当进行图像复制和传递时,不再复制整个Mat数据,而只是复制矩阵头和指向像素矩阵的指针,但是其矩阵指针指向同一个矩阵,也就是其中任何一个改变了矩阵数据都会影响另外一个。
那么,多个Mat共用一个矩阵数据,最后谁来释放矩阵数据呢?
这就是引用计数的作用,当Mat对象每被复制一次时,就会将引用计数加1,而每销毁一个Mat对象(共用同一个矩阵数据)时引用计数会被减1,当引用计数为0时,矩阵数据会被清理。这就是refcount的作用。

7.datastart dataend datalimit

const uchar* cv::Mat::dataend
const uchar* cv::Mat::datalimit
const uchar* cv::Mat::datastart

helper fields used in locateROI and adjustROI
这些都是用来控制ROI区域,来获取一些图像的局部切片,减少计算量或者特殊需求的。

cv::Rect rect(100, 100, 100, 100); 

srcImage(rect).copyTo(roiImage); 

8.allocator

custom allocator
如果需要创建一个新矩阵的内存空间,系统会调用MatAllocator类作为分配符进行内存的分配。

9.size

MatSize cv::Mat::size // 返回矩阵大小

10.step

矩阵元素寻址

addr(Mi0,...,iM.dims−1)=M.data+M.step[0]∗i0+M.step[1]∗i1+...+M.step[M.dims−1]∗iM.dims−1

step[i]是Mat类中十分重要的一个属性,表示第i维的总大小,单位字节
M.data指向存储这列的首地址(类似于数组名)
M.dims是总维度

后续

更复杂细节后续再更

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010248552/article/details/79962132
文章标签: opencv c++ Mat
个人分类: C++ openCV
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭