OpenCV 3D Mat to Vector

时间:2014-12-30 08:50:52

标签: opencv vector 3d reshape mat

我有3D Mat并希望将其转换为Vector。我尝试了opencv的reshape()函数,但它似乎不适用于尺寸大于2的矩阵。如何将3D Mat转换为Vector?我可以通过访问Mat中的所有元素来实现。有没有有效的方法?

3 个答案:

答案 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)

获取包含相同元素的相同类型的向量:

  1. 使用重载的STL向量构造函数:

    声明并初始化与矩阵相同类型的矢量并复制所有mat元素:

    const int* p3 = m3.ptr<int>(0);
    std::vector<int> flat0(p3, p3+m3.total());
    
  2. 使用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());
    }
    
  3. 使用这两种解决方案,所有元素都被考虑在内,除了它们以不同方式排序并因此以不同方式访问。 在第一个中,您可以通过

    访问行,列,平面上的元素
    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