Skip to content

Commit 4a81ec4

Browse files
author
AleksandrPanov
committed
add CharucoDetector to test
1 parent a28d875 commit 4a81ec4

File tree

6 files changed

+894
-76
lines changed

6 files changed

+894
-76
lines changed

modules/aruco/include/opencv2/aruco/charuco.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include <opencv2/core.hpp>
88
#include <vector>
99
#include <opencv2/aruco.hpp>
10-
#include <opencv2/objdetect/aruco_detector.hpp>
10+
#include <opencv2/objdetect/charuco_detector.hpp>
1111
#include <opencv2/aruco/aruco_calib.hpp>
1212

1313

modules/aruco/test/test_aruco_utils.hpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,117 @@ static inline Mat projectBoard(Ptr<aruco::GridBoard>& board, Mat cameraMatrix, d
122122
return img;
123123
}
124124

125+
int getBoardPose(InputArrayOfArrays corners, InputArray ids, const Ptr<aruco::Board> &board,
126+
InputArray cameraMatrix, InputArray distCoeffs, InputOutputArray rvec,
127+
InputOutputArray tvec, bool useExtrinsicGuess = false) {
128+
CV_Assert(corners.total() == ids.total());
129+
Mat objPoints, imgPoints; // get object and image points for the solvePnP function
130+
board->matchImagePoints(corners, ids, objPoints, imgPoints);
131+
CV_Assert(imgPoints.total() == objPoints.total());
132+
133+
if(objPoints.total() == 0) // 0 of the detected markers in board
134+
return 0;
135+
solvePnP(objPoints, imgPoints, cameraMatrix, distCoeffs, rvec, tvec, useExtrinsicGuess);
136+
137+
// divide by four since all the four corners are concatenated in the array for each marker
138+
return (int)objPoints.total() / 4;
139+
}
140+
141+
/** Check if a set of 3d points are enough for calibration. Z coordinate is ignored. Only axis parallel lines are considered */
142+
static bool _arePointsEnoughForPoseEstimation(const std::vector<Point3f> &points) {
143+
if(points.size() < 4) return false;
144+
145+
std::vector<double> sameXValue; // different x values in points
146+
std::vector<int> sameXCounter; // number of points with the x value in sameXValue
147+
for(unsigned int i = 0; i < points.size(); i++) {
148+
bool found = false;
149+
for(unsigned int j = 0; j < sameXValue.size(); j++) {
150+
if(sameXValue[j] == points[i].x) {
151+
found = true;
152+
sameXCounter[j]++;
153+
}
154+
}
155+
if(!found) {
156+
sameXValue.push_back(points[i].x);
157+
sameXCounter.push_back(1);
158+
}
159+
}
160+
161+
// count how many x values has more than 2 points
162+
int moreThan2 = 0;
163+
for(unsigned int i = 0; i < sameXCounter.size(); i++) {
164+
if(sameXCounter[i] >= 2) moreThan2++;
165+
}
166+
167+
// if we have more than 1 two xvalues with more than 2 points, calibration is ok
168+
if(moreThan2 > 1)
169+
return true;
170+
return false;
171+
}
172+
173+
bool getCharucoBoardPose(InputArray charucoCorners, InputArray charucoIds, const Ptr<aruco::CharucoBoard> &board,
174+
InputArray cameraMatrix, InputArray distCoeffs, InputOutputArray rvec, InputOutputArray tvec,
175+
bool useExtrinsicGuess = false) {
176+
CV_Assert((charucoCorners.getMat().total() == charucoIds.getMat().total()));
177+
if(charucoIds.getMat().total() < 4) return false; // need, at least, 4 corners
178+
179+
std::vector<Point3f> objPoints;
180+
objPoints.reserve(charucoIds.getMat().total());
181+
for(unsigned int i = 0; i < charucoIds.getMat().total(); i++) {
182+
int currId = charucoIds.getMat().at< int >(i);
183+
CV_Assert(currId >= 0 && currId < (int)board->getChessboardCorners().size());
184+
objPoints.push_back(board->getChessboardCorners()[currId]);
185+
}
186+
187+
// points need to be in different lines, check if detected points are enough
188+
if(!_arePointsEnoughForPoseEstimation(objPoints)) return false;
189+
190+
solvePnP(objPoints, charucoCorners, cameraMatrix, distCoeffs, rvec, tvec, useExtrinsicGuess);
191+
return true;
192+
}
193+
194+
195+
/**
196+
* @brief Return object points for the system centered in a middle (by default) or in a top left corner of single
197+
* marker, given the marker length
198+
*/
199+
static Mat _getSingleMarkerObjectPoints(float markerLength, bool use_aruco_ccw_center) {
200+
CV_Assert(markerLength > 0);
201+
Mat objPoints(4, 1, CV_32FC3);
202+
// set coordinate system in the top-left corner of the marker, with Z pointing out
203+
if (use_aruco_ccw_center) {
204+
objPoints.ptr<Vec3f>(0)[0] = Vec3f(-markerLength/2.f, markerLength/2.f, 0);
205+
objPoints.ptr<Vec3f>(0)[1] = Vec3f(markerLength/2.f, markerLength/2.f, 0);
206+
objPoints.ptr<Vec3f>(0)[2] = Vec3f(markerLength/2.f, -markerLength/2.f, 0);
207+
objPoints.ptr<Vec3f>(0)[3] = Vec3f(-markerLength/2.f, -markerLength/2.f, 0);
208+
}
209+
else {
210+
objPoints.ptr<Vec3f>(0)[0] = Vec3f(0.f, 0.f, 0);
211+
objPoints.ptr<Vec3f>(0)[1] = Vec3f(markerLength, 0.f, 0);
212+
objPoints.ptr<Vec3f>(0)[2] = Vec3f(markerLength, markerLength, 0);
213+
objPoints.ptr<Vec3f>(0)[3] = Vec3f(0.f, markerLength, 0);
214+
}
215+
return objPoints;
216+
}
217+
218+
void getMarkersPoses(InputArrayOfArrays corners, float markerLength, InputArray cameraMatrix, InputArray distCoeffs,
219+
OutputArray _rvecs, OutputArray _tvecs, OutputArray objPoints = noArray(),
220+
bool use_aruco_ccw_center = true, SolvePnPMethod solvePnPMethod = SolvePnPMethod::SOLVEPNP_ITERATIVE) {
221+
CV_Assert(markerLength > 0);
222+
Mat markerObjPoints = _getSingleMarkerObjectPoints(markerLength, use_aruco_ccw_center);
223+
int nMarkers = (int)corners.total();
224+
_rvecs.create(nMarkers, 1, CV_64FC3);
225+
_tvecs.create(nMarkers, 1, CV_64FC3);
226+
227+
Mat rvecs = _rvecs.getMat(), tvecs = _tvecs.getMat();
228+
for (int i = 0; i < nMarkers; i++)
229+
solvePnP(markerObjPoints, corners.getMat(i), cameraMatrix, distCoeffs, rvecs.at<Vec3d>(i), tvecs.at<Vec3d>(i),
230+
solvePnPMethod);
231+
232+
if(objPoints.needed())
233+
markerObjPoints.convertTo(objPoints, -1);
234+
}
235+
125236
}
126237

127238
}

0 commit comments

Comments
 (0)