@@ -717,4 +717,93 @@ TEST(CV_ArucoDetectMarkers, regression_2492)
717717 }
718718}
719719
720+ TEST (CV_ArucoDetectMarkers, number_of_threads_does_not_change_results)
721+ {
722+ struct NumThreadsSetter {
723+ NumThreadsSetter (const int num_threads)
724+ : original_num_threads_(cv::getNumThreads()) {
725+ cv::setNumThreads (num_threads);
726+ }
727+
728+ ~NumThreadsSetter () {
729+ cv::setNumThreads (original_num_threads_);
730+ }
731+ private:
732+ int original_num_threads_;
733+ };
734+ cv::Ptr<cv::aruco::DetectorParameters> params = cv::aruco::DetectorParameters::create ();
735+ // We are not testing against different dictionaries
736+ // As we are interested mostly in small images, smaller
737+ // markers is better -> 4x4
738+ cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary (cv::aruco::DICT_4X4_50);
739+
740+ // Height of the test image can be chosen quite freely
741+ // We aim to test against small images as in those the
742+ // number of threads has most effect
743+ const int height_img = 20 ;
744+ // Just to get nice white boarder
745+ const int shift = height_img > 10 ? 5 : 1 ;
746+ const int height_marker = height_img-2 *shift;
747+
748+ // Create a test image
749+ cv::Mat img_marker;
750+ cv::aruco::drawMarker (dictionary, 23 , height_marker, img_marker, 1 );
751+
752+ // Copy to bigger image to get a white border
753+ cv::Mat img (height_img, height_img, CV_8UC1);
754+ img.setTo (255 );
755+ img_marker.copyTo (img (cv::Rect (shift, shift, height_marker, height_marker)));
756+
757+ // Number of threads to be tested. OpenCV uses C++03 so no list-initialization
758+ std::vector<int > num_threads_to_test;
759+ num_threads_to_test.push_back (1 );
760+ num_threads_to_test.push_back (2 );
761+ num_threads_to_test.push_back (8 );
762+ num_threads_to_test.push_back (16 );
763+ num_threads_to_test.push_back (32 );
764+ num_threads_to_test.push_back (height_img-1 );
765+ num_threads_to_test.push_back (height_img);
766+ num_threads_to_test.push_back (height_img+1 );
767+
768+ std::vector<cv::aruco::CornerRefineMethod> methods_to_test;
769+ methods_to_test.push_back (cv::aruco::CORNER_REFINE_NONE);
770+ methods_to_test.push_back (cv::aruco::CORNER_REFINE_SUBPIX);
771+ methods_to_test.push_back (cv::aruco::CORNER_REFINE_CONTOUR);
772+ methods_to_test.push_back (cv::aruco::CORNER_REFINE_APRILTAG);
773+
774+ for (size_t i_method = 0 ; i_method < methods_to_test.size (); ++i_method) {
775+ params->cornerRefinementMethod = methods_to_test[i_method];
776+
777+ std::vector<std::vector<cv::Point2f>> original_corners;
778+ std::vector<int > original_ids;
779+ for (size_t i_num_threads = 0 ; i_num_threads < num_threads_to_test.size (); ++i_num_threads) {
780+ NumThreadsSetter thread_num_setter (num_threads_to_test[i_num_threads]);
781+
782+ std::vector<std::vector<cv::Point2f>> corners;
783+ std::vector<int > ids;
784+ cv::aruco::detectMarkers (img, dictionary, corners, ids, params);
785+
786+ // If we don't find any markers, the test is broken
787+ ASSERT_GE (ids.size (), 1 );
788+
789+ if (original_corners.empty ()) {
790+ original_corners = corners;
791+ original_ids = ids;
792+ } else {
793+ // Make sure we got the same result as the first time
794+ ASSERT_EQ (corners.size (), original_corners.size ());
795+ ASSERT_EQ (ids.size (), original_ids.size ());
796+ ASSERT_EQ (ids.size (), corners.size ());
797+ for (size_t i = 0 ; i < corners.size (); ++i) {
798+ EXPECT_EQ (ids[i], original_ids[i]);
799+ for (size_t j = 0 ; j < corners[i].size (); ++j) {
800+ EXPECT_NEAR (corners[i][j].x , original_corners[i][j].x , 0 .1f );
801+ EXPECT_NEAR (corners[i][j].y , original_corners[i][j].y , 0 .1f );
802+ }
803+ }
804+ }
805+ }
806+ }
807+ }
808+
720809}} // namespace
0 commit comments