1
0
mirror of https://github.com/opencv/opencv_contrib.git synced 2025-10-19 11:21:39 +08:00

fix ArUco, ChArUco, diamonds, add read dictionary/params, add calibration photos, add tests, add aruco_samples_utility.hpp

This commit is contained in:
Aleksandr Panov
2021-12-18 14:19:07 +03:00
parent 5cc328d37a
commit a965b9bbf2
42 changed files with 749 additions and 430 deletions

View File

@@ -1,2 +1,31 @@
set(the_description "ArUco Marker Detection") set(the_description "ArUco Marker Detection")
ocv_define_module(aruco opencv_core opencv_imgproc opencv_calib3d WRAP python java) ocv_define_module(aruco opencv_core opencv_imgproc opencv_calib3d WRAP python java)
ocv_include_directories(${CMAKE_CURRENT_BINARY_DIR})
ocv_add_testdata(samples/ contrib/aruco
FILES_MATCHING PATTERN "*yml"
)
ocv_add_testdata(tutorials/aruco_detection/images/ contrib/aruco
FILES_MATCHING PATTERN "singlemarkersoriginal.jpg"
)
ocv_add_testdata(tutorials/aruco_board_detection/images/ contrib/aruco
FILES_MATCHING PATTERN "gboriginal.png"
)
ocv_add_testdata(tutorials/charuco_detection/images/ contrib/aruco
FILES_MATCHING PATTERN "choriginal.jpg"
)
ocv_add_testdata(tutorials/charuco_detection/images/ contrib/aruco
FILES_MATCHING PATTERN "chocclusion_original.jpg"
)
ocv_add_testdata(tutorials/charuco_diamond_detection/images/ contrib/aruco
FILES_MATCHING PATTERN "diamondmarkers.png"
)
ocv_add_testdata(tutorials/aruco_calibration/images/ contrib/aruco
FILES_MATCHING REGEX "img_[0-9]+.jpg"
)

View File

@@ -150,8 +150,8 @@ enum CornerRefineMethod{
struct CV_EXPORTS_W DetectorParameters { struct CV_EXPORTS_W DetectorParameters {
DetectorParameters(); DetectorParameters();
CV_WRAP static Ptr<DetectorParameters> create(); CV_WRAP static Ptr<DetectorParameters> create();
CV_WRAP static bool readDetectorParameters(const FileNode& fn, Ptr<DetectorParameters>& params);
CV_PROP_RW int adaptiveThreshWinSizeMin; CV_PROP_RW int adaptiveThreshWinSizeMin;
CV_PROP_RW int adaptiveThreshWinSizeMax; CV_PROP_RW int adaptiveThreshWinSizeMax;

View File

@@ -93,6 +93,16 @@ class CV_EXPORTS_W Dictionary {
CV_WRAP_AS(create_from) static Ptr<Dictionary> create(int nMarkers, int markerSize, CV_WRAP_AS(create_from) static Ptr<Dictionary> create(int nMarkers, int markerSize,
const Ptr<Dictionary> &baseDictionary, int randomSeed=0); const Ptr<Dictionary> &baseDictionary, int randomSeed=0);
/**
* @brief Read a new dictionary from FileNode. Format:
* nmarkers: 35
* markersize: 6
* marker_0: "101011111011111001001001101100000000"
* ...
* marker_34: "011111010000111011111110110101100101"
*/
CV_WRAP static bool readDictionary(const cv::FileNode& fn, cv::Ptr<cv::aruco::Dictionary> &dictionary);
/** /**
* @see getPredefinedDictionary * @see getPredefinedDictionary
*/ */

View File

@@ -0,0 +1,48 @@
#include <opencv2/highgui.hpp>
#include <opencv2/aruco.hpp>
#include <opencv2/calib3d.hpp>
#include <ctime>
namespace {
inline static bool readCameraParameters(std::string filename, cv::Mat &camMatrix, cv::Mat &distCoeffs) {
cv::FileStorage fs(filename, cv::FileStorage::READ);
if (!fs.isOpened())
return false;
fs["camera_matrix"] >> camMatrix;
fs["distortion_coefficients"] >> distCoeffs;
return true;
}
inline static bool saveCameraParams(const std::string &filename, cv::Size imageSize, float aspectRatio, int flags,
const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs, double totalAvgErr) {
cv::FileStorage fs(filename, cv::FileStorage::WRITE);
if (!fs.isOpened())
return false;
time_t tt;
time(&tt);
struct tm *t2 = localtime(&tt);
char buf[1024];
strftime(buf, sizeof(buf) - 1, "%c", t2);
fs << "calibration_time" << buf;
fs << "image_width" << imageSize.width;
fs << "image_height" << imageSize.height;
if (flags & cv::CALIB_FIX_ASPECT_RATIO) fs << "aspectRatio" << aspectRatio;
if (flags != 0) {
sprintf(buf, "flags: %s%s%s%s",
flags & cv::CALIB_USE_INTRINSIC_GUESS ? "+use_intrinsic_guess" : "",
flags & cv::CALIB_FIX_ASPECT_RATIO ? "+fix_aspectRatio" : "",
flags & cv::CALIB_FIX_PRINCIPAL_POINT ? "+fix_principal_point" : "",
flags & cv::CALIB_ZERO_TANGENT_DIST ? "+zero_tangent_dist" : "");
}
fs << "flags" << flags;
fs << "camera_matrix" << cameraMatrix;
fs << "distortion_coefficients" << distCoeffs;
fs << "avg_reprojection_error" << totalAvgErr;
return true;
}
}

View File

@@ -44,6 +44,7 @@ the use of this software, even if advised of the possibility of such damage.
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <ctime> #include <ctime>
#include "aruco_samples_utility.hpp"
using namespace std; using namespace std;
using namespace cv; using namespace cv;
@@ -64,6 +65,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_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_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}"
"{cd | | Input file with custom dictionary }"
"{@outfile |<none> | Output file with calibrated camera parameters }" "{@outfile |<none> | Output file with calibrated camera parameters }"
"{v | | Input from video file, if ommited, input comes from camera }" "{v | | Input from video file, if ommited, input comes from camera }"
"{ci | 0 | Camera id if input doesnt come from video (-v) }" "{ci | 0 | Camera id if input doesnt come from video (-v) }"
@@ -74,80 +76,7 @@ const char* keys =
"{pc | false | Fix the principal point at the center }"; "{pc | false | Fix the principal point at the center }";
} }
/**
*/
static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
FileStorage fs(filename, FileStorage::READ);
if(!fs.isOpened())
return false;
fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
fs["minDistanceToBorder"] >> params->minDistanceToBorder;
fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
fs["cornerRefinementMethod"] >> params->cornerRefinementMethod;
fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
fs["markerBorderBits"] >> params->markerBorderBits;
fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
fs["minOtsuStdDev"] >> params->minOtsuStdDev;
fs["errorCorrectionRate"] >> params->errorCorrectionRate;
return true;
}
/**
*/
static bool saveCameraParams(const string &filename, Size imageSize, float aspectRatio, int flags,
const Mat &cameraMatrix, const Mat &distCoeffs, double totalAvgErr) {
FileStorage fs(filename, FileStorage::WRITE);
if(!fs.isOpened())
return false;
time_t tt;
time(&tt);
struct tm *t2 = localtime(&tt);
char buf[1024];
strftime(buf, sizeof(buf) - 1, "%c", t2);
fs << "calibration_time" << buf;
fs << "image_width" << imageSize.width;
fs << "image_height" << imageSize.height;
if(flags & CALIB_FIX_ASPECT_RATIO) fs << "aspectRatio" << aspectRatio;
if(flags != 0) {
sprintf(buf, "flags: %s%s%s%s",
flags & CALIB_USE_INTRINSIC_GUESS ? "+use_intrinsic_guess" : "",
flags & CALIB_FIX_ASPECT_RATIO ? "+fix_aspectRatio" : "",
flags & CALIB_FIX_PRINCIPAL_POINT ? "+fix_principal_point" : "",
flags & CALIB_ZERO_TANGENT_DIST ? "+zero_tangent_dist" : "");
}
fs << "flags" << flags;
fs << "camera_matrix" << cameraMatrix;
fs << "distortion_coefficients" << distCoeffs;
fs << "avg_reprojection_error" << totalAvgErr;
return true;
}
/**
*/
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CommandLineParser parser(argc, argv, keys); CommandLineParser parser(argc, argv, keys);
parser.about(about); parser.about(about);
@@ -161,7 +90,6 @@ int main(int argc, char *argv[]) {
int markersY = parser.get<int>("h"); int markersY = parser.get<int>("h");
float markerLength = parser.get<float>("l"); float markerLength = parser.get<float>("l");
float markerSeparation = parser.get<float>("s"); float markerSeparation = parser.get<float>("s");
int dictionaryId = parser.get<int>("d");
string outputFile = parser.get<String>(0); string outputFile = parser.get<String>(0);
int calibrationFlags = 0; int calibrationFlags = 0;
@@ -173,9 +101,10 @@ int main(int argc, char *argv[]) {
if(parser.get<bool>("zt")) calibrationFlags |= CALIB_ZERO_TANGENT_DIST; if(parser.get<bool>("zt")) calibrationFlags |= CALIB_ZERO_TANGENT_DIST;
if(parser.get<bool>("pc")) calibrationFlags |= CALIB_FIX_PRINCIPAL_POINT; if(parser.get<bool>("pc")) calibrationFlags |= CALIB_FIX_PRINCIPAL_POINT;
Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create(); Ptr<aruco::DetectorParameters> detectorParams;
if(parser.has("dp")) { if(parser.has("dp")) {
bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams); FileStorage fs(parser.get<string>("dp"), FileStorage::READ);
bool readOk = aruco::DetectorParameters::readDetectorParameters(fs.root(), detectorParams);
if(!readOk) { if(!readOk) {
cerr << "Invalid detector parameters file" << endl; cerr << "Invalid detector parameters file" << endl;
return 0; return 0;
@@ -205,8 +134,23 @@ int main(int argc, char *argv[]) {
waitTime = 10; waitTime = 10;
} }
Ptr<aruco::Dictionary> dictionary = Ptr<aruco::Dictionary> dictionary;
aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); if (parser.has("d")) {
int dictionaryId = parser.get<int>("d");
dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
}
else if (parser.has("cd")) {
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ);
bool readOk = aruco::Dictionary::readDictionary(fs.root(), dictionary);
if(!readOk) {
cerr << "Invalid dictionary file" << endl;
return 0;
}
}
else {
cerr << "Dictionary not specified" << endl;
return 0;
}
// create board object // create board object
Ptr<aruco::GridBoard> gridboard = Ptr<aruco::GridBoard> gridboard =

View File

@@ -43,7 +43,7 @@ the use of this software, even if advised of the possibility of such damage.
#include <opencv2/imgproc.hpp> #include <opencv2/imgproc.hpp>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <ctime> #include "aruco_samples_utility.hpp"
using namespace std; using namespace std;
using namespace cv; using namespace cv;
@@ -63,6 +63,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_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_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}"
"{cd | | Input file with custom dictionary }"
"{@outfile |<none> | Output file with calibrated camera parameters }" "{@outfile |<none> | Output file with calibrated camera parameters }"
"{v | | Input from video file, if ommited, input comes from camera }" "{v | | Input from video file, if ommited, input comes from camera }"
"{ci | 0 | Camera id if input doesnt come from video (-v) }" "{ci | 0 | Camera id if input doesnt come from video (-v) }"
@@ -74,80 +75,7 @@ const char* keys =
"{sc | false | Show detected chessboard corners after calibration }"; "{sc | false | Show detected chessboard corners after calibration }";
} }
/**
*/
static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
FileStorage fs(filename, FileStorage::READ);
if(!fs.isOpened())
return false;
fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
fs["minDistanceToBorder"] >> params->minDistanceToBorder;
fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
fs["cornerRefinementMethod"] >> params->cornerRefinementMethod;
fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
fs["markerBorderBits"] >> params->markerBorderBits;
fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
fs["minOtsuStdDev"] >> params->minOtsuStdDev;
fs["errorCorrectionRate"] >> params->errorCorrectionRate;
return true;
}
/**
*/
static bool saveCameraParams(const string &filename, Size imageSize, float aspectRatio, int flags,
const Mat &cameraMatrix, const Mat &distCoeffs, double totalAvgErr) {
FileStorage fs(filename, FileStorage::WRITE);
if(!fs.isOpened())
return false;
time_t tt;
time(&tt);
struct tm *t2 = localtime(&tt);
char buf[1024];
strftime(buf, sizeof(buf) - 1, "%c", t2);
fs << "calibration_time" << buf;
fs << "image_width" << imageSize.width;
fs << "image_height" << imageSize.height;
if(flags & CALIB_FIX_ASPECT_RATIO) fs << "aspectRatio" << aspectRatio;
if(flags != 0) {
sprintf(buf, "flags: %s%s%s%s",
flags & CALIB_USE_INTRINSIC_GUESS ? "+use_intrinsic_guess" : "",
flags & CALIB_FIX_ASPECT_RATIO ? "+fix_aspectRatio" : "",
flags & CALIB_FIX_PRINCIPAL_POINT ? "+fix_principal_point" : "",
flags & CALIB_ZERO_TANGENT_DIST ? "+zero_tangent_dist" : "");
}
fs << "flags" << flags;
fs << "camera_matrix" << cameraMatrix;
fs << "distortion_coefficients" << distCoeffs;
fs << "avg_reprojection_error" << totalAvgErr;
return true;
}
/**
*/
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CommandLineParser parser(argc, argv, keys); CommandLineParser parser(argc, argv, keys);
parser.about(about); parser.about(about);
@@ -161,7 +89,6 @@ int main(int argc, char *argv[]) {
int squaresY = parser.get<int>("h"); int squaresY = parser.get<int>("h");
float squareLength = parser.get<float>("sl"); float squareLength = parser.get<float>("sl");
float markerLength = parser.get<float>("ml"); float markerLength = parser.get<float>("ml");
int dictionaryId = parser.get<int>("d");
string outputFile = parser.get<string>(0); string outputFile = parser.get<string>(0);
bool showChessboardCorners = parser.get<bool>("sc"); bool showChessboardCorners = parser.get<bool>("sc");
@@ -175,9 +102,10 @@ int main(int argc, char *argv[]) {
if(parser.get<bool>("zt")) calibrationFlags |= CALIB_ZERO_TANGENT_DIST; if(parser.get<bool>("zt")) calibrationFlags |= CALIB_ZERO_TANGENT_DIST;
if(parser.get<bool>("pc")) calibrationFlags |= CALIB_FIX_PRINCIPAL_POINT; if(parser.get<bool>("pc")) calibrationFlags |= CALIB_FIX_PRINCIPAL_POINT;
Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create(); Ptr<aruco::DetectorParameters> detectorParams;
if(parser.has("dp")) { if(parser.has("dp")) {
bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams); FileStorage fs(parser.get<string>("dp"), FileStorage::READ);
bool readOk = aruco::DetectorParameters::readDetectorParameters(fs.root(), detectorParams);
if(!readOk) { if(!readOk) {
cerr << "Invalid detector parameters file" << endl; cerr << "Invalid detector parameters file" << endl;
return 0; return 0;
@@ -207,8 +135,23 @@ int main(int argc, char *argv[]) {
waitTime = 10; waitTime = 10;
} }
Ptr<aruco::Dictionary> dictionary = Ptr<aruco::Dictionary> dictionary;
aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); if (parser.has("d")) {
int dictionaryId = parser.get<int>("d");
dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
}
else if (parser.has("cd")) {
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ);
bool readOk = aruco::Dictionary::readDictionary(fs.root(), dictionary);
if(!readOk) {
cerr << "Invalid dictionary file" << endl;
return 0;
}
}
else {
cerr << "Dictionary not specified" << endl;
return 0;
}
// create charuco board object // create charuco board object
Ptr<aruco::CharucoBoard> charucoboard = Ptr<aruco::CharucoBoard> charucoboard =

View File

@@ -39,6 +39,8 @@ the use of this software, even if advised of the possibility of such damage.
#include <opencv2/highgui.hpp> #include <opencv2/highgui.hpp>
#include <opencv2/aruco.hpp> #include <opencv2/aruco.hpp>
#include <iostream>
#include "aruco_samples_utility.hpp"
using namespace cv; using namespace cv;
@@ -54,11 +56,13 @@ const char* keys =
"DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "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_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}"
"{cd | | Input file with custom dictionary }"
"{m | | Margins size (in pixels). Default is marker separation (-s) }" "{m | | Margins size (in pixels). Default is marker separation (-s) }"
"{bb | 1 | Number of bits in marker borders }" "{bb | 1 | Number of bits in marker borders }"
"{si | false | show generated image }"; "{si | false | show generated image }";
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CommandLineParser parser(argc, argv, keys); CommandLineParser parser(argc, argv, keys);
parser.about(about); parser.about(about);
@@ -72,7 +76,6 @@ int main(int argc, char *argv[]) {
int markersY = parser.get<int>("h"); int markersY = parser.get<int>("h");
int markerLength = parser.get<int>("l"); int markerLength = parser.get<int>("l");
int markerSeparation = parser.get<int>("s"); int markerSeparation = parser.get<int>("s");
int dictionaryId = parser.get<int>("d");
int margins = markerSeparation; int margins = markerSeparation;
if(parser.has("m")) { if(parser.has("m")) {
margins = parser.get<int>("m"); margins = parser.get<int>("m");
@@ -93,8 +96,24 @@ int main(int argc, char *argv[]) {
imageSize.height = imageSize.height =
markersY * (markerLength + markerSeparation) - markerSeparation + 2 * margins; markersY * (markerLength + markerSeparation) - markerSeparation + 2 * margins;
Ptr<aruco::Dictionary> dictionary = Ptr<aruco::Dictionary> dictionary;
aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); if (parser.has("d")) {
int dictionaryId = parser.get<int>("d");
dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
}
else if (parser.has("cd")) {
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ);
bool readOk = aruco::Dictionary::readDictionary(fs.root(), dictionary);
if(!readOk)
{
std::cerr << "Invalid dictionary file" << std::endl;
return 0;
}
}
else {
std::cerr << "Dictionary not specified" << std::endl;
return 0;
}
Ptr<aruco::GridBoard> board = aruco::GridBoard::create(markersX, markersY, float(markerLength), Ptr<aruco::GridBoard> board = aruco::GridBoard::create(markersX, markersY, float(markerLength),
float(markerSeparation), dictionary); float(markerSeparation), dictionary);

View File

@@ -39,11 +39,14 @@ the use of this software, even if advised of the possibility of such damage.
#include <opencv2/highgui.hpp> #include <opencv2/highgui.hpp>
#include <opencv2/aruco/charuco.hpp> #include <opencv2/aruco/charuco.hpp>
#include <iostream>
#include "aruco_samples_utility.hpp"
using namespace cv; using namespace cv;
namespace { namespace {
const char* about = "Create a ChArUco board image"; const char* about = "Create a ChArUco board image";
//! [charuco_detect_board_keys]
const char* keys = const char* keys =
"{@outfile |<none> | Output image }" "{@outfile |<none> | Output image }"
"{w | | Number of squares in X direction }" "{w | | Number of squares in X direction }"
@@ -54,10 +57,13 @@ const char* keys =
"DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "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_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}"
"{cd | | Input file with custom dictionary }"
"{m | | Margins size (in pixels). Default is (squareLength-markerLength) }" "{m | | Margins size (in pixels). Default is (squareLength-markerLength) }"
"{bb | 1 | Number of bits in marker borders }" "{bb | 1 | Number of bits in marker borders }"
"{si | false | show generated image }"; "{si | false | show generated image }";
} }
//! [charuco_detect_board_keys]
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CommandLineParser parser(argc, argv, keys); CommandLineParser parser(argc, argv, keys);
@@ -72,7 +78,6 @@ int main(int argc, char *argv[]) {
int squaresY = parser.get<int>("h"); int squaresY = parser.get<int>("h");
int squareLength = parser.get<int>("sl"); int squareLength = parser.get<int>("sl");
int markerLength = parser.get<int>("ml"); int markerLength = parser.get<int>("ml");
int dictionaryId = parser.get<int>("d");
int margins = squareLength - markerLength; int margins = squareLength - markerLength;
if(parser.has("m")) { if(parser.has("m")) {
margins = parser.get<int>("m"); margins = parser.get<int>("m");
@@ -88,8 +93,23 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
Ptr<aruco::Dictionary> dictionary = Ptr<aruco::Dictionary> dictionary;
aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); if (parser.has("d")) {
int dictionaryId = parser.get<int>("d");
dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
}
else if (parser.has("cd")) {
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ);
bool readOk = aruco::Dictionary::readDictionary(fs.root(), dictionary);
if(!readOk) {
std::cerr << "Invalid dictionary file" << std::endl;
return 0;
}
}
else {
std::cerr << "Dictionary not specified" << std::endl;
return 0;
}
Size imageSize; Size imageSize;
imageSize.width = squaresX * squareLength + 2 * margins; imageSize.width = squaresX * squareLength + 2 * margins;

View File

@@ -39,22 +39,28 @@ the use of this software, even if advised of the possibility of such damage.
#include <opencv2/highgui.hpp> #include <opencv2/highgui.hpp>
#include <opencv2/aruco.hpp> #include <opencv2/aruco.hpp>
#include <iostream>
#include "aruco_samples_utility.hpp"
using namespace cv; using namespace cv;
namespace { namespace {
const char* about = "Create an ArUco marker image"; const char* about = "Create an ArUco marker image";
//! [aruco_create_markers_keys]
const char* keys = const char* keys =
"{@outfile |<none> | Output image }" "{@outfile |<none> | Output image }"
"{d | | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "{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_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_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}"
"{cd | | Input file with custom dictionary }"
"{id | | Marker id in the dictionary }" "{id | | Marker id in the dictionary }"
"{ms | 200 | Marker size in pixels }" "{ms | 200 | Marker size in pixels }"
"{bb | 1 | Number of bits in marker borders }" "{bb | 1 | Number of bits in marker borders }"
"{si | false | show generated image }"; "{si | false | show generated image }";
} }
//! [aruco_create_markers_keys]
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@@ -66,7 +72,6 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
int dictionaryId = parser.get<int>("d");
int markerId = parser.get<int>("id"); int markerId = parser.get<int>("id");
int borderBits = parser.get<int>("bb"); int borderBits = parser.get<int>("bb");
int markerSize = parser.get<int>("ms"); int markerSize = parser.get<int>("ms");
@@ -79,8 +84,23 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
Ptr<aruco::Dictionary> dictionary = Ptr<aruco::Dictionary> dictionary;
aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); if (parser.has("d")) {
int dictionaryId = parser.get<int>("d");
dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
}
else if (parser.has("cd")) {
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ);
bool readOk = aruco::Dictionary::readDictionary(fs.root(), dictionary);
if(!readOk) {
std::cerr << "Invalid dictionary file" << std::endl;
return 0;
}
}
else {
std::cerr << "Dictionary not specified" << std::endl;
return 0;
}
Mat markerImg; Mat markerImg;
aruco::drawMarker(dictionary, markerId, markerSize, markerImg, borderBits); aruco::drawMarker(dictionary, markerId, markerSize, markerImg, borderBits);

View File

@@ -41,12 +41,15 @@ the use of this software, even if advised of the possibility of such damage.
#include <opencv2/aruco.hpp> #include <opencv2/aruco.hpp>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include "aruco_samples_utility.hpp"
using namespace std; using namespace std;
using namespace cv; using namespace cv;
namespace { namespace {
const char* about = "Pose estimation using a ArUco Planar Grid board"; const char* about = "Pose estimation using a ArUco Planar Grid board";
//! [aruco_detect_board_keys]
const char* keys = const char* keys =
"{w | | Number of squares in X direction }" "{w | | Number of squares in X direction }"
"{h | | Number of squares in Y direction }" "{h | | Number of squares in Y direction }"
@@ -56,59 +59,17 @@ const char* keys =
"DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "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_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}"
"{cd | | Input file with custom dictionary }"
"{c | | Output file with calibrated camera parameters }" "{c | | Output file with calibrated camera parameters }"
"{v | | Input from video file, if ommited, input comes from camera }" "{v | | Input from video or image file, if omitted, input comes from camera }"
"{ci | 0 | Camera id if input doesnt come from video (-v) }" "{ci | 0 | Camera id if input doesnt come from video (-v) }"
"{dp | | File of marker detector parameters }" "{dp | | File of marker detector parameters }"
"{rs | | Apply refind strategy }" "{rs | | Apply refind strategy }"
"{r | | show rejected candidates too }"; "{r | | show rejected candidates too }";
} }
//! [aruco_detect_board_keys]
/**
*/
static bool readCameraParameters(string filename, Mat &camMatrix, Mat &distCoeffs) {
FileStorage fs(filename, FileStorage::READ);
if(!fs.isOpened())
return false;
fs["camera_matrix"] >> camMatrix;
fs["distortion_coefficients"] >> distCoeffs;
return true;
}
/**
*/
static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
FileStorage fs(filename, FileStorage::READ);
if(!fs.isOpened())
return false;
fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
fs["minDistanceToBorder"] >> params->minDistanceToBorder;
fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
fs["cornerRefinementMethod"] >> params->cornerRefinementMethod;
fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
fs["markerBorderBits"] >> params->markerBorderBits;
fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
fs["minOtsuStdDev"] >> params->minOtsuStdDev;
fs["errorCorrectionRate"] >> params->errorCorrectionRate;
return true;
}
/**
*/
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CommandLineParser parser(argc, argv, keys); CommandLineParser parser(argc, argv, keys);
parser.about(about); parser.about(about);
@@ -122,7 +83,6 @@ int main(int argc, char *argv[]) {
int markersY = parser.get<int>("h"); int markersY = parser.get<int>("h");
float markerLength = parser.get<float>("l"); float markerLength = parser.get<float>("l");
float markerSeparation = parser.get<float>("s"); float markerSeparation = parser.get<float>("s");
int dictionaryId = parser.get<int>("d");
bool showRejected = parser.has("r"); bool showRejected = parser.has("r");
bool refindStrategy = parser.has("rs"); bool refindStrategy = parser.has("rs");
int camId = parser.get<int>("ci"); int camId = parser.get<int>("ci");
@@ -137,9 +97,10 @@ int main(int argc, char *argv[]) {
} }
} }
Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create(); Ptr<aruco::DetectorParameters> detectorParams;
if(parser.has("dp")) { if(parser.has("dp")) {
bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams); FileStorage fs(parser.get<string>("dp"), FileStorage::READ);
bool readOk = aruco::DetectorParameters::readDetectorParameters(fs.root(), detectorParams);
if(!readOk) { if(!readOk) {
cerr << "Invalid detector parameters file" << endl; cerr << "Invalid detector parameters file" << endl;
return 0; return 0;
@@ -157,8 +118,23 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
Ptr<aruco::Dictionary> dictionary = Ptr<aruco::Dictionary> dictionary;
aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); if (parser.has("d")) {
int dictionaryId = parser.get<int>("d");
dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
}
else if (parser.has("cd")) {
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ);
bool readOk = aruco::Dictionary::readDictionary(fs.root(), dictionary);
if(!readOk) {
cerr << "Invalid dictionary file" << endl;
return 0;
}
}
else {
cerr << "Dictionary not specified" << endl;
return 0;
}
VideoCapture inputVideo; VideoCapture inputVideo;
int waitTime; int waitTime;

View File

@@ -41,6 +41,7 @@ the use of this software, even if advised of the possibility of such damage.
#include <opencv2/aruco/charuco.hpp> #include <opencv2/aruco/charuco.hpp>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include "aruco_samples_utility.hpp"
using namespace std; using namespace std;
using namespace cv; using namespace cv;
@@ -57,58 +58,16 @@ const char* keys =
"DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, " "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_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}"
"{cd | | Input file with custom dictionary }"
"{c | | Output file with calibrated camera parameters }" "{c | | Output file with calibrated camera parameters }"
"{v | | Input from video file, if ommited, input comes from camera }" "{v | | Input from video or image file, if ommited, input comes from camera }"
"{ci | 0 | Camera id if input doesnt come from video (-v) }" "{ci | 0 | Camera id if input doesnt come from video (-v) }"
"{dp | | File of marker detector parameters }" "{dp | | File of marker detector parameters }"
"{rs | | Apply refind strategy }" "{rs | | Apply refind strategy }"
"{r | | show rejected candidates too }"; "{r | | show rejected candidates too }";
} }
/**
*/
static bool readCameraParameters(string filename, Mat &camMatrix, Mat &distCoeffs) {
FileStorage fs(filename, FileStorage::READ);
if(!fs.isOpened())
return false;
fs["camera_matrix"] >> camMatrix;
fs["distortion_coefficients"] >> distCoeffs;
return true;
}
/**
*/
static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
FileStorage fs(filename, FileStorage::READ);
if(!fs.isOpened())
return false;
fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
fs["minDistanceToBorder"] >> params->minDistanceToBorder;
fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
fs["cornerRefinementMethod"] >> params->cornerRefinementMethod;
fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
fs["markerBorderBits"] >> params->markerBorderBits;
fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
fs["minOtsuStdDev"] >> params->minOtsuStdDev;
fs["errorCorrectionRate"] >> params->errorCorrectionRate;
return true;
}
/**
*/
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CommandLineParser parser(argc, argv, keys); CommandLineParser parser(argc, argv, keys);
parser.about(about); parser.about(about);
@@ -122,7 +81,6 @@ int main(int argc, char *argv[]) {
int squaresY = parser.get<int>("h"); int squaresY = parser.get<int>("h");
float squareLength = parser.get<float>("sl"); float squareLength = parser.get<float>("sl");
float markerLength = parser.get<float>("ml"); float markerLength = parser.get<float>("ml");
int dictionaryId = parser.get<int>("d");
bool showRejected = parser.has("r"); bool showRejected = parser.has("r");
bool refindStrategy = parser.has("rs"); bool refindStrategy = parser.has("rs");
int camId = parser.get<int>("ci"); int camId = parser.get<int>("ci");
@@ -141,9 +99,10 @@ int main(int argc, char *argv[]) {
} }
} }
Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create(); Ptr<aruco::DetectorParameters> detectorParams;
if(parser.has("dp")) { if(parser.has("dp")) {
bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams); FileStorage fs(parser.get<string>("dp"), FileStorage::READ);
bool readOk = aruco::DetectorParameters::readDetectorParameters(fs.root(), detectorParams);
if(!readOk) { if(!readOk) {
cerr << "Invalid detector parameters file" << endl; cerr << "Invalid detector parameters file" << endl;
return 0; return 0;
@@ -155,8 +114,23 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
Ptr<aruco::Dictionary> dictionary = Ptr<aruco::Dictionary> dictionary;
aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); if (parser.has("d")) {
int dictionaryId = parser.get<int>("d");
dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
}
else if (parser.has("cd")) {
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ);
bool readOk = aruco::Dictionary::readDictionary(fs.root(), dictionary);
if(!readOk) {
cerr << "Invalid dictionary file" << endl;
return 0;
}
}
else {
cerr << "Dictionary not specified" << endl;
return 0;
}
VideoCapture inputVideo; VideoCapture inputVideo;
int waitTime; int waitTime;

View File

@@ -41,6 +41,7 @@ the use of this software, even if advised of the possibility of such damage.
#include <opencv2/aruco/charuco.hpp> #include <opencv2/aruco/charuco.hpp>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include "aruco_samples_utility.hpp"
using namespace std; using namespace std;
using namespace cv; using namespace cv;
@@ -55,6 +56,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_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_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}"
"{cd | | Input file with custom dictionary }"
"{c | | Output file with calibrated camera parameters }" "{c | | Output file with calibrated camera parameters }"
"{as | | Automatic scale. The provided number is multiplied by the last" "{as | | Automatic scale. The provided number is multiplied by the last"
"diamond id becoming an indicator of the square length. In this case, the -sl and " "diamond id becoming an indicator of the square length. In this case, the -sl and "
@@ -63,53 +65,12 @@ const char* keys =
"{ci | 0 | Camera id if input doesnt come from video (-v) }" "{ci | 0 | Camera id if input doesnt come from video (-v) }"
"{dp | | File of marker detector parameters }" "{dp | | File of marker detector parameters }"
"{rs | | Apply refind strategy }" "{rs | | Apply refind strategy }"
"{refine | | Corner refinement: CORNER_REFINE_NONE=0, CORNER_REFINE_SUBPIX=1,"
"CORNER_REFINE_CONTOUR=2, CORNER_REFINE_APRILTAG=3}"
"{r | | show rejected candidates too }"; "{r | | show rejected candidates too }";
} }
/**
*/
static bool readCameraParameters(string filename, Mat &camMatrix, Mat &distCoeffs) {
FileStorage fs(filename, FileStorage::READ);
if(!fs.isOpened())
return false;
fs["camera_matrix"] >> camMatrix;
fs["distortion_coefficients"] >> distCoeffs;
return true;
}
/**
*/
static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
FileStorage fs(filename, FileStorage::READ);
if(!fs.isOpened())
return false;
fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
fs["minDistanceToBorder"] >> params->minDistanceToBorder;
fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
fs["cornerRefinementMethod"] >> params->cornerRefinementMethod;
fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
fs["markerBorderBits"] >> params->markerBorderBits;
fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
fs["minOtsuStdDev"] >> params->minOtsuStdDev;
fs["errorCorrectionRate"] >> params->errorCorrectionRate;
return true;
}
/**
*/
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CommandLineParser parser(argc, argv, keys); CommandLineParser parser(argc, argv, keys);
parser.about(about); parser.about(about);
@@ -121,20 +82,25 @@ int main(int argc, char *argv[]) {
float squareLength = parser.get<float>("sl"); float squareLength = parser.get<float>("sl");
float markerLength = parser.get<float>("ml"); float markerLength = parser.get<float>("ml");
int dictionaryId = parser.get<int>("d");
bool showRejected = parser.has("r"); bool showRejected = parser.has("r");
bool estimatePose = parser.has("c"); bool estimatePose = parser.has("c");
bool autoScale = parser.has("as"); bool autoScale = parser.has("as");
float autoScaleFactor = autoScale ? parser.get<float>("as") : 1.f; float autoScaleFactor = autoScale ? parser.get<float>("as") : 1.f;
Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create(); Ptr<aruco::DetectorParameters> detectorParams;
if(parser.has("dp")) { if(parser.has("dp")) {
bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams); FileStorage fs(parser.get<string>("dp"), FileStorage::READ);
bool readOk = aruco::DetectorParameters::readDetectorParameters(fs.root(), detectorParams);
if(!readOk) { if(!readOk) {
cerr << "Invalid detector parameters file" << endl; cerr << "Invalid detector parameters file" << endl;
return 0; return 0;
} }
} }
if (parser.has("refine")) {
//override cornerRefinementMethod read from config file
detectorParams->cornerRefinementMethod = parser.get<int>("refine");
}
std::cout << "Corner refinement method (0: None, 1: Subpixel, 2:contour, 3: AprilTag 2): " << detectorParams->cornerRefinementMethod << std::endl;
int camId = parser.get<int>("ci"); int camId = parser.get<int>("ci");
String video; String video;
@@ -148,8 +114,23 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
Ptr<aruco::Dictionary> dictionary = Ptr<aruco::Dictionary> dictionary;
aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); if (parser.has("d")) {
int dictionaryId = parser.get<int>("d");
dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
}
else if (parser.has("cd")) {
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ);
bool readOk = aruco::Dictionary::readDictionary(fs.root(), dictionary);
if(!readOk) {
cerr << "Invalid dictionary file" << endl;
return 0;
}
}
else {
cerr << "Dictionary not specified" << endl;
return 0;
}
Mat camMatrix, distCoeffs; Mat camMatrix, distCoeffs;
if(estimatePose) { if(estimatePose) {

View File

@@ -40,19 +40,23 @@ the use of this software, even if advised of the possibility of such damage.
#include <opencv2/highgui.hpp> #include <opencv2/highgui.hpp>
#include <opencv2/aruco.hpp> #include <opencv2/aruco.hpp>
#include <iostream> #include <iostream>
#include "aruco_samples_utility.hpp"
using namespace std; using namespace std;
using namespace cv; using namespace cv;
namespace { namespace {
const char* about = "Basic marker detection"; const char* about = "Basic marker detection";
//! [aruco_detect_markers_keys]
const char* keys = const char* keys =
"{d | | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2," "{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_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_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_APRILTAG_16h5=17, DICT_APRILTAG_25h9=18, DICT_APRILTAG_36h10=19, DICT_APRILTAG_36h11=20}"
"{v | | Input from video file, if ommited, input comes from camera }" "{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) }" "{ci | 0 | Camera id if input doesnt come from video (-v) }"
"{c | | Camera intrinsic parameters. Needed for camera pose }" "{c | | Camera intrinsic parameters. Needed for camera pose }"
"{l | 0.1 | Marker side length (in meters). Needed for correct scale in camera pose }" "{l | 0.1 | Marker side length (in meters). Needed for correct scale in camera pose }"
@@ -61,53 +65,8 @@ const char* keys =
"{refine | | Corner refinement: CORNER_REFINE_NONE=0, CORNER_REFINE_SUBPIX=1," "{refine | | Corner refinement: CORNER_REFINE_NONE=0, CORNER_REFINE_SUBPIX=1,"
"CORNER_REFINE_CONTOUR=2, CORNER_REFINE_APRILTAG=3}"; "CORNER_REFINE_CONTOUR=2, CORNER_REFINE_APRILTAG=3}";
} }
//! [aruco_detect_markers_keys]
/**
*/
static bool readCameraParameters(string filename, Mat &camMatrix, Mat &distCoeffs) {
FileStorage fs(filename, FileStorage::READ);
if(!fs.isOpened())
return false;
fs["camera_matrix"] >> camMatrix;
fs["distortion_coefficients"] >> distCoeffs;
return true;
}
/**
*/
static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
FileStorage fs(filename, FileStorage::READ);
if(!fs.isOpened())
return false;
fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
fs["minDistanceToBorder"] >> params->minDistanceToBorder;
fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
fs["cornerRefinementMethod"] >> params->cornerRefinementMethod;
fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
fs["markerBorderBits"] >> params->markerBorderBits;
fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
fs["minOtsuStdDev"] >> params->minOtsuStdDev;
fs["errorCorrectionRate"] >> params->errorCorrectionRate;
return true;
}
/**
*/
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CommandLineParser parser(argc, argv, keys); CommandLineParser parser(argc, argv, keys);
parser.about(about); parser.about(about);
@@ -117,14 +76,14 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
int dictionaryId = parser.get<int>("d");
bool showRejected = parser.has("r"); bool showRejected = parser.has("r");
bool estimatePose = parser.has("c"); bool estimatePose = parser.has("c");
float markerLength = parser.get<float>("l"); float markerLength = parser.get<float>("l");
Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create(); Ptr<aruco::DetectorParameters> detectorParams;
if(parser.has("dp")) { if(parser.has("dp")) {
bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams); FileStorage fs(parser.get<string>("dp"), FileStorage::READ);
bool readOk = aruco::DetectorParameters::readDetectorParameters(fs.root(), detectorParams);
if(!readOk) { if(!readOk) {
cerr << "Invalid detector parameters file" << endl; cerr << "Invalid detector parameters file" << endl;
return 0; return 0;
@@ -149,8 +108,23 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
Ptr<aruco::Dictionary> dictionary = Ptr<aruco::Dictionary> dictionary;
aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId)); if (parser.has("d")) {
int dictionaryId = parser.get<int>("d");
dictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
}
else if (parser.has("cd")) {
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ);
bool readOk = aruco::Dictionary::readDictionary(fs.root(), dictionary);
if(!readOk) {
std::cerr << "Invalid dictionary file" << std::endl;
return 0;
}
}
else {
std::cerr << "Dictionary not specified" << std::endl;
return 0;
}
Mat camMatrix, distCoeffs; Mat camMatrix, distCoeffs;
if(estimatePose) { if(estimatePose) {

View File

@@ -1,5 +1,4 @@
%YAML:1.0 %YAML:1.0
nmarkers: 1024
adaptiveThreshWinSizeMin: 3 adaptiveThreshWinSizeMin: 3
adaptiveThreshWinSizeMax: 23 adaptiveThreshWinSizeMax: 23
adaptiveThreshWinSizeStep: 10 adaptiveThreshWinSizeStep: 10

View File

@@ -0,0 +1,21 @@
%YAML:1.0
---
calibration_time: "Wed 08 Dec 2021 05:13:09 PM MSK"
image_width: 640
image_height: 480
flags: 0
camera_matrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ 4.5251072219637672e+02, 0., 3.1770297317353277e+02, 0.,
4.5676707935146891e+02, 2.7775155919135995e+02, 0., 0., 1. ]
distortion_coefficients: !!opencv-matrix
rows: 1
cols: 5
dt: d
data: [ 1.2136925618707872e-01, -1.0854664722560681e+00,
1.1786843796668460e-04, -4.6240686046485508e-04,
2.9542589406810080e+00 ]
avg_reprojection_error: 1.8234905535936044e-01
info: "The camera calibration parameters were obtained by img_00.jpg-img_03.jpg from aruco/tutorials/aruco_calibration/images"

View File

@@ -0,0 +1,14 @@
%YAML:1.0
camera_matrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ 628.158, 0., 324.099,
0., 628.156, 260.908,
0., 0., 1. ]
distortion_coefficients: !!opencv-matrix
rows: 5
cols: 1
dt: d
data: [ 0.0995485, -0.206384,
0.00754589, 0.00336531, 0 ]

View File

@@ -4,27 +4,14 @@
#include <opencv2/highgui.hpp> #include <opencv2/highgui.hpp>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include "aruco_samples_utility.hpp"
namespace { namespace {
const char* about = "A tutorial code on charuco board creation and detection of charuco board with and without camera caliberation"; const char* about = "A tutorial code on charuco board creation and detection of charuco board with and without camera caliberation";
const char* keys = "{c | | Put value of c=1 to create charuco board;\nc=2 to detect charuco board without camera calibration;\nc=3 to detect charuco board with camera calibration and Pose Estimation}"; const char* keys = "{c | | Put value of c=1 to create charuco board;\nc=2 to detect charuco board without camera calibration;\nc=3 to detect charuco board with camera calibration and Pose Estimation}";
} }
void createBoard(); static inline void createBoard()
void detectCharucoBoardWithCalibrationPose();
void detectCharucoBoardWithoutCalibration();
static bool readCameraParameters(std::string filename, cv::Mat& camMatrix, cv::Mat& distCoeffs)
{
cv::FileStorage fs(filename, cv::FileStorage::READ);
if (!fs.isOpened())
return false;
fs["camera_matrix"] >> camMatrix;
fs["distortion_coefficients"] >> distCoeffs;
return (camMatrix.size() == cv::Size(3,3)) ;
}
void createBoard()
{ {
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
//! [createBoard] //! [createBoard]
@@ -36,7 +23,7 @@ void createBoard()
} }
//! [detwcp] //! [detwcp]
void detectCharucoBoardWithCalibrationPose() static inline void detectCharucoBoardWithCalibrationPose()
{ {
cv::VideoCapture inputVideo; cv::VideoCapture inputVideo;
inputVideo.open(0); inputVideo.open(0);
@@ -81,9 +68,8 @@ void detectCharucoBoardWithCalibrationPose()
//! [detcor] //! [detcor]
cv::Vec3d rvec, tvec; cv::Vec3d rvec, tvec;
//! [pose] //! [pose]
// cv::aruco::estimatePoseCharucoBoard(charucoCorners, charucoIds, board, cameraMatrix, distCoeffs, rvec, tvec);
//! [pose]
bool valid = cv::aruco::estimatePoseCharucoBoard(charucoCorners, charucoIds, board, cameraMatrix, distCoeffs, rvec, tvec); bool valid = cv::aruco::estimatePoseCharucoBoard(charucoCorners, charucoIds, board, cameraMatrix, distCoeffs, rvec, tvec);
//! [pose]
// if charuco pose is valid // if charuco pose is valid
if (valid) if (valid)
cv::aruco::drawAxis(imageCopy, cameraMatrix, distCoeffs, rvec, tvec, 0.1f); cv::aruco::drawAxis(imageCopy, cameraMatrix, distCoeffs, rvec, tvec, 0.1f);
@@ -99,7 +85,7 @@ void detectCharucoBoardWithCalibrationPose()
//! [detwcp] //! [detwcp]
//! [detwc] //! [detwc]
void detectCharucoBoardWithoutCalibration() static inline void detectCharucoBoardWithoutCalibration()
{ {
cv::VideoCapture inputVideo; cv::VideoCapture inputVideo;
inputVideo.open(0); inputVideo.open(0);

View File

@@ -0,0 +1,38 @@
%YAML:1.0
nmarkers: 35
markersize: 6
marker_0: "101011111011111001001001101100000000"
marker_1: "000000000010011001010011111010111000"
marker_2: "011001100000001010000101111101001101"
marker_3: "001000111111000111011001110000011111"
marker_4: "100110110100101111000000111101110011"
marker_5: "010101101110111000111010111100010111"
marker_6: "101001000110011110101001010100110100"
marker_7: "011010100100110000011101110110100010"
marker_8: "111110001000101000110001010010111101"
marker_9: "011101101100110111001100100001010100"
marker_10: "100001100001010001110001011000000111"
marker_11: "110010010010011100101111111000001111"
marker_12: "110101001001010110011111010110001101"
marker_13: "001111000001000100010001101001010001"
marker_14: "000000010010101010111110110011010011"
marker_15: "110001110111100101110011111100111010"
marker_16: "101011001110001010110011111011001110"
marker_17: "101110111101110100101101011001010111"
marker_18: "000100111000111101010011010101000101"
marker_19: "001110001110001101100101110100000011"
marker_20: "100101101100010110110110110001100011"
marker_21: "010110001001011010000100111000110110"
marker_22: "001000000000100100000000010100010010"
marker_23: "101001110010100110000111111010010000"
marker_24: "111001101010001100011010010001011100"
marker_25: "101000010001010000110100111101101001"
marker_26: "101010000001010011001010110110000001"
marker_27: "100101001000010101001000111101111110"
marker_28: "010010100110010011110001110101011100"
marker_29: "011001000101100001101111010001001111"
marker_30: "000111011100011110001101111011011001"
marker_31: "010100001011000100111101110001101010"
marker_32: "100101101001101010111111101101110100"
marker_33: "101101001010111000000100110111010101"
marker_34: "011111010000111011111110110101100101"

View File

@@ -98,6 +98,48 @@ Ptr<DetectorParameters> DetectorParameters::create() {
return params; return params;
} }
template<typename T>
static inline bool readParameter(const FileNode& node, T& parameter)
{
if (!node.empty()) {
node >> parameter;
return true;
}
return false;
}
/**
* @brief Read a new set of DetectorParameters from FileStorage.
*/
bool DetectorParameters::readDetectorParameters(const FileNode& fn, Ptr<DetectorParameters>& params)
{
if(fn.empty())
return true;
params = DetectorParameters::create();
bool checkRead = false;
checkRead |= readParameter(fn["adaptiveThreshWinSizeMin"], params->adaptiveThreshWinSizeMin);
checkRead |= readParameter(fn["adaptiveThreshWinSizeMax"], params->adaptiveThreshWinSizeMax);
checkRead |= readParameter(fn["adaptiveThreshWinSizeStep"], params->adaptiveThreshWinSizeStep);
checkRead |= readParameter(fn["adaptiveThreshConstant"], params->adaptiveThreshConstant);
checkRead |= readParameter(fn["minMarkerPerimeterRate"], params->minMarkerPerimeterRate);
checkRead |= readParameter(fn["maxMarkerPerimeterRate"], params->maxMarkerPerimeterRate);
checkRead |= readParameter(fn["polygonalApproxAccuracyRate"], params->polygonalApproxAccuracyRate);
checkRead |= readParameter(fn["minCornerDistanceRate"], params->minCornerDistanceRate);
checkRead |= readParameter(fn["minDistanceToBorder"], params->minDistanceToBorder);
checkRead |= readParameter(fn["minMarkerDistanceRate"], params->minMarkerDistanceRate);
checkRead |= readParameter(fn["cornerRefinementMethod"], params->cornerRefinementMethod);
checkRead |= readParameter(fn["cornerRefinementWinSize"], params->cornerRefinementWinSize);
checkRead |= readParameter(fn["cornerRefinementMaxIterations"], params->cornerRefinementMaxIterations);
checkRead |= readParameter(fn["cornerRefinementMinAccuracy"], params->cornerRefinementMinAccuracy);
checkRead |= readParameter(fn["markerBorderBits"], params->markerBorderBits);
checkRead |= readParameter(fn["perspectiveRemovePixelPerCell"], params->perspectiveRemovePixelPerCell);
checkRead |= readParameter(fn["perspectiveRemoveIgnoredMarginPerCell"], params->perspectiveRemoveIgnoredMarginPerCell);
checkRead |= readParameter(fn["maxErroneousBitsInBorderRate"], params->maxErroneousBitsInBorderRate);
checkRead |= readParameter(fn["minOtsuStdDev"], params->minOtsuStdDev);
checkRead |= readParameter(fn["errorCorrectionRate"], params->errorCorrectionRate);
return checkRead;
}
/** /**
* @brief Convert input image to gray if it is a 3-channels image * @brief Convert input image to gray if it is a 3-channels image

View File

@@ -84,6 +84,36 @@ Ptr<Dictionary> Dictionary::create(int nMarkers, int markerSize,
return generateCustomDictionary(nMarkers, markerSize, baseDictionary, randomSeed); return generateCustomDictionary(nMarkers, markerSize, baseDictionary, randomSeed);
} }
template<typename T>
static inline bool readParameter(const FileNode& node, T& parameter)
{
if (!node.empty()) {
node >> parameter;
return true;
}
return false;
}
bool Dictionary::readDictionary(const cv::FileNode& fn, cv::Ptr<cv::aruco::Dictionary> &dictionary)
{
int nMarkers = 0, markerSize = 0;
if(fn.empty() || !readParameter(fn["nmarkers"], nMarkers) || !readParameter(fn["markersize"], markerSize))
return false;
cv::Mat bytes(0, 0, CV_8UC1), marker(markerSize, markerSize, CV_8UC1);
std::string markerString;
for (int i = 0; i < nMarkers; i++) {
std::ostringstream ostr;
ostr << i;
if (!readParameter(fn["marker_" + ostr.str()], markerString))
return false;
for (int j = 0; j < (int) markerString.size(); j++)
marker.at<unsigned char>(j) = (markerString[j] == '0') ? 0 : 1;
bytes.push_back(cv::aruco::Dictionary::getByteListFromBits(marker));
}
dictionary = cv::makePtr<cv::aruco::Dictionary>(bytes, markerSize);
return true;
}
/** /**
*/ */

View File

@@ -36,8 +36,8 @@ or tort (including negligence or otherwise) arising in any way out of
the use of this software, even if advised of the possibility of such damage. the use of this software, even if advised of the possibility of such damage.
*/ */
#include "test_precomp.hpp" #include "test_precomp.hpp"
#include <opencv2/core/utils/logger.defines.hpp>
namespace opencv_test { namespace { namespace opencv_test { namespace {
@@ -554,4 +554,94 @@ TEST(CV_ArucoBitCorrection, algorithmic) {
test.safe_run(); test.safe_run();
} }
TEST(CV_ArucoTutorial, can_find_singlemarkersoriginal)
{
string img_path = cvtest::findDataFile("singlemarkersoriginal.jpg", false);
Mat image = imread(img_path);
Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
vector< int > ids;
vector< vector< Point2f > > corners, rejected;
const size_t N = 6ull;
// corners of ArUco markers with indices goldCornersIds
const int goldCorners[N][8] = { {359,310, 404,310, 410,350, 362,350}, {427,255, 469,256, 477,289, 434,288},
{233,273, 190,273, 196,241, 237,241}, {298,185, 334,186, 335,212, 297,211},
{425,163, 430,186, 394,186, 390,162}, {195,155, 230,155, 227,178, 190,178} };
const int goldCornersIds[N] = { 40, 98, 62, 23, 124, 203};
map<int, const int*> mapGoldCorners;
for (size_t i = 0; i < N; i++)
mapGoldCorners[goldCornersIds[i]] = goldCorners[i];
aruco::detectMarkers(image, dictionary, corners, ids, detectorParams, rejected);
ASSERT_EQ(N, ids.size());
for (size_t i = 0; i < N; i++)
{
int arucoId = ids[i];
ASSERT_EQ(4ull, corners[i].size());
ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end());
for (int j = 0; j < 4; j++)
{
EXPECT_NEAR(static_cast<float>(mapGoldCorners[arucoId][j * 2]), corners[i][j].x, 1.f);
EXPECT_NEAR(static_cast<float>(mapGoldCorners[arucoId][j * 2 + 1]), corners[i][j].y, 1.f);
}
}
}
TEST(CV_ArucoTutorial, can_find_gboriginal)
{
string imgPath = cvtest::findDataFile("gboriginal.png", false);
Mat image = imread(imgPath);
string dictPath = cvtest::findDataFile("tutorial_dict.yml", false);
cv::Ptr<cv::aruco::Dictionary> dictionary;
FileStorage fs(dictPath, FileStorage::READ);
aruco::Dictionary::readDictionary(fs.root(), dictionary); // set marker from tutorial_dict.yml
Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
vector< int > ids;
vector< vector< Point2f > > corners, rejected;
const size_t N = 35ull;
// corners of ArUco markers with indices 0, 1, ..., 34
const int goldCorners[N][8] = { {252,74, 286,81, 274,102, 238,95}, {295,82, 330,89, 319,111, 282,104},
{338,91, 375,99, 365,121, 327,113}, {383,100, 421,107, 412,130, 374,123},
{429,109, 468,116, 461,139, 421,132}, {235,100, 270,108, 257,130, 220,122},
{279,109, 316,117, 304,140, 266,133}, {324,119, 362,126, 352,150, 313,143},
{371,128, 410,136, 400,161, 360,152}, {418,139, 459,145, 451,170, 410,163},
{216,128, 253,136, 239,161, 200,152}, {262,138, 300,146, 287,172, 248,164},
{309,148, 349,156, 337,183, 296,174}, {358,158, 398,167, 388,194, 346,185},
{407,169, 449,176, 440,205, 397,196}, {196,158, 235,168, 218,195, 179,185},
{243,170, 283,178, 269,206, 228,197}, {293,180, 334,190, 321,218, 279,209},
{343,192, 385,200, 374,230, 330,220}, {395,203, 438,211, 429,241, 384,233},
{174,192, 215,201, 197,231, 156,221}, {223,204, 265,213, 249,244, 207,234},
{275,215, 317,225, 303,257, 259,246}, {327,227, 371,238, 359,270, 313,259},
{381,240, 426,249, 416,282, 369,273}, {151,228, 193,238, 173,271, 130,260},
{202,241, 245,251, 228,285, 183,274}, {255,254, 300,264, 284,299, 238,288},
{310,267, 355,278, 342,314, 295,302}, {366,281, 413,290, 402,327, 353,317},
{125,267, 168,278, 147,314, 102,303}, {178,281, 223,293, 204,330, 157,317},
{233,296, 280,307, 263,346, 214,333}, {291,310, 338,322, 323,363, 274,349},
{349,325, 399,336, 386,378, 335,366} };
map<int, const int*> mapGoldCorners;
for (int i = 0; i < static_cast<int>(N); i++)
mapGoldCorners[i] = goldCorners[i];
aruco::detectMarkers(image, dictionary, corners, ids, detectorParams, rejected);
ASSERT_EQ(N, ids.size());
for (size_t i = 0; i < N; i++)
{
int arucoId = ids[i];
ASSERT_EQ(4ull, corners[i].size());
ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end());
for (int j = 0; j < 4; j++)
{
EXPECT_NEAR(static_cast<float>(mapGoldCorners[arucoId][j*2]), corners[i][j].x, 1.f);
EXPECT_NEAR(static_cast<float>(mapGoldCorners[arucoId][j*2+1]), corners[i][j].y, 1.f);
}
}
}
}} // namespace }} // namespace

View File

@@ -677,4 +677,120 @@ TEST(Charuco, testCharucoCornersCollinear_false)
EXPECT_FALSE(result); EXPECT_FALSE(result);
} }
TEST(CV_ArucoTutorial, can_find_choriginal)
{
string imgPath = cvtest::findDataFile("choriginal.jpg", false);
Mat image = imread(imgPath);
cv::Ptr<cv::aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
vector< int > ids;
vector< vector< Point2f > > corners, rejected;
const size_t N = 17ull;
// corners of aruco markers with indices goldCornersIds
const int goldCorners[N][8] = { {268,77, 290,80, 286,97, 263,94}, {360,90, 382,93, 379,111, 357,108},
{211,106, 233,109, 228,127, 205,123}, {306,120, 328,124, 325,142, 302,138},
{402,135, 425,139, 423,157, 400,154}, {247,152, 271,155, 267,174, 242,171},
{347,167, 371,171, 369,191, 344,187}, {185,185, 209,189, 203,210, 178,206},
{288,201, 313,206, 309,227, 284,223}, {393,218, 418,222, 416,245, 391,241},
{223,240, 250,244, 244,268, 217,263}, {333,258, 359,262, 356,286, 329,282},
{152,281, 179,285, 171,312, 143,307}, {267,300, 294,305, 289,331, 261,327},
{383,319, 410,324, 408,351, 380,347}, {194,347, 223,352, 216,382, 186,377},
{315,368, 345,373, 341,403, 310,398} };
map<int, const int*> mapGoldCorners;
for (int i = 0; i < static_cast<int>(N); i++)
mapGoldCorners[i] = goldCorners[i];
aruco::detectMarkers(image, dictionary, corners, ids, detectorParams, rejected);
ASSERT_EQ(N, ids.size());
for (size_t i = 0; i < N; i++)
{
int arucoId = ids[i];
ASSERT_EQ(4ull, corners[i].size());
ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end());
for (int j = 0; j < 4; j++)
{
EXPECT_NEAR(static_cast<float>(mapGoldCorners[arucoId][j * 2]), corners[i][j].x, 1.f);
EXPECT_NEAR(static_cast<float>(mapGoldCorners[arucoId][j * 2 + 1]), corners[i][j].y, 1.f);
}
}
}
TEST(CV_ArucoTutorial, can_find_chocclusion)
{
string imgPath = cvtest::findDataFile("chocclusion_original.jpg", false);
Mat image = imread(imgPath);
cv::Ptr<cv::aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
vector< int > ids;
vector< vector< Point2f > > corners, rejected;
const size_t N = 13ull;
// corners of aruco markers with indices goldCornersIds
const int goldCorners[N][8] = { {301,57, 322,62, 317,79, 295,73}, {391,80, 413,85, 408,103, 386,97},
{242,79, 264,85, 256,102, 234,96}, {334,103, 357,109, 352,126, 329,121},
{428,129, 451,134, 448,152, 425,146}, {274,128, 296,134, 290,153, 266,147},
{371,154, 394,160, 390,180, 366,174}, {208,155, 232,161, 223,181, 199,175},
{309,182, 333,188, 327,209, 302,203}, {411,210, 436,216, 432,238, 407,231},
{241,212, 267,219, 258,242, 232,235}, {167,244, 194,252, 183,277, 156,269},
{202,314, 230,322, 220,349, 191,341} };
map<int, const int*> mapGoldCorners;
const int goldCornersIds[N] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15};
for (int i = 0; i < static_cast<int>(N); i++)
mapGoldCorners[goldCornersIds[i]] = goldCorners[i];
aruco::detectMarkers(image, dictionary, corners, ids, detectorParams, rejected);
ASSERT_EQ(N, ids.size());
for (size_t i = 0; i < N; i++)
{
int arucoId = ids[i];
ASSERT_EQ(4ull, corners[i].size());
ASSERT_TRUE(mapGoldCorners.find(arucoId) != mapGoldCorners.end());
for (int j = 0; j < 4; j++)
{
EXPECT_NEAR(static_cast<float>(mapGoldCorners[arucoId][j * 2]), corners[i][j].x, 1.f);
EXPECT_NEAR(static_cast<float>(mapGoldCorners[arucoId][j * 2 + 1]), corners[i][j].y, 1.f);
}
}
}
TEST(CV_ArucoTutorial, can_find_diamondmarkers)
{
string imgPath = cvtest::findDataFile("diamondmarkers.png", false);
Mat image = imread(imgPath);
string dictPath = cvtest::findDataFile("tutorial_dict.yml", false);
cv::Ptr<cv::aruco::Dictionary> dictionary;
FileStorage fs(dictPath, FileStorage::READ);
aruco::Dictionary::readDictionary(fs.root(), dictionary); // set marker from tutorial_dict.yml
string detectorPath = cvtest::findDataFile("detector_params.yml", false);
fs = FileStorage(detectorPath, FileStorage::READ);
Ptr<aruco::DetectorParameters> detectorParams;
aruco::DetectorParameters::readDetectorParameters(fs.root(), detectorParams);
detectorParams->cornerRefinementMethod = 3;
vector< int > ids;
vector< vector< Point2f > > corners, rejected;
const size_t N = 12ull;
// corner indices of ArUco markers
const int goldCornersIds[N] = { 4, 12, 11, 3, 12, 10, 12, 10, 10, 11, 2, 11 };
map<int, int> counterGoldCornersIds;
for (int i = 0; i < static_cast<int>(N); i++)
counterGoldCornersIds[goldCornersIds[i]]++;
aruco::detectMarkers(image, dictionary, corners, ids, detectorParams, rejected);
map<int, int> counterRes;
for (size_t i = 0; i < N; i++)
{
int arucoId = ids[i];
counterRes[arucoId]++;
}
ASSERT_EQ(N, ids.size());
EXPECT_EQ(counterGoldCornersIds, counterRes); // check the number of ArUco markers
}
}} // namespace }} // namespace

View File

@@ -3,4 +3,6 @@
// of this distribution and at http://opencv.org/license.html. // of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp" #include "test_precomp.hpp"
CV_TEST_MAIN("cv") CV_TEST_MAIN("cv",
cvtest::addDataSearchSubDirectory("contrib/aruco")
)

View File

@@ -1,6 +1,9 @@
Detection of ArUco Boards {#tutorial_aruco_board_detection} Detection of ArUco Boards {#tutorial_aruco_board_detection}
============================== ==============================
@prev_tutorial{tutorial_aruco_detection}
@next_tutorial{tutorial_charuco_detection}
An ArUco Board is a set of markers that acts like a single marker in the sense that it provides a An ArUco Board is a set of markers that acts like a single marker in the sense that it provides a
single pose for the camera. single pose for the camera.
@@ -55,7 +58,8 @@ The aruco module provides a specific function, ```estimatePoseBoard()```, to per
cv::Mat inputImage; cv::Mat inputImage;
// camera parameters are read from somewhere // camera parameters are read from somewhere
cv::Mat cameraMatrix, distCoeffs; cv::Mat cameraMatrix, distCoeffs;
readCameraParameters(cameraMatrix, distCoeffs); // You can read camera parameters from tutorial_camera_params.yml
readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_board.cpp
// assume we have a function to create the board object // assume we have a function to create the board object
cv::Ptr<cv::aruco::Board> board = cv::aruco::Board::create(); cv::Ptr<cv::aruco::Board> board = cv::aruco::Board::create();
... ...
@@ -153,11 +157,11 @@ The output image will be something like this:
![](images/board.jpg) ![](images/board.jpg)
A full working example of board creation is included in the ```create_board.cpp``` inside the module samples folder. A full working example of board creation is included in the `create_board.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
@code{.cpp} @code{.cpp}
"_output path_/aboard.png" -w=5 -h=7 -l=100 -s=10 -d=10 "_output_path_/aboard.png" -w=5 -h=7 -l=100 -s=10 -d=10
@endcode @endcode
Finally, a full example of board detection: Finally, a full example of board detection:
@@ -167,10 +171,12 @@ Finally, a full example of board detection:
inputVideo.open(0); inputVideo.open(0);
cv::Mat cameraMatrix, distCoeffs; cv::Mat cameraMatrix, distCoeffs;
// camera parameters are read from somewhere // You can read camera parameters from tutorial_camera_params.yml
readCameraParameters(cameraMatrix, distCoeffs); readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_board.cpp
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
// To use tutorial sample, you need read custome dictionaty from tutorial_dict.yml
readDictionary(filename, dictionary); // This function is located in detect_board.cpp
cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary); cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
while (inputVideo.grab()) { while (inputVideo.grab()) {
@@ -207,14 +213,20 @@ Sample video:
<iframe width="420" height="315" src="https://www.youtube.com/embed/Q1HlJEjW_j0" frameborder="0" allowfullscreen></iframe> <iframe width="420" height="315" src="https://www.youtube.com/embed/Q1HlJEjW_j0" frameborder="0" allowfullscreen></iframe>
@endhtmlonly @endhtmlonly
A full working example is included in the ```detect_board.cpp``` inside the module samples folder. A full working example is included in the `detect_board.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
@code{.cpp} @code{.cpp}
-c="_path_"/calib.txt" "_path_/aboard.png" -w=5 -h=7 -l=100 -s=10 -d=10 -w=5 -h=7 -l=100 -s=10
-v=/path_to_aruco_tutorials/aruco_board_detection/images/gboriginal.png
-c=/path_to_aruco_samples/tutorial_camera_params.yml
-cd=/path_to_aruco_samples/tutorial_dict.yml
@endcode @endcode
Parameters for `detect_board.cpp`:
@snippet samples/detect_board.cpp aruco_detect_board_keys
@note To work with examples from the tutorial, you can use camera parameters from `tutorial_camera_params.yml` and
you need use custom dictionary from `tutorial_dict.yml`.
An example of usage in `detect_board.cpp`.
Refine marker detection Refine marker detection
----- -----

View File

@@ -1,6 +1,9 @@
Calibration with ArUco and ChArUco {#tutorial_aruco_calibration} Calibration with ArUco and ChArUco {#tutorial_aruco_calibration}
============================== ==============================
@prev_tutorial{tutorial_charuco_diamond_detection}
@next_tutorial{tutorial_aruco_faq}
The ArUco module can also be used to calibrate a camera. Camera calibration consists in obtaining the The ArUco module can also be used to calibrate a camera. Camera calibration consists in obtaining the
camera intrinsic parameters and distortion coefficients. This parameters remain fixed unless the camera camera intrinsic parameters and distortion coefficients. This parameters remain fixed unless the camera
optic is modified, thus camera calibration only need to be done once. optic is modified, thus camera calibration only need to be done once.
@@ -59,14 +62,16 @@ in each of the viewpoints.
Finally, the ```calibrationFlags``` parameter determines some of the options for the calibration. Its format is equivalent to the flags parameter in the OpenCV Finally, the ```calibrationFlags``` parameter determines some of the options for the calibration. Its format is equivalent to the flags parameter in the OpenCV
```calibrateCamera()``` function. ```calibrateCamera()``` function.
A full working example is included in the ```calibrate_camera_charuco.cpp``` inside the module samples folder. A full working example is included in the `calibrate_camera_charuco.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
@code{.cpp} @code{.cpp}
_output path_" -dp="_path_/detector_params.yml" -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10 "output_path/camera_calib.txt" -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10
-v="path_aruco/tutorials/aruco_calibration/images/img_%02d.jpg
-c=path_aruco/samples/tutorial_camera_params.yml
@endcode @endcode
The camera calibration parameters from `samples/tutorial_camera_charuco.yml` were obtained by `aruco_calibration/images/img_00.jpg-img_03.jpg`.
Calibration with ArUco Boards Calibration with ArUco Boards
------ ------
@@ -104,7 +109,7 @@ In this case, and contrary to the ```calibrateCameraCharuco()``` function, the d
The rest of parameters are the same than in ```calibrateCameraCharuco()```, except the board layout object which does not need to be a ```CharucoBoard``` object, it can be The rest of parameters are the same than in ```calibrateCameraCharuco()```, except the board layout object which does not need to be a ```CharucoBoard``` object, it can be
any ```Board``` object. any ```Board``` object.
A full working example is included in the ```calibrate_camera.cpp``` inside the module samples folder. A full working example is included in the `calibrate_camera.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
@code{.cpp} @code{.cpp}

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View File

@@ -1,6 +1,8 @@
Detection of ArUco Markers {#tutorial_aruco_detection} Detection of ArUco Markers {#tutorial_aruco_detection}
============================== ==============================
@next_tutorial{tutorial_aruco_board_detection}
Pose estimation is of great importance in many computer vision applications: robot navigation, Pose estimation is of great importance in many computer vision applications: robot navigation,
augmented reality, and many more. This process is based on finding correspondences between points in augmented reality, and many more. This process is based on finding correspondences between points in
the real environment and their 2d image projection. This is usually a difficult step, and thus it is the real environment and their 2d image projection. This is usually a difficult step, and thus it is
@@ -102,12 +104,14 @@ The generated image is:
![Generated marker](images/marker23.png) ![Generated marker](images/marker23.png)
A full working example is included in the `create_marker.cpp` inside the module samples folder. A full working example is included in the `create_marker.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input from the command line using cv::CommandLineParser. For this file the example parameters will look like Note: The samples now take input from the command line using cv::CommandLineParser. For this file the example parameters will look like:
@code{.cpp} @code{.cpp}
"marker23.png" -d=10 -id=23 "marker23.png" -d=10 -id=23
@endcode @endcode
Parameters for `create_marker.cpp`:
@snippet samples/create_marker.cpp aruco_create_markers_keys
Marker Detection Marker Detection
------ ------
@@ -231,13 +235,14 @@ while (inputVideo.grab()) {
Note that some of the optional parameters have been omitted, like the detection parameter object and the Note that some of the optional parameters have been omitted, like the detection parameter object and the
output vector of rejected candidates. output vector of rejected candidates.
A full working example is included in the `detect_markers.cpp` inside the module samples folder. A full working example is included in the `detect_markers.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input from the command line using cv::CommandLineParser. For this file the example parameters will look like Note: The samples now take input from the command line using cv::CommandLineParser. For this file the example parameters will look like
@code{.cpp} @code{.cpp}
-c="_path_/calib.txt" -d=10 -v=/path_to_aruco_tutorials/aruco_detection/images/singlemarkersoriginal.jpg -d=10
@endcode @endcode
Parameters for `detect_markers.cpp`:
@snippet samples/detect_markers.cpp aruco_detect_markers_keys
Pose Estimation Pose Estimation
@@ -267,7 +272,9 @@ The aruco module provides a function to estimate the poses of all the detected m
@code{.cpp} @code{.cpp}
cv::Mat cameraMatrix, distCoeffs; cv::Mat cameraMatrix, distCoeffs;
... // You can read camera parameters from tutorial_camera_params.yml
readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_markers.cpp
std::vector<cv::Vec3d> rvecs, tvecs; std::vector<cv::Vec3d> rvecs, tvecs;
cv::aruco::estimatePoseSingleMarkers(markerCorners, 0.05, cameraMatrix, distCoeffs, rvecs, tvecs); cv::aruco::estimatePoseSingleMarkers(markerCorners, 0.05, cameraMatrix, distCoeffs, rvecs, tvecs);
@endcode @endcode
@@ -308,8 +315,8 @@ cv::VideoCapture inputVideo;
inputVideo.open(0); inputVideo.open(0);
cv::Mat cameraMatrix, distCoeffs; cv::Mat cameraMatrix, distCoeffs;
// camera parameters are read from somewhere // You can read camera parameters from tutorial_camera_params.yml
readCameraParameters(cameraMatrix, distCoeffs); readCameraParameters(filename, cameraMatrix, distCoeffs); // This function is located in detect_markers.cpp
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
@@ -346,12 +353,17 @@ Sample video:
<iframe width="420" height="315" src="https://www.youtube.com/embed/IsXWrcB_Hvs" frameborder="0" allowfullscreen></iframe> <iframe width="420" height="315" src="https://www.youtube.com/embed/IsXWrcB_Hvs" frameborder="0" allowfullscreen></iframe>
@endhtmlonly @endhtmlonly
A full working example is included in the `detect_markers.cpp` inside the module samples folder. A full working example is included in the `detect_markers.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input from the command line using cv::CommandLineParser. For this file the example parameters will look like Note: The samples now take input from the command line using cv::CommandLineParser. For this file the example parameters will look like
@code{.cpp} @code{.cpp}
-c="_path_/calib.txt" -d=10 -v=/path_to_aruco_tutorials/aruco_detection/images/singlemarkersoriginal.jpg -d=10
-c=/path_to_aruco_samples/tutorial_camera_params.yml
@endcode @endcode
Parameters for `detect_markers.cpp`:
@snippet samples/detect_markers.cpp aruco_detect_markers_keys
@note To work with examples from the tutorial, you can use camera parameters from `tutorial_camera_params.yml`.
An example of use in `detect.cpp`.
@@ -766,4 +778,4 @@ too low, it can produce a poor subpixel refinement.
Default values: Default values:
- `int cornerRefinementMaxIterations = 30` - `int cornerRefinementMaxIterations = 30`
- `double cornerRefinementMinAccuracy = 0.1` - `double cornerRefinementMinAccuracy = 0.1`

View File

@@ -1,6 +1,8 @@
Aruco module FAQ {#tutorial_aruco_faq} Aruco module FAQ {#tutorial_aruco_faq}
============================== ==============================
@prev_tutorial{tutorial_aruco_calibration}
This is a compilation of questions that can be useful for those that want to use the aruco module. This is a compilation of questions that can be useful for those that want to use the aruco module.
- I only want to label some objects, what should I use? - I only want to label some objects, what should I use?

View File

@@ -1,6 +1,9 @@
Detection of ChArUco Corners {#tutorial_charuco_detection} Detection of ChArUco Boards {#tutorial_charuco_detection}
============================== ==============================
@prev_tutorial{tutorial_aruco_board_detection}
@next_tutorial{tutorial_charuco_diamond_detection}
ArUco markers and boards are very useful due to their fast detection and their versatility. ArUco markers and boards are very useful due to their fast detection and their versatility.
However, one of the problems of ArUco markers is that the accuracy of their corner positions is not too high, However, one of the problems of ArUco markers is that the accuracy of their corner positions is not too high,
even after applying subpixel refinement. even after applying subpixel refinement.
@@ -87,11 +90,11 @@ The output image will be something like this:
![](images/charucoboard.jpg) ![](images/charucoboard.jpg)
A full working example is included in the ```create_board_charuco.cpp``` inside the modules/aruco/samples/create_board_charuco.cpp. A full working example is included in the `create_board_charuco.cpp` inside the `modules/aruco/samples/`.
Note: The create_board_charuco.cpp now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like Note: The create_board_charuco.cpp now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
@code{.cpp} @code{.cpp}
"_ output path_/chboard.png" -w=5 -h=7 -sl=200 -ml=120 -d=10 "_output_path_/chboard.png" -w=5 -h=7 -sl=200 -ml=120 -d=10
@endcode @endcode
@@ -180,15 +183,15 @@ This can be easily done using the ```drawDetectedCornersCharuco()``` function:
For this image: For this image:
![Image with Charuco board](images/choriginal.png) ![Image with Charuco board](images/choriginal.jpg)
The result will be: The result will be:
![Charuco board detected](images/chcorners.png) ![Charuco board detected](images/chcorners.jpg)
In the presence of occlusion. like in the following image, although some corners are clearly visible, not all their surrounding markers have been detected due occlusion and, thus, they are not interpolated: In the presence of occlusion. like in the following image, although some corners are clearly visible, not all their surrounding markers have been detected due occlusion and, thus, they are not interpolated:
![Charuco detection with occlusion](images/chocclusion.png) ![Charuco detection with occlusion](images/chocclusion.jpg)
Finally, this is a full example of ChArUco detection (without using calibration parameters): Finally, this is a full example of ChArUco detection (without using calibration parameters):
@@ -200,15 +203,14 @@ Sample video:
<iframe width="420" height="315" src="https://www.youtube.com/embed/Nj44m_N_9FY" frameborder="0" allowfullscreen></iframe> <iframe width="420" height="315" src="https://www.youtube.com/embed/Nj44m_N_9FY" frameborder="0" allowfullscreen></iframe>
@endhtmlonly @endhtmlonly
A full working example is included in the ```detect_board_charuco.cpp``` inside the modules/aruco/samples/detect_board_charuco.cpp. A full working example is included in the `detect_board_charuco.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
@code{.cpp} @code{.cpp}
-c="_path_/calib.txt" -dp="_path_/detector_params.yml" -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10 -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10
-v=/path_to_aruco_tutorials/charuco_detection/images/choriginal.jpg
@endcode @endcode
Here the calib.txt is the output file generated by the calibrate_camera_charuco.cpp.
ChArUco Pose Estimation ChArUco Pose Estimation
------ ------
@@ -231,15 +233,17 @@ not enough corners for pose estimation or they are in the same line.
The axis can be drawn using ```drawAxis()``` to check the pose is correctly estimated. The result would be: (X:red, Y:green, Z:blue) The axis can be drawn using ```drawAxis()``` to check the pose is correctly estimated. The result would be: (X:red, Y:green, Z:blue)
![Charuco Board Axis](images/chaxis.png) ![Charuco Board Axis](images/chaxis.jpg)
A full example of ChArUco detection with pose estimation: A full example of ChArUco detection with pose estimation:
@snippet samples/tutorial_charuco_create_detect.cpp detwcp @snippet samples/tutorial_charuco_create_detect.cpp detwcp
A full working example is included in the ```detect_board_charuco.cpp``` inside the modules/aruco/samples/detect_board_charuco.cpp. A full working example is included in the `detect_board_charuco.cpp` inside the `modules/aruco/samples/detect_board_charuco.cpp`.
Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
@code{.cpp} @code{.cpp}
"_path_/calib.txt" -dp="_path_/detector_params.yml" -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10 -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10 -dp="_path_/detector_params.yml"
-v=/path_to_aruco_tutorials/charuco_detection/images/choriginal.jpg
-c=/path_to_aruco_samples/tutorial_camera_charuco.yml
@endcode @endcode

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 KiB

View File

@@ -1,6 +1,9 @@
Detection of Diamond Markers {#tutorial_charuco_diamond_detection} Detection of Diamond Markers {#tutorial_charuco_diamond_detection}
============================== ==============================
@prev_tutorial{tutorial_charuco_detection}
@next_tutorial{tutorial_aruco_calibration}
A ChArUco diamond marker (or simply diamond marker) is a chessboard composed by 3x3 squares and 4 ArUco markers inside the white squares. A ChArUco diamond marker (or simply diamond marker) is a chessboard composed by 3x3 squares and 4 ArUco markers inside the white squares.
It is similar to a ChArUco board in appearance, however they are conceptually different. It is similar to a ChArUco board in appearance, however they are conceptually different.
@@ -58,7 +61,7 @@ The image produced will be:
![Diamond marker](images/diamondmarker.png) ![Diamond marker](images/diamondmarker.png)
A full working example is included in the ```create_diamond.cpp``` inside the module samples folder. A full working example is included in the `create_diamond.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
@code{.cpp} @code{.cpp}
@@ -118,11 +121,13 @@ The result is the same that the one produced by ```drawDetectedMarkers()```, but
![Detected diamond markers](images/detecteddiamonds.png) ![Detected diamond markers](images/detecteddiamonds.png)
A full working example is included in the ```detect_diamonds.cpp``` inside the module samples folder. A full working example is included in the `detect_diamonds.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
@code{.cpp} @code{.cpp}
-c="_path_/calib.txt" -dp="_path_/detector_params.yml" -sl=0.04 -ml=0.02 -d=10 -dp="path_aruco/samples/detector_params.yml" -sl=0.04 -ml=0.012 -refine=3
-v="path_aruco/tutorials/charuco_diamond_detection/images/diamondmarkers.png"
-cd="path_aruco/samples/tutorial_dict.yml
@endcode @endcode
ChArUco Diamond Pose Estimation ChArUco Diamond Pose Estimation
@@ -166,9 +171,12 @@ Sample video:
<iframe width="420" height="315" src="https://www.youtube.com/embed/OqKpBnglH7k" frameborder="0" allowfullscreen></iframe> <iframe width="420" height="315" src="https://www.youtube.com/embed/OqKpBnglH7k" frameborder="0" allowfullscreen></iframe>
@endhtmlonly @endhtmlonly
A full working example is included in the ```detect_diamonds.cpp``` inside the module samples folder. A full working example is included in the `detect_diamonds.cpp` inside the `modules/aruco/samples/`.
Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
@code{.cpp} @code{.cpp}
-c="_output path_/calib.txt" -dp="_path_/detector_params.yml" -sl=0.04 -ml=0.02 -d=10 -dp="path_aruco/samples/detector_params.yml" -sl=0.04 -ml=0.012 -refine=3
-v="path_aruco/tutorials/charuco_diamond_detection/images/diamondmarkers.png"
-cd="path_aruco/samples/tutorial_dict.yml
-c="path_aruco/samples/tutorial_camera_params.yml"
@endcode @endcode