c++opencv

Does the ptr function in opencv convert values to the desired type?


I have been browsing the opencv source code for unrelated reasons, and could not find the documentation that explains what exactly happens in this line:

const double* const distPtr = distCoeffs.ptr<double>();
double k1 = distPtr[0];
double k2 = distPtr[1];

The variable distCoeffs originates from a getMat() call on a parameter of type InputArray. To my understanding, the InputArray does not guarantee that it contains doubles. It might as well be e.g. a float.

Right as I finished typing this question I realized that in my linked example, there is a conversion to ensure we don't hit this case:

if( !distCoeffs.empty() )
    distCoeffs = Mat_<double>(distCoeffs);

I still would like to know, generally, whether such a safeguard is necessary. I could not find the documentation for cv::Mat::ptr except for a redirect to the docs for isContinuous, which does not explicitly answer my question.

Does the distCoeffs.ptr<double>(); expect the values to be doubles and will otherwise misbehave? Or is this a safe conversion even if the input parameter was actually e.g. an std::vector<float>?


Solution

  • Looking at the source code in their repo (https://github.com/opencv/opencv/blob/4.x/modules/core/include/opencv2/core/mat.inl.hpp):

    template<typename _Tp> inline
    _Tp* Mat::ptr(int y)
    {
        CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) );
        return (_Tp*)(data + step.p[0] * y);
    }
    

    So the assumption is implicit: a C-style cast of the underlying pointer, most likely a reinterpret-cast. Using this pointer to dereference data that is wrongly converted could be UB, depending on the types involved. If not, it would most likely be junk. For example, if the mat holds floats, reinterpret-cast to double would just append the byte data of two floats together and read them as a single double, which would be a garbage value.

    Another potential issue if the template type is wider, is that you may try to dereference data at an index beyond the buffer, thinking that the index exist (remember that the buffer size in bytes doesn't change, but would be divided among larger elements.)

    Edit: added an example and the second issue