From the doc If the array header is built on top of user-allocated data, you should handle the data by yourself
... in your case the returned cv::Mat.data
points to the memory of matrix
variable that is local and is destroyed on function exit. Consequently the cv::Mat.data becomes a dangling pointer.
see also this about method to declare an image processing function
Some examples:
CASE (1) This works because OpenCV is the owner of the img
memory. The local img
is destroyed but its memory is safely managed by OpenCV because is used by main()
cv::Mat transformToCVMatrix()
{
//img is local and has its own memory
cv::Mat img(rows,cols,CV_64FC1);
...
return img;
}
void main()
{
cv::Mat mat = transformToCVMatrix();
}
CASE (2) this works because the user-allocated data is within the scope of the caller function main()
. The memory is still valid after transformToCVMatrix
returns
const int rows = 2;
const int cols = 3;
double userdata[rows][cols] = {
{ 0, 1, 2 },
{ 3, 4, 5 }
};
cv::Mat transformToCVMatrix()
{
//here img points to an user-allocated data that is GLOBAL
cv::Mat img(rows,cols,CV_64FC1,userdata);
...
return img;
}
void main()
{
cv::Mat mat = transformToCVMatrix();
}
CASE (3) This works with care until you don't explicitly delete userdata. You have to delete[] userdata somewhere. Is common case that userdata is allocated by some other 3rd function or API. Maybe it will dispose the memory for you. In this case you have to be sure that doesn't happen while you are using the Mat otherwise it will become a dangling Mat. But if you manage the memory you can delete it using he Mat.data pointer.
cv::Mat transformToCVMatrix()
{
int rows = 2, cols = 3;
double *userdata = new double[cols*rows];
// fill with test values;
for (int r = 0; r < rows; r++)
for (int c = 0; c < cols; c++)
{
int idx = c + r*cols;
userdata[idx] = double(idx);
}
//we are making a header for user-allocated on the heap.
//This will survive after function returns
cv::Mat img(rows, cols, CV_64FC1, userdata);
return img;
}
void main()
{
cv::Mat mat = transformToCVMatrix();
// use your mat but remember to delete the memory
delete[](double *)mat.data;
}
CASE (4) this (is your case) does not work because OpenCV can't manage the user-allocated data. img.data
points to userdata
that is destroyed on return... than img.data
becomes a dangling pointer
cv::Mat transformToCVMatrix()
{
const int rows = 2;
const int cols = 3;
double userdata[rows][cols] = {
{ 0, 1, 2 },
{ 3, 4, 5 }
};
//we are making a header for user-allocated data is LOCAL. this is not safe
cv::Mat img(rows,cols,CV_64FC1,userdata);
...
return img;
}
In your case the solution is to copy the user data into the cv::Mat to as suggested by @berak using ::clone()
return cv::Mat(rows, cols, CV_64FC1, matrix).clone();
or build a Matx with the flag copyData=true
return Mat(cv::Matx<double, rows, cols>(*matrix), true);
both options will switch your case to CASE (1)