Reputation: 55
I want to modify a part of a multi-dimensional matrix using openCV. Basically I want to achieve the same as written in Matlab:
A = zeros(5,5,25);
A(:,:,1) = some_matrix1;
A(:,:,2) = some_matrix2;
I am not sure if I should use a 5x5 matrix with 25 channels or a 5x5x25 matrix with single channel. Here is what I tried:
int dim[3] = { 5,5,25 };
Mat A(3, dim, CV_32FC(1), Scalar::all(0));
A(Range::all(),Range::all(),0) = some_matrix;
But it seems like I can only use Range for two dimensions. Or
Mat A(5, 5, CV_32FC(25), Scalar::all(0));
A(Range::all(),Range::all())[0] = some_matrix;
But in this case, I don't know how to access the channel. Can you please help me with it?
Upvotes: 0
Views: 1376
Reputation: 41765
OpenCV is optimized for 2D matrices. Multidimensional matrix will work, but are rather inefficient and difficult to access.
This example code will show you how to write and read values from an 3D matrix:
#include <opencv2\opencv.hpp>
using namespace cv;
int main()
{
int sizes[] = { 5, 5, 25 };
Mat data(3, sizes, CV_32F);
Mat1f some_matrix(sizes[0], sizes[1]);
randu(some_matrix, 0.f, 100.f); // some random values
// Init data with each plane a constant increasing value
for (int z = 0; z < data.size[2]; ++z)
{
// Set each z-plane to some scalar value
Range ranges[] = { Range::all(), Range::all(), Range(z, z + 1) };
data(ranges) = data.size[2] - z;
}
// Set the n-th z-plane to some_matrix
int z = 0;
for (int r = 0; r < sizes[0]; ++r)
{
for (int c = 0; c < sizes[1]; ++c)
{
data.at<float>(r, c, z) = some_matrix(r, c);
}
}
// Access all slices along z dimension
for (int z = 0; z < data.size[2]; ++z)
{
Range ranges[] = { Range::all(), Range::all(), Range(z, z + 1) };
Mat slice3d(data(ranges).clone()); // with clone slice is continuous, but still 3d
Mat slice(2, &data.size[0], data.type(), slice3d.data);
}
return 0;
}
However, it's far easier and practical to store your 5x5x25 3D matrix as a std::vector<Mat>
, where the vector
has length 25, and each matrix is a 2D 5x5.
See the code:
#include <opencv2\opencv.hpp>
using namespace cv;
int main()
{
int sizes[] = { 5, 5, 25 };
vector<Mat> data(sizes[2]);
// Init data with each plane a constant increasing value
for (int z = 0; z < sizes[2]; ++z)
{
data[z] = Mat(sizes[0], sizes[1], CV_32F, float(sizes[2] - z));
}
Mat1f some_matrix(sizes[0], sizes[1]);
randu(some_matrix, 0.f, 100.f); // some random values
// Set the n-th z-plane to some_matrix
int z = 0;
data[z] = some_matrix;
return 0;
}
Upvotes: 2
Reputation: 394
Here is the piece of code to access the pixel from the channel, you can try it.
int dim[3] = { 5,5,25 };
Mat A(3, dim, CV_32FC1, Scalar::all(0));
for (int m = 0; m < 5; m++)
{
for (int n = 0; n < 5; n++)
{
for (int a = 0; a < 25; a++) // no of channels
{
cout << A.at<cv::Vec3f>(m,n)[a] << endl;
}
}
}
Upvotes: 2