我正在尝试在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 << " ";
}
}
}
答案 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
。