-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
@@ -1563,7 +1563,7 @@ void refineDetectedMarkers(InputArray _image, const Ptr<Board> &_board, | |||
|
|||
_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.
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 corners
andrejectedCorners
with different dimensions (for similar cases).detectMarkers()
always returnscorners
andrejectedCorners
asvector<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()
createcorners
andrejectedCorners
with different ways.vector<vector<Point2f> >
forcorners
andrejectedCorners
. Also, the current tests only check the number of refined corners (dimension and value are not checked).In this PR
refineDetectedMarkers()
for createOutputArrayOfArrays corners
andrejectedCorners
uses_copyVector2Output()
, just likedetectMarkers()
.opencv_extra=fix_refineDetectedMarkers_shape
Pull 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.