fix ArUco, ChArUco, diamonds, add read dictionary/params, add calibration photos, add tests, add aruco_samples_utility.hpp
@@ -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"
|
||||||
|
)
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
|
||||||
*/
|
*/
|
||||||
|
48
modules/aruco/samples/aruco_samples_utility.hpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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> ¶ms) {
|
|
||||||
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 =
|
||||||
|
@@ -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> ¶ms) {
|
|
||||||
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 =
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
@@ -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);
|
||||||
|
@@ -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> ¶ms) {
|
|
||||||
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;
|
||||||
|
@@ -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> ¶ms) {
|
|
||||||
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;
|
||||||
|
@@ -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> ¶ms) {
|
|
||||||
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) {
|
||||||
|
@@ -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> ¶ms) {
|
|
||||||
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) {
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
%YAML:1.0
|
%YAML:1.0
|
||||||
nmarkers: 1024
|
|
||||||
adaptiveThreshWinSizeMin: 3
|
adaptiveThreshWinSizeMin: 3
|
||||||
adaptiveThreshWinSizeMax: 23
|
adaptiveThreshWinSizeMax: 23
|
||||||
adaptiveThreshWinSizeStep: 10
|
adaptiveThreshWinSizeStep: 10
|
||||||
|
21
modules/aruco/samples/tutorial_camera_charuco.yml
Normal 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"
|
14
modules/aruco/samples/tutorial_camera_params.yml
Normal 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 ]
|
@@ -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);
|
||||||
|
38
modules/aruco/samples/tutorial_dict.yml
Normal 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"
|
@@ -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
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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")
|
||||||
|
)
|
||||||
|
@@ -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:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
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
|
||||||
-----
|
-----
|
||||||
|
@@ -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}
|
||||||
|
BIN
modules/aruco/tutorials/aruco_calibration/images/img_00.jpg
Normal file
After Width: | Height: | Size: 124 KiB |
BIN
modules/aruco/tutorials/aruco_calibration/images/img_01.jpg
Normal file
After Width: | Height: | Size: 115 KiB |
BIN
modules/aruco/tutorials/aruco_calibration/images/img_02.jpg
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
modules/aruco/tutorials/aruco_calibration/images/img_03.jpg
Normal file
After Width: | Height: | Size: 123 KiB |
@@ -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:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
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`
|
@@ -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?
|
||||||
|
@@ -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:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The result will be:
|
The result will be:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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
|
||||||
|
BIN
modules/aruco/tutorials/charuco_detection/images/chaxis.jpg
Normal file
After Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 385 KiB |
BIN
modules/aruco/tutorials/charuco_detection/images/chcorners.jpg
Normal file
After Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 387 KiB |
BIN
modules/aruco/tutorials/charuco_detection/images/chocclusion.jpg
Normal file
After Width: | Height: | Size: 97 KiB |
Before Width: | Height: | Size: 404 KiB |
After Width: | Height: | Size: 112 KiB |
BIN
modules/aruco/tutorials/charuco_detection/images/choriginal.jpg
Normal file
After Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 348 KiB |
@@ -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:
|
|||||||
|
|
||||||

|

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

|

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