Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

I prefer

void foo(const cv::Mat &src, cv::Mat &dst) // for cv::Mat only

or

void foo(InputArray src,OutputArray dst)  //for cv::Mat, cv::Mat_, cv::Matx,std:vector

Both are fastest and clear.

In general, cv::Mat has a powerful Automatic Memory Management that allocate/deallocates the memory automatically. This help developers to forget about memory management and many call statements are similar (for opencv mats only!!)

cv::Mat consists of header that hold informations about the Mat and a pointer to a memory block that holds the Mat data (matrix,images,...).

2 (or more cv::Mat) can share same memory for data but each cv::Mat has its own header. Using mat1 = mat2 you will achieve this result. This operation is O(1) and is fast because only header (small) information will be copied.

Function headers:

void foo(cv::Mat src,cv::Mat dst) // create 2 additional headers each call

With above declaration you will create 2 new temporary headers each time you call foo. Again memory data will be shared with calling function. Again is fast O(1) operation.

void foo(cv::Mat &src,cv::Mat &dst) // by ref, use same objects from calling function

With this 2nd declaration you are using param by reference as standard C++. This means that you are using same object instance from calling function. This is fastest method because you won't create new headers.

What's happens to mat1.data when you write mat1 = mat2 ?

mat1.data will be deallocated automatically when is used nowhere else .This is achieved by OpenCV using internal counter.

Below some showcases:

void foo(const cv::Mat &src, cv::Mat &dst)
{
    cvtColor(src,dst,BGR2GRAY); // dst.data will be allocated here IF NEEDED
    cvtColor(src,src,BGR2GRAY); // NOT ALLOWED because src is const
}
void bar(cv::Mat &dst)
{
    cv::circle(dst,... // draw a circle on dst
}

main()
{
    cv::Mat mat1,mat2,mat3,mat4,mat5,mat6;
    cv::imread("some.jpg"); //allocate mem for mat1.data
    foo(mat1,mat2);         //new memory for mat2.data has been allocated

    mat3 = cv::Mat(mat1.size(),mat1.type()); // allocate mem for mat3.data
    foo(mat1,mat3);                          // existing mat3.data has been used (size fits)

    mat4 = cv::Mat(10,10,mat1.type()); // allocate mem (SMALL SIZE) for mat4.data
    foo(mat1,mat4);                    // no one using mat4.data than it has been deallocated.
                                       // New memory has been allocated for mat4.data

    mat5 = cv::Mat(10,10,mat1.type()); // allocate mem (SMALL SIZE) for mat5.data
    mat6 = mat5;                       // mat5 and mat6 share same data
    bar(mat5);                         // draw a circle
                                       // mat6 contains circle too
    foo(mat1,mat5); // existing data is still valid for mat6.
                    // New memory has been allocated for mat5
    // now mat6 is different from mat5. It contains circle same as before.
} //deallocate memory for all mats

this works also if you are using some local var

void foo(const cv::Mat &src, cv::Mat &dst) // for cv::Mat only
{
    cv::Mat local;
    cv::cvtColor(src, local, cv::COLOR_BGR2GRAY);//new memory for local is allocated here 

    // deallocate dst.memory is used nowhere else
    // move dst memory pointer to memory pointed by local
    dst = local;  
} // only the header of local is destroyed because dst is sharing its memory!!

main()
{
    cv::Mat mat1,mat2;
    cv::imread("some.jpg"); // mat1.data will be allocated
    foo(mat1,mat2);         // memory allocated for local has been kept for mat2.data
} //deallocate memory for mat1 and mat2

definitely thanks to OpenCV memory automation also this should work (even if is discouraged and generally not used in opencv)

cv::Mat foo(const cv::Mat &src)
{
    cv::Mat local;
    cv::cvtColor(src, local, cv::COLOR_BGR2GRAY);//new memory for local is allocated here 
    return local;
} // only the header of local is destroyed because some vars is sharing its memory!!

At the end I would to underline some open protection using const. Take look at this function

void mistake(const cv::Mat &src, cv::Mat &dst)
{
    // this is allowed but shouldn't !?!
    dst = src;  

    //THIS DRAWS CIRCLE ON SRC TOO EITHER IF IT'S CONST
    cv::circle(dst, cv::Point(100, 100), 10, 255, 2);
}

I hope this helps.