OpeCV中常用基本数据类型的定义分析之二

Mat是OpenCV中最重要的数据结构,不仅能存放各种数据,而且提供各种数据操作接口,几乎包含了所有上层算法或程序对数据操作的需求。

Mat的功能需求:

1. 存放数据及数据的属性,包括大小,维度,数据类型及step
2. 初始化,构造、析构
3. 数据之间的转换
4. 基本元素数据的获取和修改
5. 数据的复制、部分引用、分割、融合

6. 单个或多个矩阵的基本数学操作,要能满足图像操作里对数据块的计算需求
    数学、逻辑、统计及傅里叶变换

Mat的声明在core.hpp中,成员函数实现在mat.hpp中

Mat的数据成员有哪些?
常用属性:
(row, col,size),(step,dim),  data
不常用内部属性:
refcount,可选的custom allocator, 用于POI的datastart, dataend, datalimit

Mat 四大成员函数(构造、析构、复制、赋值)
从简单的开始:
析构函数:
release(); --> refcount为1时, deallocate(); --> fastFree或allocator->deallocate(refcount, datastart, data)
Mat实际类似于一个引用计数智能指针,封装着数据。

复制构造函数
Mat(const Mat& m)
并不是复制数据,而仅仅是增加引用计数,图像数据的改变,会影响其他的引用Mat

赋值函数
release自身,然后增加对参数矩阵的引用计数,dims <= 2 && m.dims <= 2时并不复制数据。引用计数智能指针的方式,Mat就不用太在意内存泄露或野指针的问题。

构造
创建新的Mat头部信息,或者创建新的数据区,或者与其他数据区想关联。
1. 默认构造函数mat()
    所有数据成员都为0
2. 创建新的数据区,包含大小、维度和类型的构造函数
    都会调用create函数,而create函数会根据参数初始化mat头数据,并在setsize中计算出所需要开辟的字节数。
    然后,mat调用custom allocator或fastMalloc分配内存。如下fastMalloc的分配方式:

            size_t total = alignSize(step.p[0]*size.p[0], (int)sizeof(*refcount));
            data = datastart = (uchar*)fastMalloc(total + (int)sizeof(*refcount));
            refcount = (int*)(data + total);
            *refcount = 1;
    create是一种释放旧数据,重新分配内存的方式。

    初始化指定值:
    Mat A33(3, 3, CV 32F, Scalar(5));
    Mat B33(3, 3, CV 32F); B33 = Scalar(5);
    Mat C33 = Mat::ones(3, 3, CV 32F)*5.;

    Mat D33 = Mat::zeros(3, 3, CV 32F) + 5.;


    类似matlab的初始化方式,static成员函数:
    static MatExpr zeros(int rows, int cols, int type);

    static MatExpr ones(int ndims, const int* sz, int type);

    static MatExpr eye(Size size, int type);

  

3. 不创建数据区,引用其他数据
    由CvMat、CvMatND、IplImage转化来,仅仅创建mat头信息,不创建新的数据。或者从数组中转化来
    float B22data[] = {cos(a), -sin(a), sin(a), cos(a)};
    Mat B22 = Mat(2, 2, CV 32F, B22data);
    
    vector<Point> iptvec(10);
    Mat iP(iptvec); // iP { 10x1 CV 32SC2 matrix
    
4. 深度copy数据,创建mat    
    clone()是deep copy 创建mat的函数。
    Mat newC2 = cvarrToMat(oldC0).clone();
    vector<Point2f> ptvec = Mat <Point2f>(iP);

Size、Point、Mat之间的关系
Size是Mat属性的一部分。
而Point也应该是Mat的基本元素的位置信息属性,但point并不是Mat的之间属性。所以访问mat的基本元素,必须应用at,ptr函数或Mat_::iterator,访问某个point的值。而不能直接使用point。如
A33.at<float>(i,j)
Vec3b* prevRow = image.ptr<Vec3b>(y-1);
Mat <Vec3b>::iterator it = image.begin<Vec3b>();

Mat的复制
clone() --> copyTo() --> convertTo()都是深度copy数据,实现方式都是一样的。

Part Access部分引用
reshape(),不创建新的mat,不改变数据区,仅仅改变mat头信息。

其他range的方式获取部分引用,用于ROI是非常好用的,这部分在另外一篇文章中有介绍


Mat其他接口:
1. 转换为CvMat、CvMatND、IplImage、vector<_Tp>、Vec<_Tp, n>、Matx<_Tp, m, n>类型,显示定义类型转换函数,用于隐式类型转换调用。方便类型间转换。
    //! converts header to CvMat; no data is copied
    operator CvMat() const;
    //! converts header to CvMatND; no data is copied
    operator CvMatND() const;
    //! converts header to IplImage; no data is copied
    operator IplImage() const;


    template<typename _Tp, int m, int n> operator Matx<_Tp, m, n>() const;


2. 访问自身属性的接口:
    虽然能直接访问Mat里的数据信息,但提供封装的接口是类型设计的要素之一。const成员函数,inline实现,封装频繁调用且又简要的操作。
    isContinuous()、isSubmatrix()、elemSize()、step1(int i=0)
    常用接口
    type()、depth()、channels()、empty()、total()


3. 更改数据
    resize(), push_back(),pop_back(),reserve()
    扩展时,当Mat大小不足时,重新分配内存。当缩减时,只需修改mat头信息size和dataend就行了。


4. 矩阵运算、线性代数里常用操作:
    转置、求逆、矩阵相乘
    t()、inv()、mul()
    不重载其他操作符运算,effective c++中item23,item24应用非成员函数non-member的方式更合适。

Matop.cpp的操作,基本上都以非成员函数的方式对mat操作,mat的运算
包括数学
逻辑
统计
代数+SVD
傅里叶变换

与Mat关系紧密的几个类MatOp、MatExpr、Mat_.


1. 与Mat相关的重载操作符的函数设计,参数都是输入,返回值是MatExpr类

2. 与Mat相关的显示命名函数设计,参数列表是输入Mat+ 输出Mat+其他输入参数,返回值基本是void类型。而不是返回值是MatExpr的形式

这样设计的好处:

1. 减少开销


--------------------------

在imshow视频或图像时,需要刷新窗口。waitKey()函数不仅仅是等待处理键盘消息,而且是刷新窗口的唯一接口。

http://opencv.willowgarage.com/documentation/python/highgui_user_interface.html#waitkey

你可能感兴趣的:(数据结构,iterator,Access,float,Matrix)