diff --git a/modules/objdetect/include/opencv2/objdetect/aruco_detector.hpp b/modules/objdetect/include/opencv2/objdetect/aruco_detector.hpp index 0d3eb69647..d38fb1753e 100644 --- a/modules/objdetect/include/opencv2/objdetect/aruco_detector.hpp +++ b/modules/objdetect/include/opencv2/objdetect/aruco_detector.hpp @@ -350,12 +350,12 @@ public: InputArray cameraMatrix = noArray(), InputArray distCoeffs = noArray(), OutputArray recoveredIdxs = noArray()) const; - CV_WRAP const Dictionary& getDictionary(size_t index = 0) const; - CV_WRAP void setDictionary(const Dictionary& dictionary, size_t index = 0); + CV_WRAP const Dictionary& getDictionary(int index = 0) const; + CV_WRAP void setDictionary(const Dictionary& dictionary, int index = 0); CV_WRAP const std::vector& getDictionaries() const; CV_WRAP void setDictionaries(const std::vector& dictionaries); CV_WRAP void addDictionary(const Dictionary& dictionary); - CV_WRAP void removeDictionary(size_t index); + CV_WRAP void removeDictionary(int index); CV_WRAP const DetectorParameters& getDetectorParameters() const; CV_WRAP void setDetectorParameters(const DetectorParameters& detectorParameters); diff --git a/modules/objdetect/misc/python/test/test_objdetect_aruco.py b/modules/objdetect/misc/python/test/test_objdetect_aruco.py index 8dd407d32f..a6991f364d 100644 --- a/modules/objdetect/misc/python/test/test_objdetect_aruco.py +++ b/modules/objdetect/misc/python/test/test_objdetect_aruco.py @@ -156,7 +156,7 @@ class aruco_objdetect_test(NewOpenCVTests): gold_corners = np.array([[offset, offset],[marker_size+offset-1.0,offset], [marker_size+offset-1.0,marker_size+offset-1.0], [offset, marker_size+offset-1.0]], dtype=np.float32) - corners, ids, rejected = aruco_detector.detectMarkers(img_marker) + corners, ids, rejected, _ = aruco_detector.detectMarkers(img_marker) self.assertEqual(1, len(ids)) self.assertEqual(id, ids[0]) @@ -171,7 +171,7 @@ class aruco_objdetect_test(NewOpenCVTests): board = cv.aruco.GridBoard(board_size, 5.0, 1.0, aruco_dict) board_image = board.generateImage((board_size[0]*50, board_size[1]*50), marginSize=10) - corners, ids, rejected = aruco_detector.detectMarkers(board_image) + corners, ids, rejected, _ = aruco_detector.detectMarkers(board_image) self.assertEqual(board_size[0]*board_size[1], len(ids)) part_corners, part_ids, part_rejected = corners[:-1], ids[:-1], list(rejected) @@ -203,7 +203,7 @@ class aruco_objdetect_test(NewOpenCVTests): gold_corners = np.array(board.getObjPoints())[:, :, 0:2]*cell_size # detect corners - markerCorners, markerIds, _ = aruco_detector.detectMarkers(image) + markerCorners, markerIds, _, _ = aruco_detector.detectMarkers(image) # test refine rejected = [markerCorners[-1]] @@ -458,5 +458,30 @@ class aruco_objdetect_test(NewOpenCVTests): with self.assertRaises(Exception): img = cv.aruco.drawDetectedDiamonds(img, points2, borderColor=255) + def test_multi_dict_arucodetector(self): + aruco_params = cv.aruco.DetectorParameters() + aruco_dicts = [ + cv.aruco.getPredefinedDictionary(cv.aruco.DICT_4X4_250), + cv.aruco.getPredefinedDictionary(cv.aruco.DICT_5X5_250) + ] + aruco_detector = cv.aruco.ArucoDetector(aruco_dicts, aruco_params) + id = 2 + marker_size = 100 + offset = 10 + img_marker1 = cv.aruco.generateImageMarker(aruco_dicts[0], id, marker_size, aruco_params.markerBorderBits) + img_marker1 = np.pad(img_marker1, pad_width=offset, mode='constant', constant_values=255) + img_marker2 = cv.aruco.generateImageMarker(aruco_dicts[1], id, marker_size, aruco_params.markerBorderBits) + img_marker2 = np.pad(img_marker2, pad_width=offset, mode='constant', constant_values=255) + img_markers = np.concatenate((img_marker1, img_marker2), axis=1) + + corners, ids, rejected, dictIndices = aruco_detector.detectMarkers(img_markers) + + self.assertEqual(2, len(ids)) + self.assertEqual(id, ids[0]) + self.assertEqual(id, ids[1]) + self.assertEqual(2, len(dictIndices)) + self.assertEqual(0, dictIndices[0]) + self.assertEqual(1, dictIndices[1]) + if __name__ == '__main__': NewOpenCVTests.bootstrap() diff --git a/modules/objdetect/src/aruco/aruco_detector.cpp b/modules/objdetect/src/aruco/aruco_detector.cpp index 2c9ddb9160..ab3e325618 100644 --- a/modules/objdetect/src/aruco/aruco_detector.cpp +++ b/modules/objdetect/src/aruco/aruco_detector.cpp @@ -654,7 +654,9 @@ struct ArucoDetector::ArucoDetectorImpl { ArucoDetectorImpl(const std::vector&_dictionaries, const DetectorParameters &_detectorParams, const RefineParameters& _refineParams): dictionaries(_dictionaries), - detectorParams(_detectorParams), refineParams(_refineParams) {} + detectorParams(_detectorParams), refineParams(_refineParams) { + CV_Assert(!dictionaries.empty()); + } /** * @brief Detect square candidates in the input image */ @@ -1034,10 +1036,7 @@ void ArucoDetector::detectMarkers(InputArray _image, OutputArrayOfArrays _corner _copyVector2Output(candidates, _corners); Mat(ids).copyTo(_ids); if (_dictIndices.needed()) { - _dictIndices.create(dictIndices.size(), 1, CV_32SC1); - Mat dictIndicesMat = _dictIndices.getMat(); - Mat m = cv::Mat1i(dictIndices).t(); - m.copyTo(dictIndicesMat); + Mat(dictIndices).copyTo(_dictIndices); } } @@ -1346,12 +1345,12 @@ void ArucoDetector::read(const FileNode &fn) { arucoDetectorImpl->refineParams.readRefineParameters(fn); } -const Dictionary& ArucoDetector::getDictionary(size_t index) const { +const Dictionary& ArucoDetector::getDictionary(int index) const { CV_Assert(index < arucoDetectorImpl->dictionaries.size()); return arucoDetectorImpl->dictionaries[index]; } -void ArucoDetector::setDictionary(const Dictionary& dictionary, size_t index) { +void ArucoDetector::setDictionary(const Dictionary& dictionary, int index) { // special case: if index is 0, we add the dictionary to the list to preserve the old behavior CV_Assert(index == 0 || index < arucoDetectorImpl->dictionaries.size()); if (index == 0 && arucoDetectorImpl->dictionaries.empty()) { @@ -1373,8 +1372,10 @@ void ArucoDetector::addDictionary(const Dictionary& dictionary) { arucoDetectorImpl->dictionaries.push_back(dictionary); } -void ArucoDetector::removeDictionary(size_t index) { +void ArucoDetector::removeDictionary(int index) { CV_Assert(index < arucoDetectorImpl->dictionaries.size()); + // disallow no dictionaries + CV_Assert(arucoDetectorImpl->dictionaries.size() > 1); arucoDetectorImpl->dictionaries.erase(arucoDetectorImpl->dictionaries.begin() + index); } diff --git a/modules/objdetect/test/test_arucodetection.cpp b/modules/objdetect/test/test_arucodetection.cpp index 94e062eb56..511f71e74b 100644 --- a/modules/objdetect/test/test_arucodetection.cpp +++ b/modules/objdetect/test/test_arucodetection.cpp @@ -640,6 +640,7 @@ TEST(CV_ArucoDetectMarkers, regression_contour_24220) TEST(CV_ArucoMultiDict, addRemoveDictionary) { + // using default constructor that pre-configures DICT_4X4_50 aruco::ArucoDetector detector; detector.addDictionary(aruco::getPredefinedDictionary(aruco::DICT_5X5_100)); const auto& dicts = detector.getDictionaries(); @@ -649,11 +650,10 @@ TEST(CV_ArucoMultiDict, addRemoveDictionary) detector.removeDictionary(0); ASSERT_EQ(dicts.size(), 1ul); EXPECT_EQ(dicts[0].markerSize, 5); - detector.removeDictionary(0); - EXPECT_EQ(dicts.size(), 0ul); detector.addDictionary(aruco::getPredefinedDictionary(aruco::DICT_6X6_100)); detector.addDictionary(aruco::getPredefinedDictionary(aruco::DICT_7X7_250)); detector.addDictionary(aruco::getPredefinedDictionary(aruco::DICT_APRILTAG_25h9)); + detector.removeDictionary(0); ASSERT_EQ(dicts.size(), 3ul); EXPECT_EQ(dicts[0].markerSize, 6); EXPECT_EQ(dicts[1].markerSize, 7); @@ -672,27 +672,17 @@ TEST(CV_ArucoMultiDict, addRemoveDictionary) TEST(CV_ArucoMultiDict, noDict) { aruco::ArucoDetector detector; - detector.removeDictionary(0); - - vector > markerCorners; - vector markerIds; - - string img_path = cvtest::findDataFile("aruco/singlemarkersoriginal.jpg"); - Mat image = imread(img_path); - - detector.detectMarkers(image, markerCorners, markerIds); - - EXPECT_EQ(markerIds.size(), 0u); + EXPECT_THROW({ + detector.removeDictionary(0); + }, Exception); } TEST(CV_ArucoMultiDict, multiMarkerDetection) { - aruco::ArucoDetector detector; - detector.removeDictionary(0); - const int markerSidePixels = 100; const int imageSize = markerSidePixels * 2 + 3 * (markerSidePixels / 2); + vector usedDictionaries; // draw synthetic image Mat img = Mat(imageSize, imageSize, CV_8UC1, Scalar::all(255)); @@ -702,18 +692,18 @@ TEST(CV_ArucoMultiDict, multiMarkerDetection) int id = y * 2 + x; int dictId = x * 4 + y * 8; auto dict = aruco::getPredefinedDictionary(dictId); - detector.addDictionary(dict); + usedDictionaries.push_back(dict); aruco::generateImageMarker(dict, id, markerSidePixels, marker); - Point2f firstCorner = - Point2f(markerSidePixels / 2.f + x * (1.5f * markerSidePixels), + Point2f firstCorner(markerSidePixels / 2.f + x * (1.5f * markerSidePixels), markerSidePixels / 2.f + y * (1.5f * markerSidePixels)); - Mat aux = img.colRange((int)firstCorner.x, (int)firstCorner.x + markerSidePixels) - .rowRange((int)firstCorner.y, (int)firstCorner.y + markerSidePixels); + Mat aux = img(Rect((int)firstCorner.x, (int)firstCorner.y, markerSidePixels, markerSidePixels)); marker.copyTo(aux); } } img.convertTo(img, CV_8UC3); + aruco::ArucoDetector detector(usedDictionaries); + vector > markerCorners; vector markerIds; vector > rejectedImgPts;