【问题标题】:OpenCV 3D Mat to VectorOpenCV 3D 垫到矢量
【发布时间】:2014-12-30 08:50:51
【问题描述】:

我有 3D Mat 并想将其转换为 Vector。我尝试了 opencv 的 reshape() 函数,但它似乎不适用于维度超过 2 的矩阵。如何将 3D Mat 转换为 Vector ?我可以通过访问 Mat 中的所有元素来做到这一点。有什么有效的方法吗?

【问题讨论】:

  • 你能通过访问所有元素发布代码吗?提示您想要的向量的格式和顺序。

标签: opencv vector 3d reshape mat


【解决方案1】:

如果我们有以下 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,...)

这仅适用于连续垫对象(即 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());
    }
    

对于这两种解决方案,所有元素都被考虑在内,只是它们的顺序不同,因此访问方式也不同。 首先,您通过

访问行、列、平面上的元素
int index = row * COLS * PLANES + col * PLANES + p

在第二个中,您的元素按平面排序。

选择哪种解决方案可能取决于您将如何索引向量。

【讨论】:

  • 请注意,mat.total() = mat.rows * mat.cols。 Total 表示总共一个平面。 OpenCV 文档没有提到这一点,但您可以检查任何 RGB 图像。
【解决方案2】:

另一种变体,但根据实际问题,它从 2D 数组开始,然后使用 Mat 构造函数的 3d-given-already-allocated-data 形式通过提供 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

【讨论】:

    【解决方案3】:

    重塑应该可以工作。下面是一个示例。

    //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 );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-05
      • 2018-07-10
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多