Skip to content

Commit 43ff44b

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 43ff44b

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

modules/aruco/test/test_arucodetection.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)