66namespace opencv_test {
77using namespace perf ;
88
9- // useAruco3Detection
10- // CORNER_REFINE_SUBPIX
11- typedef tuple <bool , int > ArucoTestParams;
12- typedef TestBaseWithParam<ArucoTestParams> EstimateAruco;
9+ typedef tuple<bool , int > UseArucoParams;
10+ typedef TestBaseWithParam<UseArucoParams> EstimateAruco;
1311#define ESTIMATE_PARAMS Combine (Values(false , true ), Values(-1 ))
1412
15- PERF_TEST_P(EstimateAruco, ArucoFirst, ESTIMATE_PARAMS )
16- {
17- string imgPath = cvtest::findDataFile (" gboriginal.png" , false );
18- Mat image = imread (imgPath);
19- string dictPath = cvtest::findDataFile (" tutorial_dict.yml" , false );
20- cv::Ptr<cv::aruco::Dictionary> dictionary;
21-
22- FileStorage fs (dictPath, FileStorage::READ);
23- if (!aruco::Dictionary::readDictionary (fs.root (), dictionary)) {
24- cvtest::SkipTestException (" Not founded tutorial_dict.yml" );
25- }
26-
27- Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create ();
28- ArucoTestParams params = GetParam ();
29- detectorParams->useAruco3Detection = get<0 >(params);
30- detectorParams->minMarkerLengthRatioOriginalImg = 0 .01f ;
31-
32- vector<int > ids;
33- vector<vector<Point2f> > corners, rejected;
34- const size_t N = 35ull ;
35- // corners of ArUco markers with indices 0, 1, ..., 34
36- const int goldCorners[N][8 ] = { {252 ,74 , 286 ,81 , 274 ,102 , 238 ,95 }, {295 ,82 , 330 ,89 , 319 ,111 , 282 ,104 },
37- {338 ,91 , 375 ,99 , 365 ,121 , 327 ,113 }, {383 ,100 , 421 ,107 , 412 ,130 , 374 ,123 },
38- {429 ,109 , 468 ,116 , 461 ,139 , 421 ,132 }, {235 ,100 , 270 ,108 , 257 ,130 , 220 ,122 },
39- {279 ,109 , 316 ,117 , 304 ,140 , 266 ,133 }, {324 ,119 , 362 ,126 , 352 ,150 , 313 ,143 },
40- {371 ,128 , 410 ,136 , 400 ,161 , 360 ,152 }, {418 ,139 , 459 ,145 , 451 ,170 , 410 ,163 },
41- {216 ,128 , 253 ,136 , 239 ,161 , 200 ,152 }, {262 ,138 , 300 ,146 , 287 ,172 , 248 ,164 },
42- {309 ,148 , 349 ,156 , 337 ,183 , 296 ,174 }, {358 ,158 , 398 ,167 , 388 ,194 , 346 ,185 },
43- {407 ,169 , 449 ,176 , 440 ,205 , 397 ,196 }, {196 ,158 , 235 ,168 , 218 ,195 , 179 ,185 },
44- {243 ,170 , 283 ,178 , 269 ,206 , 228 ,197 }, {293 ,180 , 334 ,190 , 321 ,218 , 279 ,209 },
45- {343 ,192 , 385 ,200 , 374 ,230 , 330 ,220 }, {395 ,203 , 438 ,211 , 429 ,241 , 384 ,233 },
46- {174 ,192 , 215 ,201 , 197 ,231 , 156 ,221 }, {223 ,204 , 265 ,213 , 249 ,244 , 207 ,234 },
47- {275 ,215 , 317 ,225 , 303 ,257 , 259 ,246 }, {327 ,227 , 371 ,238 , 359 ,270 , 313 ,259 },
48- {381 ,240 , 426 ,249 , 416 ,282 , 369 ,273 }, {151 ,228 , 193 ,238 , 173 ,271 , 130 ,260 },
49- {202 ,241 , 245 ,251 , 228 ,285 , 183 ,274 }, {255 ,254 , 300 ,264 , 284 ,299 , 238 ,288 },
50- {310 ,267 , 355 ,278 , 342 ,314 , 295 ,302 }, {366 ,281 , 413 ,290 , 402 ,327 , 353 ,317 },
51- {125 ,267 , 168 ,278 , 147 ,314 , 102 ,303 }, {178 ,281 , 223 ,293 , 204 ,330 , 157 ,317 },
52- {233 ,296 , 280 ,307 , 263 ,346 , 214 ,333 }, {291 ,310 , 338 ,322 , 323 ,363 , 274 ,349 },
53- {349 ,325 , 399 ,336 , 386 ,378 , 335 ,366 } };
54- map<int , const int *> mapGoldCorners;
55- for (int i = 0 ; i < static_cast <int >(N); i++)
56- mapGoldCorners[i] = goldCorners[i];
57-
58- TEST_CYCLE () aruco::detectMarkers (image, dictionary, corners, ids, detectorParams, rejected);
59- SANITY_CHECK_NOTHING ();
60- }
61-
6213static double deg2rad(double deg) { return deg * CV_PI / 180 .; }
6314
6415class MarkerPainter
6516{
6617private:
67- Size imgMarkerSize;
18+ int imgMarkerSize = 0 ;
6819 Mat cameraMatrix;
6920public:
70- MarkerPainter (const Size& size)
21+ MarkerPainter (const int size)
7122 {
7223 setImgMarkerSize (size);
7324 }
7425
75- void setImgMarkerSize (const Size& size)
26+ void setImgMarkerSize (const int size)
7627 {
7728 imgMarkerSize = size;
78- CV_Assert (imgMarkerSize.width == imgMarkerSize.height );
7929 cameraMatrix = Mat::eye (3 , 3 , CV_64FC1);
80- cameraMatrix.at <double >(0 , 0 ) = cameraMatrix.at <double >(1 , 1 ) = 650 ;
81- cameraMatrix.at <double >(0 , 2 ) = imgMarkerSize. width / 2 ;
82- cameraMatrix.at <double >(1 , 2 ) = imgMarkerSize. height / 2 ;
30+ cameraMatrix.at <double >(0 , 0 ) = cameraMatrix.at <double >(1 , 1 ) = imgMarkerSize ;
31+ cameraMatrix.at <double >(0 , 2 ) = imgMarkerSize / 2.0 ;
32+ cameraMatrix.at <double >(1 , 2 ) = imgMarkerSize / 2.0 ;
8333 }
8434
8535 static std::pair<Mat, Mat> getSyntheticRT (double yaw, double pitch, double distance)
@@ -133,122 +83,209 @@ class MarkerPainter
13383 const Ptr<aruco::DetectorParameters>& parameters,
13484 const Ptr<aruco::Dictionary>& dictionary)
13585 {
136- CV_Assert (imgMarkerSize.width == imgMarkerSize.height );
137- auto marker_corners = std::make_pair (Mat (imgMarkerSize, CV_8UC1, Scalar::all (255 )), vector<Point2f>());
86+ auto marker_corners = std::make_pair (Mat (imgMarkerSize, imgMarkerSize, CV_8UC1, Scalar::all (255 )), vector<Point2f>());
13887 Mat& img = marker_corners.first ;
13988 vector<Point2f>& corners = marker_corners.second ;
14089
14190 // canonical image
142- const int markerSizePixels = static_cast <int >(imgMarkerSize. width /sqrt (2 ));
91+ const int markerSizePixels = static_cast <int >(imgMarkerSize/sqrt (2 . f ));
14392 aruco::drawMarker (dictionary, id, markerSizePixels, img, parameters->markerBorderBits );
14493
14594 // get rvec and tvec for the perspective
146- const double distance = 0.4 ;
95+ const double distance = 0.1 ;
14796 auto rvec_tvec = MarkerPainter::getSyntheticRT (yaw, pitch, distance);
14897 Mat& rvec = rvec_tvec.first ;
14998 Mat& tvec = rvec_tvec.second ;
15099
151100 const float markerLength = 0 .05f ;
152101 vector<Point3f> markerObjPoints;
153- markerObjPoints.push_back (Point3f (-markerLength / 2 .f , +markerLength / 2 .f , 0 ));
154- markerObjPoints.push_back (markerObjPoints[0 ] + Point3f (markerLength, 0 , 0 ));
155- markerObjPoints.push_back (markerObjPoints[0 ] + Point3f (markerLength, -markerLength, 0 ));
156- markerObjPoints.push_back (markerObjPoints[0 ] + Point3f (0 , -markerLength, 0 ));
102+ markerObjPoints.emplace_back (Point3f (-markerLength / 2 .f , +markerLength / 2 .f , 0 ));
103+ markerObjPoints.emplace_back (markerObjPoints[0 ] + Point3f (markerLength, 0 , 0 ));
104+ markerObjPoints.emplace_back (markerObjPoints[0 ] + Point3f (markerLength, -markerLength, 0 ));
105+ markerObjPoints.emplace_back (markerObjPoints[0 ] + Point3f (0 , -markerLength, 0 ));
157106
158107 // project markers and draw them
159108 Mat distCoeffs (5 , 1 , CV_64FC1, Scalar::all (0 ));
160109 projectPoints (markerObjPoints, rvec, tvec, cameraMatrix, distCoeffs, corners);
161110
162111 vector<Point2f> originalCorners;
163- originalCorners.push_back (Point2f (0 .f , 0 .f ));
164- originalCorners.push_back (originalCorners[0 ]+Point2f ((float )markerSizePixels, 0 ));
165- originalCorners.push_back (originalCorners[0 ]+Point2f ((float )markerSizePixels, (float )markerSizePixels));
166- originalCorners.push_back (originalCorners[0 ]+Point2f (0 , (float )markerSizePixels));
112+ originalCorners.emplace_back (Point2f (0 .f , 0 .f ));
113+ originalCorners.emplace_back (originalCorners[0 ]+Point2f ((float )markerSizePixels, 0 ));
114+ originalCorners.emplace_back (originalCorners[0 ]+Point2f ((float )markerSizePixels, (float )markerSizePixels));
115+ originalCorners.emplace_back (originalCorners[0 ]+Point2f (0 , (float )markerSizePixels));
167116
168117 Mat transformation = getPerspectiveTransform (originalCorners, corners);
169118
170- warpPerspective (img, img, transformation, imgMarkerSize, INTER_NEAREST, BORDER_CONSTANT,
119+ warpPerspective (img, img, transformation, Size ( imgMarkerSize, imgMarkerSize) , INTER_NEAREST, BORDER_CONSTANT,
171120 Scalar::all (255 ));
172121 return marker_corners;
173122 }
174123
175124 std::pair<Mat, map<int , vector<Point2f> > > getProjectMarkersTile (const int numMarkers,
176- const Ptr<aruco::DetectorParameters>& params,
177- const Ptr<aruco::Dictionary>& dictionary)
125+ const Ptr<aruco::DetectorParameters>& params,
126+ const Ptr<aruco::Dictionary>& dictionary)
178127 {
179- params->minDistanceToBorder = 1 ;
180- // USE_ARUCO3
181- params->useAruco3Detection = true ;
182- params->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX;
183- params->minSideLengthCanonicalImg = 32 ;
184- params->markerBorderBits = 1 ;
185- // Mat tileImage(imgMarkerSize*numMarkers, CV_8UC1, Scalar::all(255));
186- Mat tileImage (Size (240 , 240 ), CV_8UC1, Scalar::all (255 ));
128+ Mat tileImage (imgMarkerSize*numMarkers, imgMarkerSize*numMarkers, CV_8UC1, Scalar::all (255 ));
187129 map<int , vector<Point2f> > idCorners;
188130
189- int iter = 0 , pitch = 0 , yaw = 70 ;
131+ int iter = 0 , pitch = 0 , yaw = 0 ;
190132 for (int i = 0 ; i < numMarkers; i++)
191133 {
192134 for (int j = 0 ; j < numMarkers; j++)
193135 {
194- int currentId = iter % 250 ;
195- auto marker_corners = getProjectMarker (currentId, deg2rad (yaw), deg2rad (pitch), params, dictionary);
196- Point2f startPoint (i *imgMarkerSize. height , j *imgMarkerSize. width );
197- Mat tmp_roi = tileImage (Rect (startPoint.x , startPoint.y , imgMarkerSize. height , imgMarkerSize. width ));
136+ int currentId = iter;
137+ auto marker_corners = getProjectMarker (currentId, deg2rad (70 + yaw), deg2rad (pitch), params, dictionary);
138+ Point2i startPoint (j *imgMarkerSize, i *imgMarkerSize);
139+ Mat tmp_roi = tileImage (Rect (startPoint.x , startPoint.y , imgMarkerSize, imgMarkerSize));
198140 marker_corners.first .copyTo (tmp_roi);
199141
200142 for (Point2f& point: marker_corners.second )
201- point += startPoint;
143+ point += static_cast <Point2f>( startPoint) ;
202144 idCorners[currentId] = marker_corners.second ;
203- yaw = (yaw + 40 ) % 120 ;
204- currentId++;
145+ auto test = idCorners[currentId];
146+ yaw = (yaw + 10 ) % 51 ; // 70+yaw >= 70 && 70+yaw <= 120
147+ iter++;
205148 }
206- pitch = (pitch + 70 ) % 360 ;
149+ pitch = (pitch + 60 ) % 360 ;
207150 }
208- imwrite (" tile_test" + std::to_string (iter) + " .jpg" , tileImage);
209- return std::make_pair (std::move (tileImage), std::move (idCorners));
151+ return std::make_pair (tileImage, idCorners);
210152 }
211153};
212154
213- TEST (EstimateAruco, ArucoThird)
155+ static inline double getMaxDistance (map<int , vector<Point2f> > &golds, const vector<int >& ids,
156+ const vector<vector<Point2f> >& corners)
157+ {
158+ double distance = 0 .;
159+ for (size_t i = 0 ; i < ids.size (); i++)
160+ {
161+ int id = ids[i];
162+ const auto gold_corners = golds.find (id);
163+ if (gold_corners != golds.end ())
164+ for (int c = 0 ; c < 4 ; c++)
165+ distance = std::max (distance, cv::norm (gold_corners->second [c] - corners[i][c]));
166+ }
167+ return distance;
168+ }
169+
170+ PERF_TEST_P (EstimateAruco, ArucoFirst, ESTIMATE_PARAMS)
214171{
215- // setNumThreads(1 );
172+ UseArucoParams testParams = GetParam ( );
216173 Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary (aruco::DICT_6X6_250);
217- Ptr<aruco::DetectorParameters> params = aruco::DetectorParameters::create ();
218- params->minDistanceToBorder = 1 ;
174+ Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create ();
175+ detectorParams->minDistanceToBorder = 1 ;
176+ detectorParams->markerBorderBits = 1 ;
177+ detectorParams->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX;
219178
179+ const int markerSize = 100 ;
180+ const int numMarkersInRow = 9 ;
220181 // USE_ARUCO3
221- params->useAruco3Detection = true ;
222- params->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX;
223- params->minSideLengthCanonicalImg = 16 ;
224- params->markerBorderBits = 1 ;
225- MarkerPainter painter (Size (2000 , 2000 ));
226- // painter.getProjectMarkersTile(2, params, dictionary);
227- int iter = 0 ;
228- // detect from different positions
229- for (int pitch = 0 ; pitch < 360 ; pitch += 70 ) {
230- for (int yaw = 70 ; yaw <= 120 ; yaw += 40 ) {
231- int currentId = iter % 250 ;
232- auto marker_corners = painter.getProjectMarker (currentId, deg2rad (yaw), deg2rad (pitch), params, dictionary);
233- // rectangle(img, groundTruthCorners[0]/4, 3*groundTruthCorners[0]/4, Scalar(0, 0, 0), 4);
234- // rectangle(img, Point2i(img.rows, img.cols)*0.9, Point2i(img.rows, img.cols)*0.95, Scalar(0, 0, 0), 4);
235- imwrite (" test" + std::to_string (iter) + " .jpg" , marker_corners.first );
236-
237- // detect markers
238- vector<vector<Point2f> > corners;
239- vector<int > ids;
240- aruco::detectMarkers (marker_corners.first , dictionary, corners, ids, params);
241- // check results
242- ASSERT_EQ (1ull , ids.size ());
243- ASSERT_EQ (currentId, ids[0 ]);
244- for (int c = 0 ; c < 4 ; c++)
245- {
246- double dist = cv::norm (marker_corners.second [c] - corners[0 ][c]);
247- EXPECT_LE (dist, 5.0 );
248- }
249- iter++;
250- }
182+ detectorParams->useAruco3Detection = get<0 >(testParams);
183+ if (detectorParams->useAruco3Detection ) {
184+ detectorParams->minSideLengthCanonicalImg = 32 ;
185+ detectorParams->minMarkerLengthRatioOriginalImg = 0 .04f / numMarkersInRow;
186+ }
187+ MarkerPainter painter (markerSize);
188+ auto image_map = painter.getProjectMarkersTile (numMarkersInRow, detectorParams, dictionary);
189+
190+ // detect markers
191+ vector<vector<Point2f> > corners;
192+ vector<int > ids;
193+ TEST_CYCLE_N (10 )
194+ {
195+ aruco::detectMarkers (image_map.first , dictionary, corners, ids, detectorParams);
251196 }
197+ ASSERT_EQ (numMarkersInRow*numMarkersInRow, static_cast <int >(ids.size ()));
198+ double maxDistance = getMaxDistance (image_map.second , ids, corners);
199+ ASSERT_LT (maxDistance, 3 .);
200+ SANITY_CHECK_NOTHING ();
201+ }
202+
203+ PERF_TEST_P (EstimateAruco, ArucoSecond, ESTIMATE_PARAMS)
204+ {
205+ UseArucoParams testParams = GetParam ();
206+ Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary (aruco::DICT_6X6_250);
207+ Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create ();
208+ detectorParams->minDistanceToBorder = 1 ;
209+ detectorParams->markerBorderBits = 1 ;
210+ detectorParams->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX;
211+
212+ // USE_ARUCO3
213+ detectorParams->useAruco3Detection = get<0 >(testParams);
214+ if (detectorParams->useAruco3Detection ) {
215+ detectorParams->minSideLengthCanonicalImg = 64 ;
216+ detectorParams->minMarkerLengthRatioOriginalImg = 0 .f ;
217+ }
218+ const int markerSize = 200 ;
219+ const int numMarkersInRow = 11 ;
220+ MarkerPainter painter (markerSize);
221+ auto image_map = painter.getProjectMarkersTile (numMarkersInRow, detectorParams, dictionary);
222+
223+ // detect markers
224+ vector<vector<Point2f> > corners;
225+ vector<int > ids;
226+ TEST_CYCLE_N (10 )
227+ {
228+ aruco::detectMarkers (image_map.first , dictionary, corners, ids, detectorParams);
229+ }
230+ ASSERT_EQ (numMarkersInRow*numMarkersInRow, static_cast <int >(ids.size ()));
231+ double maxDistance = getMaxDistance (image_map.second , ids, corners);
232+ ASSERT_LT (maxDistance, 3 .);
233+ SANITY_CHECK_NOTHING ();
234+ }
235+
236+ struct Aruco3Params
237+ {
238+ bool useAruco3Detection = false ;
239+ float minMarkerLengthRatioOriginalImg = 0 .f;
240+ int minSideLengthCanonicalImg = 0 ;
241+
242+ Aruco3Params (bool useAruco3, float minMarkerLen, int minSideLen): useAruco3Detection(useAruco3),
243+ minMarkerLengthRatioOriginalImg (minMarkerLen),
244+ minSideLengthCanonicalImg(minSideLen) {}
245+ friend std::ostream& operator <<(std::ostream& os, const Aruco3Params& d)
246+ {
247+ os << d.useAruco3Detection << " " << d.minMarkerLengthRatioOriginalImg << " " << d.minSideLengthCanonicalImg ;
248+ return os;
249+ }
250+ };
251+ typedef tuple<Aruco3Params, pair<int , int >> ArucoTestParams;
252+
253+ typedef TestBaseWithParam<ArucoTestParams> EstimateLargeAruco;
254+ #define ESTIMATE_FHD_PARAMS Combine (Values(Aruco3Params(false , 0 .f, 0 ), Aruco3Params(true , 0 .f, 32 ), \
255+ Aruco3Params(true , 0 .015f , 32 ), Aruco3Params(true , 0 .f, 16 ), Aruco3Params(true , 0 .0069f , 16 )), \
256+ Values(std::make_pair(1440 , 1 ), std::make_pair(480 , 3 ), std::make_pair(144 , 10 )))
257+
258+ PERF_TEST_P(EstimateLargeAruco, ArucoFHD, ESTIMATE_FHD_PARAMS)
259+ {
260+ ArucoTestParams testParams = GetParam ();
261+ Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary (aruco::DICT_6X6_250);
262+ Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create ();
263+ detectorParams->minDistanceToBorder = 1 ;
264+ detectorParams->markerBorderBits = 1 ;
265+ detectorParams->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX;
266+
267+ // USE_ARUCO3
268+ detectorParams->useAruco3Detection = get<0 >(testParams).useAruco3Detection ;
269+ if (detectorParams->useAruco3Detection ) {
270+ detectorParams->minSideLengthCanonicalImg = get<0 >(testParams).minSideLengthCanonicalImg ;
271+ detectorParams->minMarkerLengthRatioOriginalImg = get<0 >(testParams).minMarkerLengthRatioOriginalImg ;
272+ }
273+ const int markerSize = get<1 >(testParams).first ; // 1440 or 480 or 144
274+ const int numMarkersInRow = get<1 >(testParams).second ; // 1 or 3 or 144
275+ MarkerPainter painter (markerSize); // num pixels is 1440x1440 as in FHD 1920x1080
276+ auto image_map = painter.getProjectMarkersTile (numMarkersInRow, detectorParams, dictionary);
277+
278+ // detect markers
279+ vector<vector<Point2f> > corners;
280+ vector<int > ids;
281+ TEST_CYCLE_N (10 )
282+ {
283+ aruco::detectMarkers (image_map.first , dictionary, corners, ids, detectorParams);
284+ }
285+ ASSERT_EQ (numMarkersInRow*numMarkersInRow, static_cast <int >(ids.size ()));
286+ double maxDistance = getMaxDistance (image_map.second , ids, corners);
287+ ASSERT_LT (maxDistance, 3 .);
288+ SANITY_CHECK_NOTHING ();
252289}
253290
254291}
0 commit comments