Mat::at operator with single index

asked 2016-06-27 14:16:53 -0500

akihiko gravatar image

updated 2016-06-28 00:02:27 -0500

Although the OpenCV documents say:

Mat::at

the variants with a single index (i) can be used to access elements of single-row or single-column 2-dimensional arrays

we can use Mat::at with a single index for usual MxN matrix.

e.g.

cv::Mat m(3,3,CV_32F);
float *p1(m.at<float[3]>(0));
p1[0]=...; p1[1]=...; p1[2]=...;
cv::Vec3f &p2(m.at<cv::Vec3f>(1));
p2[0]=...; p2[1]=...; p2[2]=...;

This way is useful to me. My question is: Is this not a regular way? If OpenCV changes the implementation and restricts the above style, then I would have a trouble.

Edited:

What I want to do is getting a row without a big overhead. I'm seeking a way lighter than m.row(i) (which takes cv::Mat overhead). I am assuming a case where the number of columns is known, like above case (3). In such a case, I think we could get a pointer to an array block (float[3] or cv::Vec3f) at i-th row.

edit retag flag offensive close merge delete

Comments

1

for
cv::Vec3f &p2(m.at<cv::vec3f>(1)); p2[0]=...; p2[1]=...; p2[2]=...;

That's not a regular way. Code check size before get ptr to line. Hence there is an execption in your code because size of vec3f is 3*4 byte and element size your mat is 4 byte

LBerger gravatar imageLBerger ( 2016-06-27 14:46:12 -0500 )edit

Mat::at returns a reference, not a pointer.

did you ,mean Mat::ptr ?

berak gravatar imageberak ( 2016-06-27 22:49:26 -0500 )edit

LBerger, I understand that when we use Mat::at, we have to know the element type and size (above, it's float, 4 byte). So I wrote like m.at<cv::vec3f> since I knew the type and the size.

akihiko gravatar imageakihiko ( 2016-06-27 23:54:53 -0500 )edit

berak, with m.at<float[3]>, I am trying to get a row, which will return float[3]. So I stored it into a pointer float*.

akihiko gravatar imageakihiko ( 2016-06-27 23:56:35 -0500 )edit
1

akhiko, then the short answer is: no, both of your attempts are wrong, and you should not do it this way.

please check with a DEBUG build, your code should throw an exception (which is suppressed in RELEASE)

again, for a Mat m(3,3,CV_32F) you can have float v=m.at<float>(r,c) or float *p = m.ptr<float>(r,c)

anything else is illegal. (and will break on edge cases, like ROI, padding or multi-dim Mats)

berak gravatar imageberak ( 2016-06-28 00:09:01 -0500 )edit

berak, let's make the reason clear. OpenCV does NOT guarantee a continuous memory allocation. When the memory is not allocated continuously, a low-level block access like m.at<float[3]>(i) or m.at<cv::Vec3f>(i) is dangerous and should be avoided as you say. However OpenCV provides Mat::isContinuous to check if the memory allocation is continuous or not. So when the memory allocation is continuous, those block accesses could be acceptable. Are there other points?

akihiko gravatar imageakihiko ( 2016-06-28 10:40:36 -0500 )edit
1

hmm, i fail to see your point there. either you "play by the rules" (and use at() and ptr() correctly) or you could just retrieve the address of the 1st elem with float* p = ptr<float>(0) and use p according to your own scheme (and risk)

in other words, i don't see, why you want to "bend" at() or ptr() beyond scope.

berak gravatar imageberak ( 2016-06-28 10:49:26 -0500 )edit