From 0abd5c86f78e3107e526ac1273db9088358bad55 Mon Sep 17 00:00:00 2001 From: s-trinh Date: Wed, 20 May 2026 14:05:51 +0200 Subject: [PATCH] Merge pull request #28824 from s-trinh:update_ArUco_doc Update ArUco doc #28824 See https://github.com/opencv/opencv/pull/28823 Update of the ArUco doc but targeted for OpenCV 4. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake --- apps/interactive-calibration/main.cpp | 2 +- .../parametersController.cpp | 1 + .../DICT_ARUCO_MIP_36h12.json.gz | Bin 0 -> 3090 bytes apps/pattern-tools/test_charuco_board.py | 4 +- .../aruco_detection/aruco_detection.markdown | 2 +- doc/tutorials/tutorials.markdown | 2 +- ...rilTag_corners_comparison_opencv_april.png | Bin 0 -> 16612 bytes .../objdetect/doc/pics/AprilTag_family.png | Bin 0 -> 51952 bytes modules/objdetect/doc/pics/ArUco_family.png | Bin 0 -> 65978 bytes .../objdetect/include/opencv2/objdetect.hpp | 59 ++++++++++++++++++ samples/cpp/aruco_dict_utils.cpp | 8 ++- samples/cpp/calibration.cpp | 3 +- samples/cpp/stereo_calib.cpp | 3 +- .../camera_calibration/camera_calibration.cpp | 1 + .../objectDetection/calibrate_camera.cpp | 3 +- .../calibrate_camera_charuco.cpp | 3 +- .../objectDetection/create_board.cpp | 3 +- .../objectDetection/create_board_charuco.cpp | 3 +- .../objectDetection/create_diamond.cpp | 3 +- .../objectDetection/create_marker.cpp | 5 +- .../objectDetection/detect_board.cpp | 3 +- .../objectDetection/detect_board_charuco.cpp | 3 +- .../objectDetection/detect_diamonds.cpp | 3 +- .../objectDetection/detect_markers.cpp | 2 +- samples/python/aruco_detect_board_charuco.py | 3 +- samples/python/calibrate.py | 3 +- 26 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 apps/pattern-tools/DICT_ARUCO_MIP_36h12.json.gz create mode 100644 modules/objdetect/doc/pics/AprilTag_corners_comparison_opencv_april.png create mode 100644 modules/objdetect/doc/pics/AprilTag_family.png create mode 100644 modules/objdetect/doc/pics/ArUco_family.png diff --git a/apps/interactive-calibration/main.cpp b/apps/interactive-calibration/main.cpp index 889a536a69..ab0fa15ffd 100644 --- a/apps/interactive-calibration/main.cpp +++ b/apps/interactive-calibration/main.cpp @@ -52,7 +52,7 @@ const char* keys = "DICT_4X4_50, DICT_4X4_100, DICT_4X4_250, DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, " "DICT_5X5_1000, DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50, DICT_7X7_100, " "DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL, DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, " - "DICT_APRILTAG_36h10, DICT_APRILTAG_36h11 }" + "DICT_APRILTAG_36h10, DICT_APRILTAG_36h11, DICT_ARUCO_MIP_36h12 }" "{fad | None | name of file with ArUco dictionary}" "{of | cameraParameters.xml | Output file name}" "{ft | true | Auto tuning of calibration flags}" diff --git a/apps/interactive-calibration/parametersController.cpp b/apps/interactive-calibration/parametersController.cpp index 48639a2bdb..66fd769fbb 100644 --- a/apps/interactive-calibration/parametersController.cpp +++ b/apps/interactive-calibration/parametersController.cpp @@ -175,6 +175,7 @@ bool calib::parametersController::loadFromParser(cv::CommandLineParser &parser) else if (arucoDictName == "DICT_APRILTAG_25h9") { mCapParams.charucoDictName = cv::aruco::DICT_APRILTAG_25h9; } else if (arucoDictName == "DICT_APRILTAG_36h10") { mCapParams.charucoDictName = cv::aruco::DICT_APRILTAG_36h10; } else if (arucoDictName == "DICT_APRILTAG_36h11") { mCapParams.charucoDictName = cv::aruco::DICT_APRILTAG_36h11; } + else if (arucoDictName == "DICT_ARUCO_MIP_36h12") { mCapParams.charucoDictName = cv::aruco::DICT_ARUCO_MIP_36h12; } else { std::cout << "incorrect name of aruco dictionary \n"; return false; diff --git a/apps/pattern-tools/DICT_ARUCO_MIP_36h12.json.gz b/apps/pattern-tools/DICT_ARUCO_MIP_36h12.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..60734621e6b05d3022f512cef76d9dcd3a526d40 GIT binary patch literal 3090 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 literal 0 HcmV?d00001 diff --git a/apps/pattern-tools/test_charuco_board.py b/apps/pattern-tools/test_charuco_board.py index e92a38a216..6e52a1e785 100644 --- a/apps/pattern-tools/test_charuco_board.py +++ b/apps/pattern-tools/test_charuco_board.py @@ -20,10 +20,10 @@ class aruco_objdetect_test(NewOpenCVTests): square_size = 100 aruco_type = [cv.aruco.DICT_4X4_1000, cv.aruco.DICT_5X5_1000, cv.aruco.DICT_6X6_1000, cv.aruco.DICT_7X7_1000, cv.aruco.DICT_ARUCO_ORIGINAL, cv.aruco.DICT_APRILTAG_16h5, - cv.aruco.DICT_APRILTAG_25h9, cv.aruco.DICT_APRILTAG_36h10, cv.aruco.DICT_APRILTAG_36h11] + cv.aruco.DICT_APRILTAG_25h9, cv.aruco.DICT_APRILTAG_36h10, cv.aruco.DICT_APRILTAG_36h11, cv.aruco.DICT_ARUCO_MIP_36h12] aruco_type_str = ['DICT_4X4_1000','DICT_5X5_1000', 'DICT_6X6_1000', 'DICT_7X7_1000', 'DICT_ARUCO_ORIGINAL', 'DICT_APRILTAG_16h5', - 'DICT_APRILTAG_25h9', 'DICT_APRILTAG_36h10', 'DICT_APRILTAG_36h11'] + 'DICT_APRILTAG_25h9', 'DICT_APRILTAG_36h10', 'DICT_APRILTAG_36h11', 'DICT_ARUCO_MIP_36h12'] marker_size = 0.8*square_size board_width = cols*square_size board_height = rows*square_size diff --git a/doc/tutorials/objdetect/aruco_detection/aruco_detection.markdown b/doc/tutorials/objdetect/aruco_detection/aruco_detection.markdown index edd43866e7..dd4ae483df 100644 --- a/doc/tutorials/objdetect/aruco_detection/aruco_detection.markdown +++ b/doc/tutorials/objdetect/aruco_detection/aruco_detection.markdown @@ -144,7 +144,7 @@ Error correction techniques are employed when necessary. Consider the following image: -![Image with an assortment of markers](images/singlemarkerssource.jpg) +![Image with an assortment of markers](images/singlemarkerssource.jpg) { width=70% } And a printout of this image in a photo: diff --git a/doc/tutorials/tutorials.markdown b/doc/tutorials/tutorials.markdown index cd83c241af..d6e7cf2168 100644 --- a/doc/tutorials/tutorials.markdown +++ b/doc/tutorials/tutorials.markdown @@ -6,7 +6,7 @@ OpenCV Tutorials {#tutorial_root} - @subpage tutorial_table_of_content_imgproc - image processing functions - @subpage tutorial_table_of_content_app - application utils (GUI, image/video input/output) - @subpage tutorial_table_of_content_calib3d - extract 3D world information from 2D images -- @subpage tutorial_table_of_content_objdetect - INSERT OBJDETECT MODULE INFO +- @subpage tutorial_table_of_content_objdetect - detect ArUco markers and other calibration boards - @subpage tutorial_table_of_content_features2d - feature detectors, descriptors and matching framework - @subpage tutorial_table_of_content_dnn - infer neural networks using built-in _dnn_ module - @subpage tutorial_table_of_content_gapi - graph-based approach to computer vision algorithms building diff --git a/modules/objdetect/doc/pics/AprilTag_corners_comparison_opencv_april.png b/modules/objdetect/doc/pics/AprilTag_corners_comparison_opencv_april.png new file mode 100644 index 0000000000000000000000000000000000000000..3e794fe14859d2a1a36d70edc4544a48bb1007ae GIT binary patch literal 16612 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 H)%*SlN4_Z# literal 0 HcmV?d00001 diff --git a/modules/objdetect/doc/pics/AprilTag_family.png b/modules/objdetect/doc/pics/AprilTag_family.png new file mode 100644 index 0000000000000000000000000000000000000000..cb9127a85af9b0e97fac48799590622dc2750fcb GIT binary patch literal 51952 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 + + @warning In OpenCV, the order of the returned corners locations for the AprilTag family is not aligned with the ArUco one.\n + Note that this order is also different from the convention adopted by the official [AprilTag library](https://github.com/AprilRobotics/apriltag/). + ![](pics/AprilTag_corners_comparison_opencv_april.png) { width=80% } + +
+ + An overview of the supported ArUco markers family is visible in the following image: + ![](pics/ArUco_family.png) { width=80% } + +
+ + An overview of the supported AprilTag markers family is visible in the following image: + ![](pics/AprilTag_family.png) { width=80% } + + @note The generated images (in the above picture) using @ref aruco::generateImageMarker for the AprilTag markers have been + rotated by 180 degree in order to match the official AprilTag images. + When using the @ref aruco::generateImageMarker function, it will output by default a different image from the official AprilTag convention, + see the [AprilRobotics/apriltag-imgs](https://github.com/AprilRobotics/apriltag-imgs) repository. + This is the reason why you see a different corners order between ArUco and AprilTag in the above image. + +
+ + For the ArUco marker family, the recommended family is the DICT_ARUCO_MIP_36h12 one, [see](https://stackoverflow.com/a/51511558). + In general, a smaller marker family (e.g. `4x4` vs `6x6`) should give you a better detection rate with respect to the camera distance, + at the expense of having more probability to have issues with false detection or marker id decoding error. + The number of marker ids in a family is also something to take into account with respect to the application use case and the ability + to correct wrong bits during the marker id decoding process. + + You can download some pregenerated MIP_36h12 ArUco marker images from: + - https://sourceforge.net/projects/aruco/files/ + - or use the `samples/cpp/tutorial_code/objectDetection/create_marker.cpp` sample to generate the marker image for your + desired marker family (which uses the @ref aruco::generateImageMarker function) + + For the AprilTag family, you can find some pregenerated marker images in the + [AprilRobotics/apriltag-imgs](https://github.com/AprilRobotics/apriltag-imgs) repository. + + @note For accurate corners location extraction, a white border (to have a strong gradient between white and black transition) around the marker is important. + This is necessary to precisely extract the marker contour in difficult conditions such as bad illumination, confusing color background, etc. + +
+ + There are multiple parameters which can be tweaked to improve the marker detection rate or to be adapted to your use case (e.g. image resolution). + Please refer to the: + - @ref aruco::DetectorParameters + - "Detector Parameters" section in the @ref tutorial_aruco_detection tutorial or in the @ref tutorial_aruco_faq page + - [ArUco Library Documentation](https://drive.google.com/file/d/1OiavRVYVJ-WH88sQg1LUsh8CuJZUQyrX) for additional information from the ArUco library + + The corner refinement method can be changed according to the @ref aruco::CornerRefineMethod to improve the corners location accuracy + at the expense of more computation time. + +
+ + To estimate the marker pose with respect to the camera frame, we recommend you to look at the following sources of information: + - @ref tutorial_aruco_detection for a tutorial about ArUco markers detection + - @ref calib3d for some theoretical background about the pinhole camera model and the @ref calib3d_solvePnP page + - @ref solvePnP, @ref solvePnPGeneric, @ref solveP3P for the relevant pose estimation methods @} @} diff --git a/samples/cpp/aruco_dict_utils.cpp b/samples/cpp/aruco_dict_utils.cpp index 20fecd82e9..e9a40e8d50 100644 --- a/samples/cpp/aruco_dict_utils.cpp +++ b/samples/cpp/aruco_dict_utils.cpp @@ -260,7 +260,7 @@ const char* keys = "DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50," "DICT_7X7_100, DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL," "DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10," - "DICT_APRILTAG_36h11}" + "DICT_APRILTAG_36h11, DICT_ARUCO_MIP_36h12}" "{nMarkers | | Number of markers in the dictionary }" "{markerSize | | Marker size }" "{cd | | Input file with custom dictionary }"; @@ -309,6 +309,7 @@ int main(int argc, char *argv[]) else if (arucoDictName == "DICT_APRILTAG_25h9") { arucoDict = cv::aruco::DICT_APRILTAG_25h9; } else if (arucoDictName == "DICT_APRILTAG_36h10") { arucoDict = cv::aruco::DICT_APRILTAG_36h10; } else if (arucoDictName == "DICT_APRILTAG_36h11") { arucoDict = cv::aruco::DICT_APRILTAG_36h11; } + else if (arucoDictName == "DICT_ARUCO_MIP_36h12") { arucoDict = cv::aruco::DICT_ARUCO_MIP_36h12; } else { cout << "incorrect name of aruco dictionary \n"; return 1; @@ -328,13 +329,14 @@ int main(int argc, char *argv[]) cerr << "Dictionary not specified" << endl; return 0; } + if (!outputFile.empty() && nMarkers > 0 && markerSize > 0) { FileStorage fs(outputFile, FileStorage::WRITE); if (checkFlippedMarkers) - dictionary = generateCustomAsymmetricDictionary(nMarkers, markerSize, aruco::Dictionary(), 0); + dictionary = generateCustomAsymmetricDictionary(nMarkers, markerSize, dictionary, 0); else - dictionary = aruco::extendDictionary(nMarkers, markerSize, aruco::Dictionary(), 0); + dictionary = aruco::extendDictionary(nMarkers, markerSize, dictionary, 0); dictionary.writeDictionary(fs); } diff --git a/samples/cpp/calibration.cpp b/samples/cpp/calibration.cpp index 99cb1a547b..3294a93d76 100644 --- a/samples/cpp/calibration.cpp +++ b/samples/cpp/calibration.cpp @@ -66,7 +66,7 @@ static void help(char** argv) "DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, DICT_5X5_1000, " "DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50, " "DICT_7X7_100, DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL, " - "DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10, DICT_APRILTAG_36h11\n" + "DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10, DICT_APRILTAG_36h11, DICT_ARUCO_MIP_36h12\n" " [-adf=] # Custom aruco dictionary file for ChArUco board\n" " [-o=] # the output filename for intrinsic [and extrinsic] parameters\n" " [-op] # write detected feature points\n" @@ -458,6 +458,7 @@ int main( int argc, char** argv ) else if (arucoDictName == "DICT_APRILTAG_25h9") { arucoDict = cv::aruco::DICT_APRILTAG_25h9; } else if (arucoDictName == "DICT_APRILTAG_36h10") { arucoDict = cv::aruco::DICT_APRILTAG_36h10; } else if (arucoDictName == "DICT_APRILTAG_36h11") { arucoDict = cv::aruco::DICT_APRILTAG_36h11; } + else if (arucoDictName == "DICT_ARUCO_MIP_36h12") { arucoDict = cv::aruco::DICT_ARUCO_MIP_36h12; } else { cout << "Incorrect Aruco dictionary name " << arucoDictName << std::endl; return 1; diff --git a/samples/cpp/stereo_calib.cpp b/samples/cpp/stereo_calib.cpp index c583c8fa09..e6ce6adb25 100644 --- a/samples/cpp/stereo_calib.cpp +++ b/samples/cpp/stereo_calib.cpp @@ -58,7 +58,7 @@ static int print_help(char** argv) << "DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, DICT_5X5_1000, " << "DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50, " << "DICT_7X7_100, DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL, " - << "DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10, DICT_APRILTAG_36h11\n"; + << "DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10, DICT_APRILTAG_36h11, DICT_ARUCO_MIP_36h12\n"; return 0; } @@ -435,6 +435,7 @@ int main(int argc, char** argv) else if (arucoDictName == "DICT_APRILTAG_25h9") { arucoDict = cv::aruco::DICT_APRILTAG_25h9; } else if (arucoDictName == "DICT_APRILTAG_36h10") { arucoDict = cv::aruco::DICT_APRILTAG_36h10; } else if (arucoDictName == "DICT_APRILTAG_36h11") { arucoDict = cv::aruco::DICT_APRILTAG_36h11; } + else if (arucoDictName == "DICT_ARUCO_MIP_36h12") { arucoDict = cv::aruco::DICT_ARUCO_MIP_36h12; } else { cout << "incorrect name of aruco dictionary \n"; return 1; diff --git a/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp b/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp index 98f1a10a0c..2c417caae8 100644 --- a/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp +++ b/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp @@ -339,6 +339,7 @@ int main(int argc, char* argv[]) else if (s.arucoDictName == "DICT_APRILTAG_25h9") { arucoDict = cv::aruco::DICT_APRILTAG_25h9; } else if (s.arucoDictName == "DICT_APRILTAG_36h10") { arucoDict = cv::aruco::DICT_APRILTAG_36h10; } else if (s.arucoDictName == "DICT_APRILTAG_36h11") { arucoDict = cv::aruco::DICT_APRILTAG_36h11; } + else if (s.arucoDictName == "DICT_ARUCO_MIP_36h12") { arucoDict = cv::aruco::DICT_ARUCO_MIP_36h12; } else { cout << "incorrect name of aruco dictionary \n"; return 1; diff --git a/samples/cpp/tutorial_code/objectDetection/calibrate_camera.cpp b/samples/cpp/tutorial_code/objectDetection/calibrate_camera.cpp index b415477019..5662a84124 100644 --- a/samples/cpp/tutorial_code/objectDetection/calibrate_camera.cpp +++ b/samples/cpp/tutorial_code/objectDetection/calibrate_camera.cpp @@ -25,7 +25,8 @@ const char* keys = "{d | | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," - "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}" + "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16," + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}" "{cd | | Input file with custom dictionary }" "{@outfile |cam.yml| Output file with calibrated camera parameters }" "{v | | Input from video file, if ommited, input comes from camera }" diff --git a/samples/cpp/tutorial_code/objectDetection/calibrate_camera_charuco.cpp b/samples/cpp/tutorial_code/objectDetection/calibrate_camera_charuco.cpp index 5bea807db9..dcb2c8aa21 100644 --- a/samples/cpp/tutorial_code/objectDetection/calibrate_camera_charuco.cpp +++ b/samples/cpp/tutorial_code/objectDetection/calibrate_camera_charuco.cpp @@ -23,7 +23,8 @@ const char* keys = "{d | | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," - "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}" + "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16," + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}" "{cd | | Input file with custom dictionary }" "{@outfile |cam.yml| Output file with calibrated camera parameters }" "{v | | Input from video file, if ommited, input comes from camera }" diff --git a/samples/cpp/tutorial_code/objectDetection/create_board.cpp b/samples/cpp/tutorial_code/objectDetection/create_board.cpp index b1864ffc19..4af6f18da4 100644 --- a/samples/cpp/tutorial_code/objectDetection/create_board.cpp +++ b/samples/cpp/tutorial_code/objectDetection/create_board.cpp @@ -16,7 +16,8 @@ const char* keys = "{d | | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," - "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}" + "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16," + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}" "{cd | | Input file with custom dictionary }" "{m | | Margins size (in pixels). Default is marker separation (-s) }" "{bb | 1 | Number of bits in marker borders }" diff --git a/samples/cpp/tutorial_code/objectDetection/create_board_charuco.cpp b/samples/cpp/tutorial_code/objectDetection/create_board_charuco.cpp index b76708817a..e07bd670ec 100644 --- a/samples/cpp/tutorial_code/objectDetection/create_board_charuco.cpp +++ b/samples/cpp/tutorial_code/objectDetection/create_board_charuco.cpp @@ -17,7 +17,8 @@ const char* keys = "{d | | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," - "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}" + "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16," + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}" "{cd | | Input file with custom dictionary }" "{m | | Margins size (in pixels). Default is (squareLength-markerLength) }" "{bb | 1 | Number of bits in marker borders }" diff --git a/samples/cpp/tutorial_code/objectDetection/create_diamond.cpp b/samples/cpp/tutorial_code/objectDetection/create_diamond.cpp index 0db00e7e02..07effaca57 100644 --- a/samples/cpp/tutorial_code/objectDetection/create_diamond.cpp +++ b/samples/cpp/tutorial_code/objectDetection/create_diamond.cpp @@ -17,7 +17,8 @@ const char* keys = "{d | 10 | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," - "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}" + "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16," + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}" "{ids |0, 1, 2, 3 | Four ids for the ChArUco marker: id1,id2,id3,id4 }" "{m | 0 | Margins size (in pixels) }" "{bb | 1 | Number of bits in marker borders }" diff --git a/samples/cpp/tutorial_code/objectDetection/create_marker.cpp b/samples/cpp/tutorial_code/objectDetection/create_marker.cpp index 560e51c974..1ed78e4fe2 100644 --- a/samples/cpp/tutorial_code/objectDetection/create_marker.cpp +++ b/samples/cpp/tutorial_code/objectDetection/create_marker.cpp @@ -6,7 +6,7 @@ using namespace cv; namespace { -const char* about = "Create an ArUco marker image"; +const char* about = "Create an ArUco/AprilTag marker image"; //! [aruco_create_markers_keys] const char* keys = @@ -14,7 +14,8 @@ const char* keys = "{d | 0 | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," - "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}" + "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16," + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}" "{cd | | Input file with custom dictionary }" "{id | 0 | Marker id in the dictionary }" "{ms | 200 | Marker size in pixels }" diff --git a/samples/cpp/tutorial_code/objectDetection/detect_board.cpp b/samples/cpp/tutorial_code/objectDetection/detect_board.cpp index a9c74f2fdc..c7ed7ca7c0 100644 --- a/samples/cpp/tutorial_code/objectDetection/detect_board.cpp +++ b/samples/cpp/tutorial_code/objectDetection/detect_board.cpp @@ -19,7 +19,8 @@ const char* keys = "{d | | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," - "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}" + "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16," + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}" "{cd | | Input file with custom dictionary }" "{c | | Output file with calibrated camera parameters }" "{v | | Input from video or image file, if omitted, input comes from camera }" diff --git a/samples/cpp/tutorial_code/objectDetection/detect_board_charuco.cpp b/samples/cpp/tutorial_code/objectDetection/detect_board_charuco.cpp index c02318d6eb..7c4b5a6f50 100644 --- a/samples/cpp/tutorial_code/objectDetection/detect_board_charuco.cpp +++ b/samples/cpp/tutorial_code/objectDetection/detect_board_charuco.cpp @@ -19,7 +19,8 @@ const char* keys = "{d | | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," - "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}" + "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16," + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}" "{cd | | Input file with custom dictionary }" "{c | | Output file with calibrated camera parameters }" "{v | | Input from video or image file, if ommited, input comes from camera }" diff --git a/samples/cpp/tutorial_code/objectDetection/detect_diamonds.cpp b/samples/cpp/tutorial_code/objectDetection/detect_diamonds.cpp index f6a6236b2a..37097d87e9 100644 --- a/samples/cpp/tutorial_code/objectDetection/detect_diamonds.cpp +++ b/samples/cpp/tutorial_code/objectDetection/detect_diamonds.cpp @@ -16,7 +16,8 @@ const char* keys = "{d | 10 | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," - "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}" + "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16," + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}" "{cd | | Input file with custom dictionary }" "{c | | Output file with calibrated camera parameters }" "{as | | Automatic scale. The provided number is multiplied by the last" diff --git a/samples/cpp/tutorial_code/objectDetection/detect_markers.cpp b/samples/cpp/tutorial_code/objectDetection/detect_markers.cpp index f220b84565..06aa6221c4 100644 --- a/samples/cpp/tutorial_code/objectDetection/detect_markers.cpp +++ b/samples/cpp/tutorial_code/objectDetection/detect_markers.cpp @@ -15,7 +15,7 @@ const char* keys = "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12," "DICT_7X7_100=13, DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16," - "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20}" + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}" "{cd | | Input file with custom dictionary }" "{v | | Input from video or image file, if ommited, input comes from camera }" "{ci | 0 | Camera id if input doesnt come from video (-v) }" diff --git a/samples/python/aruco_detect_board_charuco.py b/samples/python/aruco_detect_board_charuco.py index ffb5ac677d..58ba5a899f 100644 --- a/samples/python/aruco_detect_board_charuco.py +++ b/samples/python/aruco_detect_board_charuco.py @@ -36,7 +36,8 @@ def main(): parser.add_argument("-d", help="dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2, DICT_4X4_1000=3," "DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, DICT_6X6_50=8," "DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12, DICT_7X7_100=13," - "DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL = 16}", + "DICT_7X7_250=14, DICT_7X7_1000=15, DICT_ARUCO_ORIGINAL=16," + "DICT_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20, DICT_ARUCO_MIP_36h12=21}", default="0", action="store", dest="d", type=int) parser.add_argument("-ci", help="Camera id if input doesnt come from video (-v)", default="0", action="store", dest="ci", type=int) diff --git a/samples/python/calibrate.py b/samples/python/calibrate.py index 33c87b6a52..19c0ab0d66 100755 --- a/samples/python/calibrate.py +++ b/samples/python/calibrate.py @@ -100,7 +100,8 @@ def main(): 'DICT_APRILTAG_16h5': cv.aruco.DICT_APRILTAG_16h5, 'DICT_APRILTAG_25h9': cv.aruco.DICT_APRILTAG_25h9, 'DICT_APRILTAG_36h10': cv.aruco.DICT_APRILTAG_36h10, - 'DICT_APRILTAG_36h11': cv.aruco.DICT_APRILTAG_36h11 + 'DICT_APRILTAG_36h11': cv.aruco.DICT_APRILTAG_36h11, + 'DICT_ARUCO_MIP_36h12': cv.aruco.DICT_ARUCO_MIP_36h12 } if (aruco_dict_name not in set(aruco_dicts.keys())):