Earlier when OpenCV was in its childhood stage – it used Iplimage as the structure to capture image data. The problem with this structure was this that one had to manage memory manually with it.
With advent of c++, OpenCV began using Mat as the image structure. It automates memory management tasks and one don’t have to care about releasing memory once we are done with some image.
Mat consists of two data parts: “matrix header” and “pointer to matrix containing pixel values”. In image processing it often creates many copies of images, which are unnecessary and creates heads on memory and processing time. To tackle this issue OpenCV uses a reference counting system. The idea is that each Mat object has its own header, however the matrix may be shared between two instance of them by having their matrix pointers point to the same address. Moreover, the copy operators will only copy the headers and the pointer to the large matrix, not the data itself.
Mat A, C; // creates just the header part A = imread(argv[1], IMREAD_COLOR); // here we'll know the method used (allocate matrix) Mat B(A); // Use the copy constructor C = A; // Assignment operator
All the above objects, in the end, point to the same single data matrix. Their headers are different, however, and making a modification using any of them will affect all the other ones as well. The real interesting part is that you can create headers which refer to only a subsection of the full data. For example, to create a region of interest (ROI) in an image you just create a new header with the new boundaries:
Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries
The copy and assignment operator also don’t create an entirely new matrice, rather they make a new header while pointing to the old data. We may, however, create a new matrice (with both data and header) by using clone function as:
Mat A,B; A = imread(argv[1], IMREAD_COLOR); B=A.clone; /* or may also use "A.copyTo(B)" to copy entire matrix to B *
So, following key points are to be kept in mind:
- Output image allocation for OpenCV functions is automatic (unless specified otherwise).
- You do not need to think about memory management with OpenCVs C++ interface.
- The assignment operator and the copy constructor only copies the header.
- The underlying matrix of an image may be copied using the cv::Mat::clone() and cv::Mat::copyTo() functions.
Despite of using Mat as an image container, it can also be used as a simple matrix. The Mat specific constructors can be found here. Given below is an example of one of the constructor which initializes a matrix:
Mat A(2,2,CV_8UC3,Scalar(0,0,255));
If we were to output above matrix on console, it would appear like:
[0,0,255, 0,0,255
0,0,255, 0,0,255]
For two dimensional and multi-channel images we first define their size (row, column), then we nee d to define the data type to use for storing the elements and the number of channels per matrix point. To do this we have multiple definitions constructed according to the following convention:
CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
For instance, CV_8UC3 means we use unsigned char types that are 8 bit long and each pixel has three of these to form the three channels. This are predefined for up to four channel numbers.
More about Mat can be found on OpenCV documentation here.