首页 > 代码库 > opencv笔记(一)——Mat的引用计数机制

opencv笔记(一)——Mat的引用计数机制

Mat是Opencv2里面主要的类。Mat的对象常常用来表示一副图像的信息。

Mat的基本操作十分简单,不多说了。下面这段代码能够读七八分明白,应该就算对Mat有大体了解。

 1 /*  For description look into the help() function. */ 2  3 #include "opencv2/core/core.hpp" 4 #include <iostream> 5  6 using namespace std; 7 using namespace cv; 8  9 static void help()10 {11     cout12     << "\n--------------------------------------------------------------------------" << endl13     << "This program shows how to create matrices(cv::Mat) in OpenCV and its serial"14     << " out capabilities"                                                            << endl15     << "That is, cv::Mat M(...); M.create and cout << M. "                            << endl16     << "Shows how output can be formated to OpenCV, python, numpy, csv and C styles." << endl17     << "Usage:"                                                                       << endl18     << "./cvout_sample"                                                               << endl19     << "--------------------------------------------------------------------------"   << endl20     << endl;21 }22 23 int main(int,char**)24 {25     help();26     // create by using the constructor27     Mat M(2,2, CV_8UC3, Scalar(0,0,255));28     cout << "M = " << endl << " " << M << endl << endl;29 30     // create by using the create function()31     M.create(4,4, CV_8UC(2));32     cout << "M = "<< endl << " "  << M << endl << endl;33 34     // create multidimensional matrices35     int sz[3] = {2,2,2};36     Mat L(3,sz, CV_8UC(1), Scalar::all(0));37     // Cannot print via operator <<38 39     // Create using MATLAB style eye, ones or zero matrix40     Mat E = Mat::eye(4, 4, CV_64F);41     cout << "E = " << endl << " " << E << endl << endl;42 43     Mat O = Mat::ones(2, 2, CV_32F);44     cout << "O = " << endl << " " << O << endl << endl;45 46     Mat Z = Mat::zeros(3,3, CV_8UC1);47     cout << "Z = " << endl << " " << Z << endl << endl;48 49     // create a 3x3 double-precision identity matrix50     Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);51     cout << "C = " << endl << " " << C << endl << endl;52 53     Mat RowClone = C.row(1).clone();54     cout << "RowClone = " << endl << " " << RowClone << endl << endl;55 56     // Fill a matrix with random values57     Mat R = Mat(3, 2, CV_8UC3);58     randu(R, Scalar::all(0), Scalar::all(255));59 60     // Demonstrate the output formating options61     cout << "R (default) = " << endl <<        R           << endl << endl;62     cout << "R (python)  = " << endl << format(R,"python") << endl << endl;63     cout << "R (numpy)   = " << endl << format(R,"numpy" ) << endl << endl;64     cout << "R (csv)     = " << endl << format(R,"csv"   ) << endl << endl;65     cout << "R (c)       = " << endl << format(R,"C"     ) << endl << endl;66 67     Point2f P(5, 1);68     cout << "Point (2D) = " << P << endl << endl;69 70     Point3f P3f(2, 6, 7);71     cout << "Point (3D) = " << P3f << endl << endl;72 73 74     vector<float> v;75     v.push_back( (float)CV_PI);   v.push_back(2);    v.push_back(3.01f);76 77     cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;78 79     vector<Point2f> vPoints(20);80     for (size_t i = 0; i < vPoints.size(); ++i)81         vPoints[i] = Point2f((float)(i * 5), (float)(i % 7));82 83     cout << "A vector of 2D Points = " << vPoints << endl << endl;84     return 0;85 }
View Code

 

文档上边说,Mat的数据成员由头部和数据组成。我们打开core.hpp,看看Mat类的声明中的数据成员部分:

 1     /*! includes several bit-fields: 2          - the magic signature 3          - continuity flag 4          - depth 5          - number of channels 6      */ 7     int flags; 8     //! the matrix dimensionality, >= 2 9     int dims;10     //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions11     int rows, cols;12     //! pointer to the data13     uchar* data;14 15     //! pointer to the reference counter;16     // when matrix points to user-allocated data, the pointer is NULL17     int* refcount;

Mat的头部信息:flags,dims,rows,cols,data指针,refcount指针。

Mat的数据部分:显然,意味着data指针指向的空间。

而refcount指针,就是起引用计数的作用。有了引用计数机制,使得我们的Mat能够很好地支持浅拷贝的操作:使用等号操作符给Mat赋值(或者使用拷贝构造的时候),仅拷贝头部信息,如此能够节约许多的空间和时间。而深拷贝的工作,就交给成员方法clone()和copyTo()。、

 

现在假设我们有Mat的对象A,当我们对A进行初始化工作的时候,引用计数为1(对相关的代码有疑问,所以此处不给出。)以下引用官方文档。

  1. If the current array shape and the type match the new ones, return immediately. Otherwise, de-reference the previous data by calling Mat::release().
  2. Initialize the new header.
  3. Allocate the new data of total()*elemSize() bytes.
  4. Allocate the new, associated with the data, reference counter and set it to 1.

令Mat的对象B=A,此时将引用计数增到2。

 1 inline Mat& Mat::operator = (const Mat& m) 2 { 3     if( this != &m ) 4     { 5         if( m.refcount ) 6             CV_XADD(m.refcount, 1); 7         release(); 8         flags = m.flags; 9         if( dims <= 2 && m.dims <= 2 )10         {11             dims = m.dims;12             rows = m.rows;13             cols = m.cols;14             step[0] = m.step[0];15             step[1] = m.step[1];16         }17         else18             copySize(m);19         data =http://www.mamicode.com/ m.data;20         datastart = m.datastart;21         dataend = m.dataend;22         datalimit = m.datalimit;23         refcount = m.refcount;24         allocator = m.allocator;25     }26     return *this;27 }
1 static inline int CV_XADD(int* addr, int delta)2  {3      int tmp = *addr;4      *addr += delta; 5      return tmp;6  }

当B析构的时候,将引用计数减1,当前引用计数为1:

 1 inline Mat::~Mat() 2 { 3     release(); 4     if( step.p != step.buf ) 5         fastFree(step.p); 6 } 7  8 inline void Mat::release() 9 {10     if( refcount && CV_XADD(refcount, -1) == 1 )11         deallocate();12     data = http://www.mamicode.com/datastart = dataend = datalimit = 0;13     size.p[0] = 0;14     refcount = 0;15 }

当A析构的时候,引用计数为0,于是调用deallocate(),数据信息和头部信息一起清空。

 

opencv笔记(一)——Mat的引用计数机制