我有一个3D矩阵,并希望将其转换为向量。我尝试使用opencv的reshape()函数,但似乎不能用于具有超过2维的矩阵。如何将3D矩阵转换为向量?我可以通过访问Mat中的所有元素来完成。是否有更有效的方法?
const int ROWS=2, COLS=3, PLANES=4;
int dims[3] = {ROWS, COLS, PLANES};
cv::Mat m = cv::Mat(3, dims, CV_32SC1); // works with other types (e.g. float, double,...)
这仅适用于连续的mat对象(即m.isContinuous() == true)。
要获得包含相同元素的相同类型的向量:
Using the overloaded STL vector constructor:
Declaring and initializing a vector of same type as the matrix and copying all mat elements:
const int* p3 = m3.ptr<int>(0);
std::vector<int> flat0(p3, p3+m3.total());
Using OpenCV's reshape:
This differs from the first solution in how the elements are laid out in the end. Originally from this post: How to divide 3D matrix into bunches of 2D matrix with opencv C++ I second his suggestion on defining your dimensions as channels if possible. OpenCV handles channels better than dimensions. Of course, that might not be applicable if you intended to have more than 4 dimensions.
cv::Mat m2(ROWS, COLS*PLANES, CV_32SC1, m3.data); // no copying happening here
cv::Mat m2xPlanes = m2.reshape(PLANES); // not sure if this involves a copy
std::vector<Mat> planes;
cv::split(m2xPlanes, planes); // usually used for splitting multi-channel matrices
std::vector<int> flat;
for(size_t i=0; i<planes.size(); i++) {
cv::Mat plane_i = planes[i];
const int* plane_i_ptr = plane_i.ptr<int>(0);
flat.insert(flat.end(), plane_i_ptr, plane_i_ptr+plane_i.total());
}
使用这两种解决方案,所有元素都被考虑在内,只是它们的顺序不同,因此访问方式也不同。 在第一种解决方案中,您可以通过row、col和plane来访问元素。
int index = row * COLS * PLANES + col * PLANES + p
第二个元素按平面排序。
选择哪种解决方案可能取决于您将如何索引向量。
mat.total() = mat.rows * mat.cols
。Total 意味着一个平面的总数。OpenCV 文档没有提到这一点,但您可以通过任何 RGB 图像进行检查。 - sziraquiint nRows = 3;
int nCols = 4;
int nPlanes = 2;
int aslicesizes[3] = {nRows,nCols,1};
int a3DMsizes[3] = {nRows,nCols,nPlanes};
Mat OneM = Mat::ones(nRows,nCols,CV_8UC1);
Mat MAs3DPlane; // will be generic slice that will hava a 3d slice (plane) view of the 2d matrices (OneM, TwoM) before they are copied into OneTwo3D
// Mat OneM = Mat::ones(3,aslicesizes,CV_8UC1);
Mat TwoM = Mat::ones(nRows,nCols,CV_8UC1)+1;
// Mat TwoM = Mat::ones(3,aslicesizes,CV_8UC1)+1;
Mat OneTwo3D = Mat::zeros(3,a3DMsizes,CV_8UC1); // target 3d array
Mat OneTwo3DPlaneM; // slice of the 3d target array
Range OneTwo3DRanges[] = {Range::all(),Range::all(),Range(0,1)}; // first slice range
OneTwo3DPlaneM = OneTwo3D(OneTwo3DRanges); // first target slice of OneTwo3D
MAs3DPlane = Mat::Mat(3,aslicesizes,CV_8UC1,OneM.data); // source slice of OneM.
MAs3DPlane.copyTo(OneTwo3DPlaneM); // copying OneM slice to first slice
OneTwo3DRanges[2] = Range(1,2); // reset ranges appropriate OneTwo3D's second slice (plane)
OneTwo3DPlaneM = OneTwo3D(OneTwo3DRanges); // set to second slice of OneTwo3d
MAs3DPlane = Mat::Mat(3,aslicesizes,CV_8UC1,TwoM.data);// source slice of TwoM.
MAs3DPlane.copyTo(OneTwo3DPlaneM);// copying TwoM slice to first slice
//make sample 3d mat
Mat img = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 9);
//reshape - creates a new mat header of 1 row without copying data
Mat result = img.reshape ( 0, 1 );
// declare vector and alloc size
std::vector<double> outVector;
outVector.reserve( result.cols );
//copy data
result.copyTo( outVector );