opencv深入学习(1)--Mat主要成员变量

时间:2022-07-05 00:17:04

opencv深入学习(1)--Mat主要成员变量

分类: opencv深入学习 2057人阅读 评论(8) 收藏 举报

     决心好好研究一下opencv2.x,正好现在论文也写完了,有一些时间,从头深入研究一下!

     先从基础结构cv::Mat开始,首先分析了一下Mat的主要的成员变量:

     下面的是Mat的声明,在core.hpp中:

  1. class CV_EXPORTS Mat  
  2. {  
  3. public:  
  4.     /* 
  5.     * functions 
  6.     */  
  7.     enum { MAGIC_VAL=0x42FF0000, AUTO_STEP=0, CONTINUOUS_FLAG=CV_MAT_CONT_FLAG, SUBMATRIX_FLAG=CV_SUBMAT_FLAG };  
  8.   
  9.     /*! includes several bit-fields: 
  10.          - the magic signature ---//Magic number-wikipedia 
  11.          - continuity flag 
  12.          - depth 
  13.          - number of channels 
  14.      */  
  15.     int flags;  
  16.     //! the matrix dimensionality, >= 2  
  17.     int dims;  
  18.     //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions  
  19.     int rows, cols;  
  20.     //! pointer to the data  
  21.     uchar* data;  
  22.   
  23.     //! pointer to the reference counter;  
  24.     // when matrix points to user-allocated data, the pointer is NULL  
  25.     int* refcount;  
  26.       
  27.     //! helper fields used in locateROI and adjustROI  
  28.     uchar* datastart;  
  29.     uchar* dataend;  
  30.     uchar* datalimit;  
  31.       
  32.     //! custom allocator  
  33.     MatAllocator* allocator;  
  34.       
  35.     struct CV_EXPORTS MSize  
  36.     {  
  37.         MSize(int* _p);  
  38.         Size operator()() const;  
  39.         const int& operator[](int i) const;  
  40.         int& operator[](int i);  
  41.         operator const int*() const;  
  42.         bool operator == (const MSize& sz) const;  
  43.         bool operator != (const MSize& sz) const;  
  44.           
  45.         int* p;  
  46.     };  
  47.       
  48.     struct CV_EXPORTS MStep  
  49.     {  
  50.         MStep();  
  51.         MStep(size_t s);  
  52.         const size_t& operator[](int i) const;  
  53.         size_t& operator[](int i);  
  54.         operator size_t() const;  
  55.         MStep& operator = (size_t s);  
  56.           
  57.         size_t* p;  
  58.         size_t buf[2];  
  59.     protected:  
  60.         MStep& operator = (const MStep&);  
  61.     };  
  62.       
  63.     MSize size;  
  64.     MStep step;  
  65. };  

    

    Mat代表多维密集单通道或者多通道的数值型数组。可以用来存储实数、复数向量或者灰度、彩色图像或者向量场,点云等等,数组M的数据布局由参数M.step[k]【第k维的不常】确定, M的第(i_0,...,i_M.dims-1)个元素的地址可以这样计算获得:

 addr(Mi_0,...,i_M.dims-1)=M.data+M.step[0]*i_0+M.step[1]*i_1+...+M.step[M.dims-1]*i_M.dims-1;
【其中0<=i_k<M.size[k],是第k维的坐标,ex.在rows*cols=300*200的二维图像中,第0维的size,即M.size[0]=300,M.size[1]=200,M.dims=2,这样的话假设取矩阵(20,30) 处的数值的地址,则两个索引就可以确定为:i_0=20,i_1=30,从而也就可以确定M(20,30)的地址】。 
在2维数组的情况下,上面的计算地址的公式变为:
addr(Mi,j)=M.data+M.step[0]*i+M.step[1]*j;
    注意到M.step[i]>=M.step[i+1](事实上M.step[i]>=M.step[i+1]*M.size[i+1]),也就是说,2维的矩阵是按照一行一行存储的,3维矩阵是按照一面一面存储的,所以M.step[M.dims-1]是最小的并且一定等于元素的大小M.elemSize().【M.elemSize()函数返回的是每个元素占的字节空间大小,如果元素类型为CV_16SC3,则返回3*sizeof(short)即6】
   【这里是解释步长step[k]的,步长也可以看作是与第k维的存储单位,在2维的矩阵中,因为存储是按照行的顺序存储的,整个矩阵存储为一个平面,所以第k=0维的步长也就是单位肯定就是一行所占的字节数;如果是3维的话,第0维是按照面为单位来存储的,第1维是按照行为单位来存储的,第2维是按照元素类型为单位存储的,每个元素类型是基本类型(即uchar,float,short等等)与通道数的乘积...;
也就是基本数据类型与通道数组成元素,多个元素组成了行,多行组成了面,多个面组成了3维体,多个3维体 组成4维超体。。。以此类推,如此看来某一维的步长应该等于低一维的步长step*低一维的大小size,那么>=是怎么回事?
   这是字节对齐的原因,为了提高计算速度,对数据存储按照字长进行了对齐,在32位机器中是按照4字节对齐的,就像一个row=100,cols=101大小的单通道uchar图像,如果进行字节对齐则其step[0]=104,而不是101;
##注##--使用cv::Mat时,如果数据是从图像加载的,或者使用构造函数、create等创建分配的数据,是没有字节对齐的,所有的数据都是顺序存储,是continuous的,但是如果
  (1)是使用自己的数据,然后用了Mat的头来访问,而指定的step不是AUTO_STEP的话,那么是否存在字节对齐就不一定了,但是如果是指定了step=AUTO_STEP则没有字节对齐,这个可以从手册中使用外部数据的构造函数对step参数的介绍中知道。
  (2)图像是用IplImage加载的,然后转换为cv::Mat那就存在字节对齐的现象。
下面给出一个关于step,size的测试例子,从其输出中可以验证这些】
  1. Mat load_mat = imread("d:/picture/temp1.bmp");  
  2. cout<<"step[0]="<<load_mat.step[0]<<",size[0]="<<load_mat.size[0]<<",step[1]="<<load_mat.step[1]<<",size[1]="<<load_mat.size[1]<<endl;  
  3. cout<<"rows="<<load_mat.rows<<",cols="<<load_mat.cols<<"elemSize="<<load_mat.elemSize()<<",continuous="<<load_mat.isContinuous()<<endl;  
  4. cout<<"----------------------------------------------------"<<endl;  
  5.   
  6. Mat mem_mat(101,104, CV_8UC3, Scalar::all(255));  
  7. cout<<"step[0]="<<mem_mat.step[0]<<",size[0]="<<mem_mat.size[0]<<",step[1]="<<mem_mat.step[1]<<",size[1]="<<mem_mat.size[1]<<endl;  
  8. cout<<"rows="<<mem_mat.rows<<",cols="<<mem_mat.cols<<"elemSize="<<mem_mat.elemSize()<<",continuous="<<mem_mat.isContinuous()<<endl;  
  9. cout<<"----------------------------------------------------"<<endl;  
  10.   
  11. int sz[]={101,101,101};  
  12. Mat cube(3, sz, CV_32FC3, Scalar::all(0));  
  13. cout<<"step[0]="<<cube.step[0]<<",size[0]="<<cube.size[0]<<",step[1]="<<cube.step[1]<<",size[1]="<<cube.size[1]<<endl;  
  14. cout<<"step[2]="<<cube.step[2]<<",size[2]="<<cube.size[2]<<",step1*size1="<<cube.step[1]*cube.size[1]<<endl;  
  15. cout<<"step2*size2="<<cube.size[2]*cube.step[2]<<",elemSize="<<cube.elemSize()<<",continuous="<<cube.isContinuous()<<endl;  
  16. cout<<"rows="<<cube.rows<<",cols="<<cube.cols<<endl;  
  17. cout<<"----------------------------------------------------"<<endl;  
  18.   
  19. uchar data[1212]={0};  
  20. Mat createdmat(cv::Size(101,12),CV_8UC1, data, 104);  
  21. cout<<"step[0]="<<createdmat.step[0]<<",size[0]="<<createdmat.size[0]<<",step[1]="<<createdmat.step[1]<<",size[1]="<<createdmat.size[1]<<endl;  
  22. cout<<"rows="<<createdmat.rows<<",cols="<<createdmat.cols<<"elemSize="<<createdmat.elemSize()<<",continuous="<<createdmat.isContinuous()<<endl;  
  23. cout<<"----------------------------------------------------"<<endl;  
  24.   
  25. Mat createdmat2(cv::Size(101,12),CV_8UC1, data);  
  26. cout<<"step[0]="<<createdmat2.step[0]<<",size[0]="<<createdmat2.size[0]<<",step[1]="<<createdmat2.step[1]<<",size[1]="<<createdmat2.size[1]<<endl;  
  27. cout<<"rows="<<createdmat2.rows<<",cols="<<createdmat2.cols<<"elemSize="<<createdmat2.elemSize()<<",continuous="<<createdmat2.isContinuous()<<endl;  
  28. cout<<"----------------------------------------------------"<<endl;  
  29.   
  30. IplImage *image = cvLoadImage("d:/picture/temp1.bmp");  
  31. cout<<"widthstep="<<image->widthStep<<",height="<<image->height<<",width="<<image->width<<endl;  
  32. Mat cvted(image);  
  33. cout<<"step[0]="<<cvted.step[0]<<",size[0]="<<cvted.size[0]<<",step[1]="<<cvted.step[1]<<",size[1]="<<cvted.size[1]<<endl;  
  34. cout<<",step1*size1="<<cvted.step[1]*cvted.size[1]<<"elemSize="<<cvted.elemSize()<<",continuous="<<cvted.isContinuous()<<endl;  
  35. cout<<"=========================================================="<<endl;  
  36.   
  37. cout<<"sizeof(loadmat)="<<sizeof(load_mat)<<",sizeof(memmat)="<<sizeof(mem_mat)<<",sizeof(cube)="<<sizeof(cube)<<endl;  
  38. cout<<"sizeof(createdmat)="<<sizeof(createdmat)<<",sizeof(createdmat2)="<<sizeof(createdmat2)<<",sizeof(cvted)="<<sizeof(cvted)<<endl;  
  39.       
  40. cvReleaseImage(&image);  
 
     下面是输出:
   结合上面的分析,可以看出第一种情况是使用imread加载的图像,虽然图像的cols=355,但是其step[0]=1065=355*3 没有字节对齐,从continuous=1也可以看出,下面的第二种情况也是,第三种情况是3维矩阵,也没有进行字节对齐,此时可以看出cols=rows=-1; 第四种情况,使用外部数据,指定了step=104进行字节对齐,可以看出此时step[0]!=step[1]*size[1]了,continuous=0,但是第五种情况下,step采用默认AUTO_STEP时,没有字节对齐,第六种情况,采用IplImage加载与第一种同一幅图像时,可以看出此时使用了字节对齐,其widthstep等于转换为Mat之后的step[0]的值,大于step[1]*size[1],continuous=0,这也验证了上面的分析。
另外几个常用的成员变量:
--------------------------------------------------
   int flags; 标志位,包含几个位域:
 --magic signature 魔法签名或者更确切的说应该是文件的签名,用于区分不同文件格式的标志,是文件的"身份证";在Mat构造函数中可以发现一些端倪, 在使用外部数据构造Mat的构造函数中:flags(MAGIC_VAL + (_type & TYPE_MASK)),在默认构造函数中:flags(0),在imread图像加载时应该也进行了相应的设置【没有确认?】,
 关于该数字签名的一些相关东西,可以参考一下WikiPedia的Magic number词条
 --continuity flag 即是否是连续存储的,标志有没有使用字节对齐
 --depth 元素深度即基本元素类型,uchar,short,float等
 --number of channels 通道数
 --------------------------------------------------
   cols,rows 矩阵的行数,列数【注意,在图像中行数对应的是高度,列数对应的是宽度】,当维数大于2时,均为-1;
   dims 矩阵的维数;
   uchar* data; 存储具体数据的地址指针。
更多 0