c++opencvopencv-mat

Why specifying type when accessing element of a matrix?


In OpenCV, to access the elements of a cv::Mat defined by

cv::Mat mat = cv::Mat::zeros(3, 3, CV_8UC1);

We have to do:

mat.at<uchar>(1,2);

To give the uchar information to mat.at() seems redundant to me. Isn't it already encoded in the header of the matrix? Why do we have to provide it?


Solution

  • cv::Mat supports storing elements of various types.

    Without the template argument for the at methods, the API could not have defined the return type - it cannot be determined at compile time unless you specify it.

    This is why the various at methods are actually method templates, and the template argument dictates their return value.

    For example:

     template<typename _Tp>
    _Tp & cv::Mat::at(int i0, int i1)   // NOTE: The returned type `_Tp &` 
                                        //       is using the template parameter
    

    A second reason is for validation:

    In Debug mode, if you specify the wrong type for at, you will get an assertion failure.
    For example, the source code of the method overload mentioned above (at(int i0, int i1)) contains these 2 assertion which are dependant on the type you specify (_Tp):

    CV_DbgAssert((unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()));
    CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_Tp>::value) == elemSize1());
    

    However keep in mind that in Release mode there is no validation, for performance reasons (inferred from looking at the source code). Using the wrong type would lead to undefined behavior.

    Note:
    If you want to avoid having to specify the type for accessing the elements, you can use cv::Mat_<_Tp> class instead of cv::Mat.
    cv::Mat_<_Tp> is a class template and so the element type is embedded in the class type.
    It has operator() that you can use to access the elements, without specifying the type (because it is taken from the class template argument).
    The potential downside is that the type must be specified at compile time (whereas with cv::Mat it can in principle be determined at runtime).