mirror of
https://github.com/opencv/opencv.git
synced 2024-11-27 12:40:05 +08:00
Merge pull request #23486 from vovka643:4.x_calibration_with_aruco
Add charuco pattern into calibration.cpp #23486 Added charuco pattern into calibration.cpp. Added charuco pattern with predefined aruco dictionary and with dictionary from file. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [х] I agree to contribute to the project under Apache 2 License. - [х] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [х] The PR is proposed to the proper branch - [х] There is a reference to the original bug report and related work - [х] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [х] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
parent
d4f29a6361
commit
a174a6c0b5
@ -5,6 +5,7 @@
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <opencv2/objdetect/charuco_detector.hpp>
|
||||
|
||||
#include <cctype>
|
||||
#include <stdio.h>
|
||||
@ -48,15 +49,25 @@ static void help(char** argv)
|
||||
{
|
||||
printf( "This is a camera calibration sample.\n"
|
||||
"Usage: %s\n"
|
||||
" -w=<board_width> # the number of inner corners per one of board dimension\n"
|
||||
" -h=<board_height> # the number of inner corners per another board dimension\n"
|
||||
" [-pt=<pattern>] # the type of pattern: chessboard or circles' grid\n"
|
||||
" -w=<board_width> # the calibration board horizontal size in inner corners "
|
||||
"for chessboard and in squares or circles for others like ChArUco or circles grid\n"
|
||||
" -h=<board_height> # the calibration board verical size in inner corners "
|
||||
"for chessboard and in squares or circles for others like ChArUco or circles grid\n"
|
||||
" [-pt=<pattern>] # the type of pattern: chessboard, charuco, circles, acircles\n"
|
||||
" [-n=<number_of_frames>] # the number of frames to use for calibration\n"
|
||||
" # (if not specified, it will be set to the number\n"
|
||||
" # of board views actually available)\n"
|
||||
" [-d=<delay>] # a minimum delay in ms between subsequent attempts to capture a next view\n"
|
||||
" # (used only for video capturing)\n"
|
||||
" [-s=<squareSize>] # square size in some user-defined units (1 by default)\n"
|
||||
" [-ms=<markerSize>] # marker size in some user-defined units (0.5 by default)\n"
|
||||
" [-ad=<arucoDict>] # Aruco dictionary name for ChArUco board. "
|
||||
"Available ArUco dictionaries: DICT_4X4_50, DICT_4X4_100, DICT_4X4_250, "
|
||||
"DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, DICT_5X5_1000, "
|
||||
"DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50, "
|
||||
"DICT_7X7_100, DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL, "
|
||||
"DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10, DICT_APRILTAG_36h11\n"
|
||||
" [-adf=<dictFilename>] # Custom aruco dictionary file for ChArUco board\n"
|
||||
" [-o=<out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters\n"
|
||||
" [-op] # write detected feature points\n"
|
||||
" [-oe] # write extrinsic parameters\n"
|
||||
@ -90,7 +101,7 @@ static void help(char** argv)
|
||||
}
|
||||
|
||||
enum { DETECTION = 0, CAPTURING = 1, CALIBRATED = 2 };
|
||||
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
|
||||
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID, CHARUCOBOARD};
|
||||
|
||||
static double computeReprojectionErrors(
|
||||
const vector<vector<Point3f> >& objectPoints,
|
||||
@ -139,6 +150,12 @@ static void calcChessboardCorners(Size boardSize, float squareSize, vector<Point
|
||||
float(i*squareSize), 0));
|
||||
break;
|
||||
|
||||
case CHARUCOBOARD:
|
||||
for( int i = 0; i < boardSize.height-1; i++ )
|
||||
for( int j = 0; j < boardSize.width-1; j++ )
|
||||
corners.push_back(Point3f(float(j*squareSize),
|
||||
float(i*squareSize), 0));
|
||||
break;
|
||||
default:
|
||||
CV_Error(Error::StsBadArg, "Unknown pattern type\n");
|
||||
}
|
||||
@ -161,7 +178,8 @@ static bool runCalibration( vector<vector<Point2f> > imagePoints,
|
||||
|
||||
vector<vector<Point3f> > objectPoints(1);
|
||||
calcChessboardCorners(boardSize, squareSize, objectPoints[0], patternType);
|
||||
objectPoints[0][boardSize.width - 1].x = objectPoints[0][0].x + grid_width;
|
||||
int offset = patternType != CHARUCOBOARD ? boardSize.width - 1: boardSize.width - 2;
|
||||
objectPoints[0][offset].x = objectPoints[0][0].x + grid_width;
|
||||
newObjPoints = objectPoints[0];
|
||||
|
||||
objectPoints.resize(imagePoints.size(),objectPoints[0]);
|
||||
@ -350,10 +368,12 @@ static bool runAndSave(const string& outputFilename,
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
Size boardSize, imageSize;
|
||||
float squareSize, aspectRatio = 1;
|
||||
float squareSize, markerSize, aspectRatio = 1;
|
||||
Mat cameraMatrix, distCoeffs;
|
||||
string outputFilename;
|
||||
string inputFilename = "";
|
||||
int arucoDict;
|
||||
string dictFilename;
|
||||
|
||||
int i, nframes;
|
||||
bool writeExtrinsics, writePoints;
|
||||
@ -367,12 +387,12 @@ int main( int argc, char** argv )
|
||||
clock_t prevTimestamp = 0;
|
||||
int mode = DETECTION;
|
||||
int cameraId = 0;
|
||||
vector<vector<Point2f> > imagePoints;
|
||||
vector<vector<Point2f>> imagePoints;
|
||||
vector<string> imageList;
|
||||
Pattern pattern = CHESSBOARD;
|
||||
|
||||
cv::CommandLineParser parser(argc, argv,
|
||||
"{help ||}{w||}{h||}{pt|chessboard|}{n|10|}{d|1000|}{s|1|}{o|out_camera_data.yml|}"
|
||||
"{help ||}{w||}{h||}{pt|chessboard|}{n|10|}{d|1000|}{s|1|}{ms|0.5|}{ad|DICT_4X4_50|}{adf|None|}{o|out_camera_data.yml|}"
|
||||
"{op||}{oe||}{zt||}{a||}{p||}{v||}{V||}{su||}"
|
||||
"{oo||}{ws|11|}{dt||}"
|
||||
"{fx||}{fy||}{cx||}{cy||}"
|
||||
@ -394,10 +414,43 @@ int main( int argc, char** argv )
|
||||
pattern = ASYMMETRIC_CIRCLES_GRID;
|
||||
else if( val == "chessboard" )
|
||||
pattern = CHESSBOARD;
|
||||
else if( val == "charuco" )
|
||||
pattern = CHARUCOBOARD;
|
||||
else
|
||||
return fprintf( stderr, "Invalid pattern type: must be chessboard or circles\n" ), -1;
|
||||
}
|
||||
|
||||
squareSize = parser.get<float>("s");
|
||||
markerSize = parser.get<float>("ms");
|
||||
|
||||
string arucoDictName = parser.get<string>("ad");
|
||||
if (arucoDictName == "DICT_4X4_50") { arucoDict = cv::aruco::DICT_4X4_50; }
|
||||
else if (arucoDictName == "DICT_4X4_100") { arucoDict = cv::aruco::DICT_4X4_100; }
|
||||
else if (arucoDictName == "DICT_4X4_250") { arucoDict = cv::aruco::DICT_4X4_250; }
|
||||
else if (arucoDictName == "DICT_4X4_1000") { arucoDict = cv::aruco::DICT_4X4_1000; }
|
||||
else if (arucoDictName == "DICT_5X5_50") { arucoDict = cv::aruco::DICT_5X5_50; }
|
||||
else if (arucoDictName == "DICT_5X5_100") { arucoDict = cv::aruco::DICT_5X5_100; }
|
||||
else if (arucoDictName == "DICT_5X5_250") { arucoDict = cv::aruco::DICT_5X5_250; }
|
||||
else if (arucoDictName == "DICT_5X5_1000") { arucoDict = cv::aruco::DICT_5X5_1000; }
|
||||
else if (arucoDictName == "DICT_6X6_50") { arucoDict = cv::aruco::DICT_6X6_50; }
|
||||
else if (arucoDictName == "DICT_6X6_100") { arucoDict = cv::aruco::DICT_6X6_100; }
|
||||
else if (arucoDictName == "DICT_6X6_250") { arucoDict = cv::aruco::DICT_6X6_250; }
|
||||
else if (arucoDictName == "DICT_6X6_1000") { arucoDict = cv::aruco::DICT_6X6_1000; }
|
||||
else if (arucoDictName == "DICT_7X7_50") { arucoDict = cv::aruco::DICT_7X7_50; }
|
||||
else if (arucoDictName == "DICT_7X7_100") { arucoDict = cv::aruco::DICT_7X7_100; }
|
||||
else if (arucoDictName == "DICT_7X7_250") { arucoDict = cv::aruco::DICT_7X7_250; }
|
||||
else if (arucoDictName == "DICT_7X7_1000") { arucoDict = cv::aruco::DICT_7X7_1000; }
|
||||
else if (arucoDictName == "DICT_ARUCO_ORIGINAL") { arucoDict = cv::aruco::DICT_ARUCO_ORIGINAL; }
|
||||
else if (arucoDictName == "DICT_APRILTAG_16h5") { arucoDict = cv::aruco::DICT_APRILTAG_16h5; }
|
||||
else if (arucoDictName == "DICT_APRILTAG_25h9") { arucoDict = cv::aruco::DICT_APRILTAG_25h9; }
|
||||
else if (arucoDictName == "DICT_APRILTAG_36h10") { arucoDict = cv::aruco::DICT_APRILTAG_36h10; }
|
||||
else if (arucoDictName == "DICT_APRILTAG_36h11") { arucoDict = cv::aruco::DICT_APRILTAG_36h11; }
|
||||
else {
|
||||
cout << "Incorrect Aruco dictionary name " << arucoDictName << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
dictFilename = parser.get<std::string>("adf");
|
||||
nframes = parser.get<int>("n");
|
||||
delay = parser.get<int>("d");
|
||||
writePoints = parser.has("op");
|
||||
@ -438,7 +491,8 @@ int main( int argc, char** argv )
|
||||
{
|
||||
flags |= CALIB_FIX_K3;
|
||||
}
|
||||
float grid_width = squareSize * (boardSize.width - 1);
|
||||
|
||||
float grid_width = squareSize *(pattern != CHARUCOBOARD ? (boardSize.width - 1): (boardSize.width - 2) );
|
||||
bool release_object = false;
|
||||
if (parser.has("dt")) {
|
||||
grid_width = parser.get<float>("dt");
|
||||
@ -463,6 +517,22 @@ int main( int argc, char** argv )
|
||||
if ( boardSize.height <= 0 )
|
||||
return fprintf( stderr, "Invalid board height\n" ), -1;
|
||||
|
||||
cv::aruco::Dictionary dictionary;
|
||||
if (dictFilename == "None") {
|
||||
std::cout << "Using predefined dictionary with id: " << arucoDict << std::endl;
|
||||
dictionary = aruco::getPredefinedDictionary(arucoDict);
|
||||
}
|
||||
else {
|
||||
std::cout << "Using custom dictionary from file: " << dictFilename << std::endl;
|
||||
cv::FileStorage dict_file(dictFilename, cv::FileStorage::Mode::READ);
|
||||
cv::FileNode fn(dict_file.root());
|
||||
dictionary.readDictionary(fn);
|
||||
}
|
||||
|
||||
cv::aruco::CharucoBoard ch_board(boardSize, squareSize, markerSize, dictionary);
|
||||
std::vector<int> markerIds;
|
||||
cv::aruco::CharucoDetector ch_detector(ch_board);
|
||||
|
||||
if( !inputFilename.empty() )
|
||||
{
|
||||
if( !videofile && readStringList(samples::findFile(inputFilename), imageList) )
|
||||
@ -474,7 +544,7 @@ int main( int argc, char** argv )
|
||||
capture.open(cameraId);
|
||||
|
||||
if( !capture.isOpened() && imageList.empty() )
|
||||
return fprintf( stderr, "Could not initialize video (%d) capture\n",cameraId ), -2;
|
||||
return fprintf( stderr, "Could not initialize video (%d) capture\n", cameraId ), -2;
|
||||
|
||||
if( !imageList.empty() )
|
||||
nframes = (int)imageList.size();
|
||||
@ -529,6 +599,12 @@ int main( int argc, char** argv )
|
||||
case ASYMMETRIC_CIRCLES_GRID:
|
||||
found = findCirclesGrid( view, boardSize, pointbuf, CALIB_CB_ASYMMETRIC_GRID );
|
||||
break;
|
||||
case CHARUCOBOARD:
|
||||
{
|
||||
ch_detector.detectBoard(view, pointbuf, markerIds);
|
||||
found = pointbuf.size() == (size_t)(boardSize.width-1)*(boardSize.height-1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return fprintf( stderr, "Unknown pattern type\n" ), -1;
|
||||
}
|
||||
@ -546,7 +622,12 @@ int main( int argc, char** argv )
|
||||
}
|
||||
|
||||
if(found)
|
||||
drawChessboardCorners( view, boardSize, Mat(pointbuf), found );
|
||||
{
|
||||
if(pattern != CHARUCOBOARD)
|
||||
drawChessboardCorners( view, boardSize, Mat(pointbuf), found );
|
||||
else
|
||||
drawChessboardCorners( view, Size(boardSize.width-1, boardSize.height-1), Mat(pointbuf), found );
|
||||
}
|
||||
|
||||
string msg = mode == CAPTURING ? "100/100" :
|
||||
mode == CALIBRATED ? "Calibrated" : "Press 'g' to start";
|
||||
|
Loading…
Reference in New Issue
Block a user