Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does copying a column of a cv::Mat into a vector fail?

Consider the following code sample. Why does the line marked below trigger a breakpoint/exception at runtime?

int main() {
    Mat m1 = Mat::zeros(10, 1, CV_32FC1);
    Mat m2 = Mat::zeros(10, 3, CV_32FC1);

    vector<float> v1(m1); // works
    Mat m2sub = m2.col(0);
    Mat m2subClone = m2.col(0).clone();
    vector<float> v2(m2subClone); // works
    vector<float> v3(m2sub); // doesn't work
return 0;
}

It seems strange as what's being called is in mat.hpp:

template<typename _Tp> inline Mat::operator std::vector<_Tp>() const {
    std::vector<_Tp> v;
    copyTo(v);
    return v; // <- breaks here
}

and copyTo seems to memcpy the data.

It doesn't give a error message but I see in the stack trace that it breaks at the return statement, and then somewhere deep into an 'operator new' and 'ntdll.dll!RtlpAllocateHeap()'.

Strangely, in my full code, it breaks at a slightly different place: inside copyTo(v) at the memcpy, and throws a 'Access violation writing location 0x0000000001F43D4C.'. My full code looks exactly like the one above, but the matrices are bigger.

Edit: If in above example, I change the matrices to

    Mat m1 = Mat::zeros(5900, 1, CV_32FC1);
    Mat m2 = Mat::zeros(5900, 3, CV_32FC1);

the snippet fails at the same place than my full code, with the access violation error.

I have over 2GB RAM free, and the app is compiled as a 64-bit app, so it shouldn't be an 'out of memory' issue (?)

like image 692
Ela782 Avatar asked Nov 02 '22 12:11

Ela782


1 Answers

I don't understand deeply the OpenCV Mat class, but I guess there is something shared by the columns in the matrices, so memcopying it might not be a good idea. Checking the OpenCV documentation of the Mat::row method (here, the Mat::col method has the same argument about a "shared header"), there is a note indicating that the following is not a good idea:

Mat A;
...
A.row(i) = A.row(j); // will not work

and that you should use the following instead:

A.row(j).copyTo(A.row(i));

So, perhaps in your code you should have used this:

vector<float> v3;
m2sub.copyTo(v3);
like image 196
Luiz Vieira Avatar answered Nov 15 '22 05:11

Luiz Vieira