我有3D Mat并希望将其转换为Vector。我尝试了opencv的reshape()函数,但它似乎不适用于尺寸大于2的矩阵。如何将3D Mat转换为Vector?我可以通过访问Mat中的所有元素来实现。有没有有效的方法?
答案 0 :(得分:3)
如果我们有以下3D矩阵:
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)
获取包含相同元素的相同类型的向量:
使用重载的STL向量构造函数:
声明并初始化与矩阵相同类型的矢量并复制所有mat元素:
const int* p3 = m3.ptr<int>(0);
std::vector<int> flat0(p3, p3+m3.total());
使用OpenCV重塑:
这与元素最终如何布局的第一个解决方案不同。 最初来自这篇文章:How to divide 3D matrix into bunches of 2D matrix with opencv C++ 如果可能的话,我再次建议将维度定义为渠道。 OpenCV处理的通道比尺寸更好。当然,如果您打算维度超过4个,那么这可能不适用。
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());
}
使用这两种解决方案,所有元素都被考虑在内,除了它们以不同方式排序并因此以不同方式访问。 在第一个中,您可以通过
访问行,列,平面上的元素int index = row * COLS * PLANES + col * PLANES + p
在第二个中,你的元素按平面排序。
选择哪种解决方案可能取决于您如何为矢量编制索引。
答案 1 :(得分:1)
重塑应该有效。以下示例。
//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 );
答案 2 :(得分:1)
另一个变体,但根据真正的问题,从2D数组开始,然后使用Mat构造函数的3d给定已分配数据形式通过给出2d的3d切片视图来影响重塑满足copyTo的矩阵(因为源和参数都具有相同的尺寸3x4x1(由下面的aslicesizes给出)
int 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