As part of a larger project, I have some code that does something similar to the following:
cv::Mat some_function()
{
// get some ND-array
Mat mat1 = get_some_mat();
vector<int> dims(mat1.size.p, mat1.size.p + mat1.dims);
// ... shuffle the dimensions stored in "dims" (the total() remains the same)
std::swap(dims[0], dims[1]); // only an example...
// create new mat header for the same data (no copying)
Mat mat2(dims.size(), dims.data(), mat1.type(), mat1.data);
// return matrix with the shuffled dimensions
mat1 = mat2; // <-- is this part safe??
return mat1; //
}
Is the last assignment safe, or will it mess up the ref count and leak memory?
I know the safer option is to just clone the data as in:
// return matrix with the shuffled dimensions
return mat2.clone();
but I'm trying to avoid making unnecessary copies of data...
I'm open to suggestion if there are better ways to reshape the ND-array in-place ...
You can assume the following is true:
CV_Assert(mat1.isContinuous() && mat1.dims > 3 && mat1.channels() == 1);
N.B: I am working with OpenCV 3.0.0
EDIT:
Another thing I tried is to directly overwrite the Mat size
and step
with those from the shuffled array:
// return matrix with the shuffled dimensions
std::copy(mat2.size.p, mat2.size.p + mat2.dims, mat1.size.p);
std::copy(mat2.step.p, mat2.step.p + mat2.dims, mat1.step.p);
return mat1;
But it's not quite right.. Apparently something in the mat1.flags
field needs to be updated as well! Any help?
EDIT2:
I found an overload overload of the Mat::reshape
method for ND-arrays, unfortunately it's not yet fully implemented and currently throws a CV_StsNotImplemented
error!
// return matrix with the shuffled dimensions
return mat1.reshape(mat2.channels(), mat2.dims, mat2.size.p);
See the source code (either 3.0 or the master branch)...
Details
Let me explain a bit more about my use case. In my actual code, I'm trying to convert the last dimension of any 1-channel ND-array into channels of a ND-array with one less dimension but multi-channels, without copying the data. (Again we can assume that the array is continuous and the destination number of channels is less than CV_CN_MAX
).
As an example, If I had the following array:
cv::Mat get_some_mat()
{
int dims[] = {2,3,4,5}; // I'm really working with arbitrary number of dimensions
Mat matnd(4, dims, CV_64F, Scalar::all(0));
return matnd;
}
I want to convert it from 2x3x4x5 array with 1-channel into a 2x3x4 array with 5-channels, i.e:
int dims[] = {2,3,4};
Mat mat(3, dims, CV_64FC(5), Scalar::all(0));
And I want to avoid unneeded copies... The above Mat::reshape
method would have been great, but it's not implemented at the moment!
The regular Mat::reshape
leaves an undesired singleton dimension at the end:
matnd.reshape(5, 0); // returns 2x3x4x1 with 5-channel (note the "1" at the end)
Thanks and sorry for the long post :)