使用at <float>(i,j)访问cv :: Mat的元素.是(x,y)还是(row,col)?

Chr*_*ris 25 c++ opencv

当我们访问cv :: Mat结构的特定元素时,我们可以使用mat.at(i,j)来访问位置i,j的元素.然而,不能立即清楚的是,(i,j)是指矩阵中的x,y坐标,还是第i行和第j列.

Ela*_*782 41

与许多其他库一样,OpenCV 以行主顺序处理矩阵访问.这意味着每个访问都被定义为(row, column).请注意,如果您正在使用图像的x和y坐标(y, x),那么这将成为y您的垂直轴.

大多数矩阵库在这方面都是相同的,访问(row, col)也在例如Matlab或Eigen(C++矩阵库)中.

然而,这些应用程序和库的不同之处在于数据实际存储在内存中的方式.OpenCV以行主要顺序将数据存储在内存中(即行首先出现),而例如Matlab将数据按列主要顺序存储在内存中.但是,如果您只是这些库的用户,并通过访问器访问数据(row, col),您将永远不会真正看到内存存储顺序的这种差异.


小智 26

所以OpenCV处理这个有点奇怪.OpenCV按行主要顺序存储Mat,但是通过matood Mat :: at()对它进行处理会错误地建议列主要顺序.我认为Opencv文档在这种情况下具有误导性.我不得不写这个测试用例来确保自己.

cv::Mat m(3,3,CV_32FC1,0.0f);
m.at<float>(1,0) = 2;
cout << m << endl;
Run Code Online (Sandbox Code Playgroud)

所以使用Mat :: at(y,x)完成寻址:

[0,0,0;
2,0,0;
0,0,0]

但是原始指针访问显示它实际上存储了行主要,例如"2"处于第4位.如果它按列主要顺序存储,则它将处于第2位.

float* mp = &m.at<float>(0);
for(int i=0;i<9;i++)
    cout << mp[i] << " ";
Run Code Online (Sandbox Code Playgroud)

0 0 0 2 0 0 0 0 0

作为旁注:Matlab以列主要顺序存储和寻址矩阵.这可能很烦人,但至少它是一致的.

  • 我相信OpenCV寻址方法遵循矩阵的数学术语,行x cols,所以你有Mat :: at(row,col). (2认同)

Sam*_*Sam 20

与其他库一样,OpenCV可以按行主顺序处理矩阵(和图像).这意味着每个访问都被定义为(row, column).

这个一般规则的显着例外是Matlab和Eigen库.

  • 它可以在内部以列主要顺序存储,但索引以标准数学(行,列)顺序完成,矩阵甚至以行主顺序指定.你有没有和MATLAB一起工作至少1分钟,或者只有维基百科在你身边?请记住,问题是关于索引而不是存储.这些可能会重合,但它们不需要,至少在它们之间还有一个额外的抽象层时. (11认同)
  • 请注意,此答案不正确,因为它包含不正确的误导信息.我已编辑(在同行评审中),但也在下面发布了正确的版本:http://stackoverflow.com/a/42327350/1345959 (5认同)
  • 自从我使用MATLAB以来有点长的时间,但我怀疑它使用[column,row],我会记得这样的数学不一致. (2认同)
  • @ Ela782:当然,你是对的,访问顺序(API)和存储顺序(实现细节)之间存在区别,但我不认为编辑其他人的答案是个好主意,尤其是不要改变他们的意思.发布您自己的答案(您已经完成)并尝试将人们重定向到它. (2认同)
  • @pyon:是的,经过一些思考和评论反馈,我完全同意.谢谢发帖.很难将此视为已接受的答案;-)特别是因为这在Google搜索结果中突然出现. (2认同)

Eti*_*tel 12

从我在文档中看到的,它是at(y, x)(即row, col).


Chr*_*ica 8

由于cv::Mat实际上是一般矩阵,图像只是一种特殊情况,它遵循矩阵索引,因此row(y)位于column(x)之前:

mat.at(i, j) = mat.at(row, col) = mat.at(y, x)
Run Code Online (Sandbox Code Playgroud)