@@ -122,6 +122,117 @@ static inline Mat projectBoard(Ptr<aruco::GridBoard>& board, Mat cameraMatrix, d
122
122
return img;
123
123
}
124
124
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
+
125
236
}
126
237
127
238
}
0 commit comments