简体   繁体   English

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

[英]C++ OpenCV - Creating a 3D matrix and access its elements

I'm trying to use a 3D matrix in OpenCV to store and access data (type float).我正在尝试在 OpenCV 中使用 3D 矩阵来存储和访问数据(浮点型)。 Currently I have 3 methods to create the 3D matrix itself of size 158 x 98 x 32 and initialize it at zero:目前我有 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;

Then I use the .data function to obtain a pointer to the first data element:然后我使用 .data 函数获取指向第一个数据元素的指针:

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

Next, I thought I could set the first element (0,0,0) to 1 by using either of the following two methods:接下来,我想我可以使用以下两种方法之一将第一个元素 (0,0,0) 设置为 1:

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

The at() method works just fine, but I can't seem to get the pointer to work. at() 方法工作得很好,但我似乎无法让指针起作用。 The following:下列:

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

Results in 4.32e-42 at element (0,0,0) while the other command seems to have no effect at all.结果在 4.32e-42 元素 (0,0,0) 而另一个命令似乎根本没有效果。 According to the documentation, input[0] should refer to the value at point (0,0,0), input[1] to (0,0,1) and input[32] to (0,1,0) etc.根据文档, input[0] 应指点 (0,0,0)、input[1] 到 (0,0,1) 和 input[32] 到 (0,1,0) 等处的值.

Also, the M.step is set to 0 and M.cols and M.rows are both -1.此外,M.step 设置为 0,M.cols 和 M.rows 均为 -1。 The number of rows and columns seems right for a multidimensional matrix, but the step should have a value, right?行数和列数对于多维矩阵来说似乎是正确的,但是步骤应该有一个值,对吗?

So, which of the 3 alternatives is best to initialize the 3D matrix and how can I use pointers to access each data elements separately?那么,这 3 种替代方案中的哪一种最适合初始化 3D 矩阵,以及如何使用指针分别访问每个数据元素?

By the way, I'm using the following code to output the contents of the matrix (any other ideas are welcome as well):顺便说一句,我使用以下代码输出矩阵的内容(也欢迎任何其他想法):

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 << " ";
      }
    }
}

Hi, I don't have enough reputation to comment and since there is neither answers nor comments I will write my comment here.嗨,我没有足够的声誉来发表评论,因为既没有答案也没有评论,我将在这里写下我的评论。

It seems like this line is erroneous:这条线似乎是错误的:

Then I use the .data function to obtain a pointer to the first data element:然后我使用 .data 函数获取指向第一个数据元素的指针:

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

since the matrix M type is float therefore you should use由于矩阵M类型是float因此您应该使用

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

I know this is an old post, but I write the answer to whomever comes and passes by.我知道这是一个旧帖子,但我把答案写给来过的人。

Two separate questions: initializing matrices and accessing multidimensional array elements.两个独立的问题:初始化矩阵和访问多维数组元素。


For the first question , on initializing matrices, I would state that all three are functional.对于第一个问题,关于初始化矩阵,我会说这三个都是函数式的。 However, the first is the best one since it is encapsulated in a standard cv constructor.但是,第一个是最好的,因为它封装在标准的 cv 构造函数中。 The second one I would say that is exactly an homologue, since you are creating a matrix which is an object with a data object inside.我要说的第二个完全是同系物,因为您正在创建一个矩阵,该矩阵是一个内部包含数据对象的对象。 Stating M = Scalar(0) is just initializing all values of the data object inside M , as in alternative 1. The third case is like the first, but through a pointer.声明M = Scalar(0)只是初始化M内数据对象的所有值,如替代方案 1。第三种情况与第一种情况类似,但通过指针。 To provide more clarity on the subject, I hope the next paragraph from Learning OpenCV 3: Computer Vision in C++ with the OpenCV Library :为了使该主题更加清晰,我希望学习 OpenCV 3: Computer Vision in C++ with the OpenCV Library 中的下一段:

In addition, some of these [constructors] allow you to initialize the data, either by providing a cv::Scalar (in which case, the entire array will be initialized to that value), or by providing a pointer to an appropriate data block that can be used by the array.此外,其中一些 [构造函数] 允许您通过提供 cv::Scalar(在这种情况下,整个数组将被初始化为该值)或通过提供指向适当数据块的指针来初始化数据可以被数组使用。 In this latter case, you are essentially just creating a header to the existing data (ie, no data is copied; the data member is set to point to the data indicated by the data argument).在后一种情况下,您实际上只是为现有数据创建了一个标头(即,不复制任何数据;数据成员被设置为指向由 data 参数指示的数据)。


Regarding the second question , accessing elements.关于第二个问题,访问元素。 We are dealing with a single valued 3 dimensional matrix.我们正在处理一个单值的 3 维矩阵。 To access the elements individually, there are different options: by location or iteration.要单独访问元素,有不同的选项:按位置或迭代。

Location supports two standard ways: at<>() and ptr<>() . Location 支持两种标准方式: at<>()ptr<>() The second is slightly faster than the first.第二个比第一个略快。 To put in a example, as you already put an example for the first:举个例子,正如你已经为第一个例子举了一个例子:

M.ptr<float>(3) will access the address of the first element in row 3. With this and knowing if values are conitnuous in memory (with isContinuous ), you can run through it by accessing the values, *M.ptr<float>(i) . M.ptr<float>(3)将访问第M.ptr<float>(3)行中第一个元素的地址。有了这个并且知道值在内存中是否连续(使用isContinuous ),您可以通过访问值来运行它, *M.ptr<float>(i)

For example, while refactoring your code:例如,在重构代码时:

    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;

Outputs:输出:

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

The last way to access elements is by the use of iterators, which work as in STL.访问元素的最后一种方法是使用迭代器,它的工作方式与 STL 中的一样。

    cv::MatConstIterator_<float> it = M.begin<float>();

    while ( it != M.end<float>()){
        *it;
    }

But accessing by pointer is faster.但是通过指针访问速度更快。

Also, to access them in group you can check the same book, chapter 4, Section Accessing Array Elements by Block , or the OpenCV docs for methods of m.row , m.col , and others, where m is cv::Mat .此外, m.row组访问它们,您可以查看同一本书,第 4 章,按块访问数组元素的部分,或 OpenCV 文档中的m.rowm.col等方法,其中 m 是cv::Mat

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM