[OpenCV] Talking about the Mat class

1. Introduction to Mat class

The Mat class is a data structure used to save image data or matrix data. It can be said to be a matrix class. In the era of OpenCV 1.0, a structure IplImage in C language is used to store image data. The trouble is that IplImage needs to be in At the end of the program, the memory is manually released, just like the heap space we have malloced now. However, with the update and iteration of the OpenCV version, the appearance of the Mat class solves this problem very conveniently.

The Mat class is used to store matrix-type data information, including data such as vectors, matrices, grayscale or color images. The Mat class is divided into two parts: the matrix head and the matrix pointer pointing to the stored data. The matrix header contains the matrix size, storage method, address and number of references, etc. The size of the matrix header is a constant and does not change with the size of the matrix. In most cases, the size of the matrix header is much smaller than the size of the data in the matrix, so the main overhead in the process of image copying and transmission is to store the matrix data. In order to solve this problem, when copying and transferring the image in OpenCV, only the matrix header and the pointer to the stored data are copied, so when creating the Mat class, the matrix header can be created first and then the data can be assigned.

For example the following program:

cv::Mat m;   // 创建一个名为m的矩阵头
m = cv::imread("C:\test.jpg");  // 向a中赋值图像数据,矩阵指针指向像素数据
cv::Mat tmp = m;  // 复制矩阵头并命名为tmp

2. Constructor

2.1, the default constructor

cv::Mat::Mat()

Default constructor: A function that generates a matrix and is provided by OpenCV (usually Mat::create() and cv::imread() to allocate memory space).
As mentioned above, the Mat class is divided into two parts: the matrix header and the matrix pointer pointing to the pixel data.

Matrix header: including the matrix size, storage method, storage address and number of references of the digital image, etc. The size of the matrix header is a constant and will not change with the size of the image, but the matrix storing the image pixel data will follow the image The size of the matrix changes, usually the amount of data will be large, several orders of magnitude larger than the matrix header. Thus, during image copying and transfer, the main overhead is caused by storing the matrix of image pixels. Therefore, OpenCV uses the reference count, when image copying and passing, instead of copying the whole Mat data, just copy the matrix header and the pointer to the pixel matrix, as in the example above.

The above m and tmp have their own matrix headers, but their matrix pointers point to the same matrix, that is, any one of them changes the matrix data and affects the other. So, multiple Mats share one matrix data, who will release the matrix data in the end?

This is the role of reference counting. When the Mat object is copied, the reference count will be increased by 1, and each time a Mat object is destroyed (sharing the same matrix data), the reference count will be decremented by 1. When the reference count is 0 , the matrix data will be cleaned.

2.2 Commonly used constructors—1

cv::Mat::Mat(int rows, int cols, int type);

The overloaded constructor, which is also one of the commonly used constructors, provides the size of the matrix (rows, the number of rows; cols, the number of columns;) and the storage type (type) while creating the object.
This type indicates the storage type of each element in the matrix in the computer memory, such as CV_8UC3, and the specific meaning is "3-channel 8-bit unsigned number".

Mat src(10,10,CV_32FC3);  // 表示src是一个10*10的矩阵,且矩阵元素以32位float类型存储

Similarly, OpenCV also provides a Size() data structure to construct Mat objects

2.3. Commonly used constructors — 2

cv::Mat::Mat(Size size, int type);

The Size class is equivalent to a pair of data, size::Size(cols,rows), pay special attention to the position of cols and rows, which is the opposite of the constructor in 2.2 .

Mat Src1(3,4,CV_32FC3);
Mat src2(Size(3,4),CV_32FC3);
cout << "src1.rows= " << src1.rows << "src1.cols= " << src2.cols << endl;
cout << "src2.rows: " << src2.rows << "src2.cols: " << src2.cols << endl;
cout << "src1.size="<<src1.size() << endl <<"src2.size=" << src2.size() <<endl;

I have to say that the data structure of the Size class is a bit "anti-human", but the advantage of this is that it facilitates the internal calculations of the computer (for example, many functions of OpenCV calculate Size-related data in this order, specifically why this is the case, I Not too clear, personally understand it as an industry standard);

Also, the resolution we usually refer to is also the type of Size, for example, the screen resolution is 1440*900, where cols=1440, rows=900;

2.4. Commonly used constructors — 3

cv::Mat::Mat(int ndims, const int* sizes, int type, const Scalar& s);

This constructor uses the Scalar parameter, which is used to initialize the element value through the Scalar data class. For example, we want to generate a picture with a white background:

Mat whiteImage(500, 500, CV_8UC3, Scalar(255,255,255));
imshow("demo", whiteImage);  // 显示白色背景图片

Among them, (255,255,255) corresponds to the white value of the RGB color gamut stored in 8-bit unsigned numbers.

2.5. Commonly used constructors — 4

cv::Mat::Mat(const Mat& m);

Refer to the m matrix, note that here is the reference value;

3. Member functions

3.1, at function

The function of the at function is to access matrix elements. According to different usage scenarios, there are multiple overloaded functions to choose from.

For example, to access a two-dimensional matrix, the prototype of the available at function is:

_Tp& cv::Mat::at(int i0,int i1)

Example:

Mat image = imread("test.jpg");
int elem = image.at<int>(0,0);   // 访问test.jpg图像的(0,0)元素

3.2, channels function

The function of the channels function is to return the number of channels of the image, and the prototype is as follows:

int cv::Mat::channels()  const

Example:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    
    
    Mat image = imread("C:/openCV_image/hutao.jpeg");
    int nChannel = image.channels();

    cout << "hutao.jpeg的通道数: " << nChannel << endl;  // 3
    
    return 0;
}

3.3, clone function

The function of the clone function is to copy a matrix to a new matrix.

//原型如下:
Mat cv::Mat::clone()    const

Example:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    
    
    Mat image = imread("C:/openCV_image/WeChatTouXiang.jpg");
    int nChannel = image.channels();

    cout << "WeChatTouXiang.jpg的通道数: " << nChannel << endl;

    Mat cloneImage;
    cloneImage = image.clone();  //复制image矩阵赋值给cloneImage矩阵


    imshow("aaa", image);
    waitKey(0);
    
    return 0;
}

3.4, convertTo function

The function of the convertTo function is to convert the matrix storage type.

// 函数原型:
void cv::Mat::convertTo(OutputArray m,int rtype,double alpha = 1,double beta = 0)   const

The specific calculation formula of the conversion matrix storage type is as follows:

m(x,y)=saturate_cast<rType>(α(∗this)(x,y)+β)

I can’t understand it. For the time being, I’m just making a record and explaining it with the words on the Internet:
m is the input matrix, rtype is the target type, alpha is the scaling factor, and beta is the increase or decrease scalar

3.5, copyTo function

The function of the copyTo function: copy the data data unit from the m matrix, similar to the function of the clone function, the prototype is as follows:

void cv::Mat::copyTo(OutputArray    m)  const

The example is not written, it is the same usage as clone.

3.6, create function

The function of the create function: allocate the storage unit of the matrix, generally used in conjunction with the default constructor, the prototype is as follows:

void cv::Mat::create(int rows,int cols,int type) 

3.7, depth function

The function of the depth function: returns the depth of the image, that is, the storage method of the matrix elements

The prototype is as follows:

int cv::Mat::depth()    const

Example:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    
    
    Mat image = imread("C:/openCV_image/WeChatTouXiang.jpg");
    int nDepth = image.depth();

    cout << "image图像深度:" << nDepth << endl;
    
    return 0;
}

3.8, pop_back function

The function of the pop_back function: pop up the last line of elements, the prototype is as follows:

void pop_back(size_t nelems=1);

This function has not been used yet.

3.9, total function

The function of the total function: returns the total number of elements in the matrix, the prototype is as follows:

size_t total() const;

Examples are as follows:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    
    
    //Mat image = imread("C:/openCV_image/WeChatTouXiang.jpg");
    //int nDepth = image.depth();

    Mat image(30, 40, CV_8UC3);  //创建一个30*40  8位3通道无符号类型的矩阵

    size_t n_total = image.total();

    cout << "image图像元素个数:" << n_total << endl;   //返回1200  30*40 = 1200个像素点
    
    return 0;
}

3.10. Mat::zeros() function

Mat m = Mat::zeros(2, 2, CV_8UC3);

It is equivalent to creating a black image, each channel of each pixel is 0, Scalar(0,0,0);

3.11. Mat::ones() function

Mat m = Mat::ones(2, 2, CV_8UC3); 相当于:Mat m = Mat(2, 2, CV_8UC3, 1);

OpenCV replaces 1 with Scalar(1,0,0) is equivalent to the first channel of each pixel is 1, and the remaining two channels are 0;

3.12, release function

The function of the release function: if necessary, decrement the reference count and release the matrix.

void Mat::release()

This method decrements the reference count associated with the matrix's data. When the reference count decreases to 0, the data of the matrix will be freed, and the data and reference counter pointers are set to NULL. If the matrix header points to an external dataset (see Mat::Mat()), the reference count is NULL, and the method has no effect in this case.

This method can be called manually to force matrix data release. But because this method is called automatically in the destructor, or other methods to change the data pointer, it is usually not necessary to call this function. On platforms that support it, decrementing the reference counter and checking for zero is an atomic operation. Therefore, it is safe to call the same matrix operations asynchronously in different threads.

ps: Of course, there are many ways to operate the matrix, such as finding the inverse matrix (inv function), finding the transpose matrix (t function), and so on. . . .

4. Member variables

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

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

uchar* cv::Mat::data   // 指向矩阵的数据单元的指针 
 
int cv::Mat::dims      // 返回矩阵维度,该维度≥2 

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

OpenCV's methods are far more than these, but I just used some of them. I will record them here for future review.

Guess you like

Origin blog.csdn.net/m0_43458204/article/details/131402953