This section describes how to traverse the elements in the mat array and the functions related to the elements in the mat, including at and PTR functions, and the matrix memory layout, as well as many c ++-related knowledge points, this is the essence of the entire mat class, and it is doomed to be a gorgeous article!
How do you locate elements in a matrix?
Opencv tutorials provides three methods to traverse the elements in the array: (1) Efficient typical C operation sub[] method; (2) safe C ++ medium iterator method; (3) Dynamic address calculation method. The following describes the main usage and advantages and disadvantages of the three methods.
(1) an unmatched C [] Operator, based on the PTR function family
Int I, j; uchar * P; for (I = 0; I <nrows; ++ I) {P = I. PTR <uchar> (I); // obtain the row pointer for (j = 0; j <ncols; ++ J) {P [J] = table [p [J] ;}}
The most efficient method
(2) c ++ iterator Method
MatIterator_<uchar> it, end; for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it) *it = table[*it]; break;
The safest way
(3) Dynamic Address Calculation Method: It mainly uses the at function family and never needs to be used!
for( int i = 0; i < I.rows; ++i) for( int j = 0; j < I.cols; ++j ) I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
This method is suitable for random access operations, but not for traversal operations. Compared with the most efficient C method, this method generates a row pointer when traversing each image element. Later, we will analyze the differences between methods (1) and methods (3.
Tutotials also provides the time comparison of the above three methods.
Efficient Way |
Iterator |
On-the-fly Ra |
79.4717 milliseconds |
83.7201 milliseconds |
93.7878 milliseconds |
Therefore, when traversing a matrix, the preferred method is method 1.
Why is there so much difference between method 1 and method 3? Next, we will answer this question by analyzing the at function family and PTR function family of mat.
At function family and PTR function family
At function family:
template<typename _Tp> _Tp& at(int i0=0);template<typename _Tp> const _Tp& at(int i0=0) const; …...template<typename _Tp> _Tp& at(Point pt);template<typename _Tp> const _Tp& at(Point pt) const;
PTR function family:
uchar* ptr(int i0=0);const uchar* ptr(int i0=0) const; …...template<typename _Tp, int n> _Tp* ptr(const Vec<int, n>& idx);template<typename _Tp, int n> const _Tp* ptr(const Vec<int, n>& idx) const;
Typical source code of PTR functions:
inline uchar* Mat::ptr(int y){ return data + step.p[0]*y;}
Typical at function source code:
template<typename _Tp> inline _Tp& Mat::at(int i0, int i1){ return ((_Tp*)(data + step.p[0]*i0))[i1];}
For explanations of step. P [0], see opencv learning: mat class detailed analysis + source code analysis (4) msize class and mstep class
Taking the two-dimensional condition as an example, PTR returns a pointer (the starting address of a certain offset in a dimension), as shown in, at is more advanced than PTR. After obtaining the pointer, it uses [] to extract the value. The biggest difference between method 1 and method 3 is described above. In method 1, a head pointer can be applied to the whole row of data, but in Method 4, a row pointer is counted every time an element is traversed, that is to say, the row pointer in method 1 calculates the row times, while the row pointer in method 3 calculates the row × Col times!