Skip to content

Commit 4e44309

Browse files
committed
Test aruco detection with different number of threads
Test ensures that different aruco detection methods do not produce different results based on number of threads. Test was created after observing infinite loop caused by small image and large number of threads when using apriltag corner refinement.
1 parent 66004ec commit 4e44309

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

modules/aruco/test/test_arucodetection.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,4 +717,71 @@ TEST(CV_ArucoDetectMarkers, regression_2492)
717717
}
718718
}
719719

720+
TEST(CV_ArucoDetectMarkers, number_of_threads_does_not_change_results)
721+
{
722+
auto params = cv::aruco::DetectorParameters::create();
723+
// We are not testing against different dictionaries
724+
// As we are interested mostly in small images, smaller
725+
// markers is better -> 4x4
726+
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_50);
727+
728+
// Height of the test image can be chosen quite freely
729+
// We aim to test against small images as in those the
730+
// number of threads has most effect
731+
const auto height_img = 20;
732+
// Just to get nice white boarder
733+
const int shift = height_img > 10 ? 5 : 1;
734+
const auto height_marker = height_img-2*shift;
735+
736+
// Create a test image
737+
cv::Mat img_marker;
738+
cv::aruco::drawMarker(dictionary, 23, height_marker, img_marker, 1);
739+
740+
// Copy to bigger image to get a white border
741+
cv::Mat img(height_img, height_img, CV_8UC1);
742+
img.setTo(255);
743+
img_marker.copyTo(img(cv::Rect(shift, shift, height_marker, height_marker)));
744+
745+
// Remember original number of threads
746+
const auto original_num_th = cv::getNumThreads();
747+
for (const auto refinement_method : {cv::aruco::CORNER_REFINE_NONE, cv::aruco::CORNER_REFINE_SUBPIX,
748+
cv::aruco::CORNER_REFINE_CONTOUR, cv::aruco::CORNER_REFINE_APRILTAG})
749+
{
750+
params->cornerRefinementMethod = refinement_method;
751+
752+
std::vector<std::vector<cv::Point2f>> original_corners;
753+
std::vector<int> original_ids;
754+
for (const auto num_threads : {1, 2, 8, 16, 32, height_img-1, height_img, height_img+1}) {
755+
cv::setNumThreads(num_threads);
756+
757+
std::vector<std::vector<cv::Point2f>> corners;
758+
std::vector<int> ids;
759+
cv::aruco::detectMarkers(img, dictionary, corners, ids, params);
760+
761+
// If we don't find any markers, the test is broken
762+
ASSERT_GE(ids.size(), 1);
763+
764+
if (original_corners.empty()) {
765+
original_corners = std::move(corners);
766+
original_ids = std::move(ids);
767+
} else {
768+
// Make sure we got the same result as the first time
769+
ASSERT_EQ(corners.size(), original_corners.size());
770+
ASSERT_EQ(ids.size(), original_ids.size());
771+
ASSERT_EQ(ids.size(), corners.size());
772+
for (size_t i = 0; i < corners.size(); ++i) {
773+
EXPECT_EQ(ids[i], original_ids[i]);
774+
for (size_t j = 0; j < corners[i].size(); ++j) {
775+
EXPECT_NEAR(corners[i][j].x, original_corners[i][j].x, 0.1f);
776+
EXPECT_NEAR(corners[i][j].y, original_corners[i][j].y, 0.1f);
777+
}
778+
}
779+
}
780+
}
781+
}
782+
783+
// Reset number of threads
784+
cv::setNumThreads(original_num_th);
785+
}
786+
720787
}} // namespace

0 commit comments

Comments
 (0)