C ++ OpenCV - 创建3D矩阵并访问其元素

时间:2015-05-26 03:28:43

标签: c++ opencv

我正在尝试在OpenCV中使用3D矩阵来存储和访问数据(类型为float)。目前我有3种方法来创建尺寸为158 x 98 x 32的3D矩阵,并将其初始化为零:

int out[3];
out[0] = 98;
out[1] = 158;
out[2] = 32;

//Alternative 1:
cv::Mat M(3, out, CV_32FC1, cv::Scalar(0));

//Alternative 2:
cv::Mat M(3, out, CV_32F);
M = Scalar(0);

//Alternative 3:
Mat *feat = new Mat(3,out,CV_32F,Scalar(0));
Mat M = *feat;

然后我使用.data函数获取指向第一个数据元素的指针:

unsigned char *input = (unsigned char*)(M.data);

接下来,我想我可以使用以下两种方法之一将第一个元素(0,0,0)设置为1:

input[0]= 1;             //Alternative 1
M.at<float>(0,0,0) = 1;  //Alternative 2

at()方法工作正常,但我似乎无法使指针工作。以下内容:

input[0]= 1;
input[1]= 2;

在元素(0,0,0)处产生4.32e-42,而另一个命令似乎完全没有效果。根据文档,input [0]应该引用点(0,0,0),输入[1]到(0,0,1)和输入[32]到(0,1,0)等的值。

此外,M.step设置为0,M.cols和M.rows都是-1。对于多维矩阵来说,行数和列数似乎是正确的,但步骤应该有一个值,对吗?

那么,3个替代方案中哪一个最适合初始化3D矩阵?如何使用指针分别访问每个数据元素?

顺便说一句,我使用以下代码输出矩阵的内容(欢迎任何其他想法):

float M_res = 0;
ofstream res;
res.open("Results.txt"); //Open file

for(int loopz=0;loopz<out[2];loopz++) {
  res << endl << endl << "Dimension " << loopz << endl;
    for(int loopy=0;loopy<out[0];loopy++) {
      res << endl;
      for(int loopx=0;loopx<out[1];loopx++) {
        M_res = M.at<float>(loopy,loopx,loopz)
        res << M_res << " ";
      }
    }
}

2 个答案:

答案 0 :(得分:2)

嗨,我没有足够的声誉发表评论,因为既没有答案也没有评论,我会在这里写评论。

这条线似乎是错误的:

  

然后我使用.data函数获取指向第一个数据元素的指针:

     

unsigned char *input = (unsigned char*)(M.data);

因为矩阵M类型为float,因此您应该使用

  

float *input = (float *)(M.data);

答案 1 :(得分:0)

我知道这是一篇过时的文章,但是我写信给那些来来往往的人。

两个独立的问题:初始化矩阵和访问多维数组元素。


对于第一个问题,在初始化矩阵时,我要声明这三个函数均起作用。但是,第一个是最好的,因为它被封装在标准的cv构造函数中。我要说的第二个恰好是同源物,因为您正在创建一个矩阵,该矩阵是一个内部带有数据对象的对象。声明M = Scalar(0)只是初始化M内的数据对象的所有值,就像在替代方法1中一样。第三种情况与第一种情况类似,但是通过指针。为了使这个主题更加清晰,我希望Learning OpenCV 3: Computer Vision in C++ with the OpenCV Library的下一段:

此外,其中一些[构造函数]允许您通过提供cv :: Scalar(在这种情况下,整个数组将被初始化为该值)或通过提供指向数组可以使用的适当数据块。在后一种情况下,您实际上只是在创建现有数据的标头(即,不复制任何数据;将数据成员设置为指向由data参数指示的数据)。


关于第二个问题,正在访问元素。我们正在处理一个单值3维矩阵。要单独访问元素,有不同的选择:按位置或迭代。

位置支持两种标准方式:at<>()ptr<>()。第二个比第一个稍快。举一个例子,就像您已经为第一个例子举个例子一样:

M.ptr<float>(3)将访问第3行中第一个元素的地址。通过此操作并知道值在内存中是否连续(使用isContinuous),可以通过访问值{ {1}}。

例如,在重构代码时:

*M.ptr<float>(i)

输出:

    int out[3] = {98, 158, 32};

    //Alternative 1:
    cv::Mat M(3, out, CV_32F, cv::Scalar(0));

    cout << "Total size " << M.size <<" and, for example, rows " << M.size[0] << endl;

    cout << "IS the matrix really continuous? " << M.isContinuous() << " Yes" << endl;
    int counter = 0;
    for (int r = 0; r < M.size[0]; r++){
        float* p = M.ptr<float>(r);
        for (int c = 0; c < M.size[1]*M.size[2]; c++){
            *(p + c);
            counter += 1;
        }
    }
    cout << "Number of elements seen " << counter << " matrix number of elements " << 98*158*32 << endl;

访问元素的最后一种方法是使用迭代器,该迭代器与STL一样工作。

Total size 98 x 158 x 32 and, for example, rows 98
IS the matrix really continuous? 1 Yes
Number of elements seen 495488 matrix number of elements 495488

但是通过指针访问速度更快。

另外,要成组访问它们,您可以检查同一本书的第4章“按块访问数组元素”或“ OpenCV文档”中的 cv::MatConstIterator_<float> it = M.begin<float>(); while ( it != M.end<float>()){ *it; } ,{{1 }}等,其中m为m.row