-
Notifications
You must be signed in to change notification settings - Fork 5.9k
fixed bad shape of markers (1x4) in several cases and added tests #3105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fixed bad shape of markers (1x4) in several cases and added tests #3105
Conversation
6df7b11 to
9b8394a
Compare
modules/aruco/src/aruco.cpp
Outdated
| _detectedCorners.create((int)finalAcceptedCorners.size(), 1, CV_32FC2); | ||
| for(unsigned int i = 0; i < finalAcceptedCorners.size(); i++) { | ||
| _detectedCorners.create(4, 1, CV_32FC2, i, true); | ||
| _detectedCorners.create(1, 4, CV_32FC2, i, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
Below we have 4,1 again: _rejectedCorners.create(4, 1, ...)
BTW, all usages from aruco module:
$ grep -Rn '.create(4, 1,' ./modules/aruco/
./modules/aruco/src/aruco.cpp:584: out.create(4, 1, CV_32FC2, i);
./modules/aruco/src/aruco.cpp:591: out.create(4, 1, CV_32FC2, i);
./modules/aruco/src/aruco.cpp:598: out.create(4, 1, CV_32FC2, i);
./modules/aruco/src/aruco.cpp:696: _objPoints.create(4, 1, CV_32FC3);
./modules/aruco/src/aruco.cpp:1402: _detectedCorners.create(4, 1, CV_32FC2, i, true);
./modules/aruco/src/aruco.cpp:1420: _rejectedCorners.create(4, 1, CV_32FC2, i, true);
./modules/aruco/src/charuco.cpp:822: _diamondCorners.create(4, 1, CV_32FC2, i, true);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is surprising that the dimension of the matrices out[i], _objPoints[i], _detectedCorners[i], _rejectedCorners[i], _diamondCorners[i] is: (1 (rows) , 4 (cols)). But create with (4 (rows), 1 (cols)) was used.

Flag allowTransposed is ignored in this case (same values for true/false).
Looks like a bug in void _OutputArray::create(int _rows, int _cols, int mtype, int i, bool allowTransposed, int fixedDepthMask) const.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such changes affecting API are considered as a "breaking change".
So proper and complete change should have:
- clear justification
- consistent solution (fix 1 place only and left 6 others is not a good way)
- adapt coding rules to avoid such/similar problems in the future.
surprising
There is allowTransposed parameter on this line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This strange code change is removed. Now refineDetectedMarkers() for create OutputArrayOfArrays corners and rejectedCorners uses _copyVector2Output(), just like detectMarkers().
It's strange that before detectMarkers() and refineDetectedMarkers() created OutputArrayOfArrays corners and rejectedCorners in different ways.
|
|
||
| aruco::detectMarkers(img, dico, corners, ids, detectorParams, rejectedPoints); | ||
| ASSERT_FALSE(corners.empty()); | ||
| EXPECT_EQ(Size(4, 1), corners[0].size()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EXPECT_EQ(Size(4, 1), corners[0].size());
Why do you think that Size(1, 4) is wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Size(1, 4) is not wrong (because it's just four 2d-points) , but corners[i] must be the same size in all cases to avoid undefined behavior.
I also think that InputOutputArrayOfArrays should not be used to pass array of pointers. You suggested replacing the InputOutputArrayOfArrays with a InputOutputArray with ndarray shape [npoints, 4, 2]. I'll try to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me clarify:
In all tests and all examples in OpenCV detectMarkers and refineDetectedMarkers return corners with Size(4, 1) (for corners[i]). It is strange if this condition is violated for no reason.
8f02cad to
211d636
Compare
211d636 to
d72a91f
Compare
|
@alalek, could you recheck PR? I changed the description of the PR. Code changes are made more clear. PR description has been improved. |
| _detectedCorners.clear(); | ||
| _detectedIds.clear(); | ||
|
|
||
| // parse output | ||
| Mat(finalAcceptedIds).copyTo(_detectedIds); | ||
|
|
||
| _detectedCorners.create((int)finalAcceptedCorners.size(), 1, CV_32FC2); | ||
| for(unsigned int i = 0; i < finalAcceptedCorners.size(); i++) { | ||
| _detectedCorners.create(4, 1, CV_32FC2, i, true); | ||
| for(int j = 0; j < 4; j++) { | ||
| _detectedCorners.getMat(i).ptr< Point2f >()[j] = | ||
| finalAcceptedCorners[i].ptr< Point2f >()[j]; | ||
| } | ||
| } | ||
| _copyVector2Output(finalAcceptedCorners, _detectedCorners); | ||
|
|
||
| // recalculate _rejectedCorners based on alreadyIdentified | ||
| vector< Mat > finalRejected; | ||
| vector<vector<Point2f> > finalRejected; | ||
| for(unsigned int i = 0; i < alreadyIdentified.size(); i++) { | ||
| if(!alreadyIdentified[i]) { | ||
| finalRejected.push_back(_rejectedCorners.getMat(i).clone()); | ||
| } | ||
| } | ||
|
|
||
| _rejectedCorners.clear(); | ||
| _rejectedCorners.create((int)finalRejected.size(), 1, CV_32FC2); | ||
| for(unsigned int i = 0; i < finalRejected.size(); i++) { | ||
| _rejectedCorners.create(4, 1, CV_32FC2, i, true); | ||
| for(int j = 0; j < 4; j++) { | ||
| _rejectedCorners.getMat(i).ptr< Point2f >()[j] = | ||
| finalRejected[i].ptr< Point2f >()[j]; | ||
| } | ||
| } | ||
| _copyVector2Output(finalRejected, _rejectedCorners); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, refineDetectedMarkers() uses _copyVector2Output() to copy, just as detectMarkers() does.
alalek
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done 👍
Merge with extra: opencv/opencv_extra#935
Fixes opencv/opencv#14014
Problem:
detectMarkers()andrefineDetectedMarkers()returnsOutputArrayOfArrays cornersandrejectedCornerswith different dimensions (for similar cases).detectMarkers()always returnscornersandrejectedCornersasvector<Mat>, with Mat dimension 4x1.refineDetectedMarkers()works differently, if it finds a new marker. Then the dimension of Mats inside thevector<Mat>changes from 4x1 to 1x4.detectMarkers()andrefineDetectedMarkers()createcornersandrejectedCornerswith different ways.vector<vector<Point2f> >forcornersandrejectedCorners. Also, the current tests only check the number of refined corners (dimension and value are not checked).In this PR
refineDetectedMarkers()for createOutputArrayOfArrays cornersandrejectedCornersuses_copyVector2Output(), just likedetectMarkers().opencv_extra=fix_refineDetectedMarkers_shapePull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
Patch to opencv_extra has the same branch name.