40 #include <visp3/core/vpConfig.h>
42 #if VISP_HAVE_OPENCV_VERSION >= 0x020300
44 #include <opencv2/calib3d/calib3d.hpp>
45 #include <opencv2/core/core.hpp>
46 #include <opencv2/highgui/highgui.hpp>
47 #include <opencv2/imgproc/imgproc.hpp>
49 #include <visp3/vision/vpCalibration.h>
51 #include <visp3/core/vpIoTools.h>
52 #include <visp3/core/vpPoint.h>
53 #include <visp3/core/vpXmlParserCamera.h>
54 #include <visp3/gui/vpDisplayD3D.h>
55 #include <visp3/gui/vpDisplayGDI.h>
56 #include <visp3/gui/vpDisplayGTK.h>
57 #include <visp3/gui/vpDisplayOpenCV.h>
58 #include <visp3/gui/vpDisplayX.h>
59 #include <visp3/io/vpVideoReader.h>
61 #ifndef DOXYGEN_SHOULD_SKIP_THIS
67 : boardSize(), calibrationPattern(UNDEFINED), squareSize(0.), input(), tempo(0.), goodInput(false), patternToUse()
69 boardSize = cv::Size(0, 0);
70 calibrationPattern = UNDEFINED;
75 enum Pattern { UNDEFINED, CHESSBOARD, CIRCLES_GRID };
77 bool read(
const std::string &filename)
89 std::cout <<
"grid width : " << boardSize.width << std::endl;
90 std::cout <<
"grid height: " << boardSize.height << std::endl;
91 std::cout <<
"square size: " << squareSize << std::endl;
92 std::cout <<
"pattern : " << patternToUse << std::endl;
93 std::cout <<
"input seq : " << input << std::endl;
94 std::cout <<
"tempo : " << tempo << std::endl;
101 if (boardSize.width <= 0 || boardSize.height <= 0) {
102 std::cerr <<
"Invalid Board size: " << boardSize.width <<
" " << boardSize.height << std::endl;
105 if (squareSize <= 10e-6) {
106 std::cerr <<
"Invalid square size " << squareSize << std::endl;
113 calibrationPattern = UNDEFINED;
114 if (patternToUse.compare(
"CHESSBOARD") == 0)
115 calibrationPattern = CHESSBOARD;
116 else if (patternToUse.compare(
"CIRCLES_GRID") == 0)
117 calibrationPattern = CIRCLES_GRID;
118 if (calibrationPattern == UNDEFINED) {
119 std::cerr <<
" Inexistent camera calibration mode: " << patternToUse << std::endl;
127 Pattern calibrationPattern;
137 std::string patternToUse;
141 int main(
int argc,
const char **argv)
144 std::string outputFileName =
"camera.xml";
146 const std::string inputSettingsFile = argc > 1 ? argv[1] :
"default.cfg";
148 if (!s.read(inputSettingsFile)) {
149 std::cout <<
"Could not open the configuration file: \"" << inputSettingsFile <<
"\"" << std::endl;
150 std::cout << std::endl <<
"Usage: " << argv[0] <<
" <configuration file>.cfg" << std::endl;
155 std::cout <<
"Invalid input detected. Application stopping. " << std::endl;
168 std::cout <<
"Check if input images name \"" << s.input <<
"\" set in " << inputSettingsFile <<
" config file is correct..." << std::endl;
174 #elif defined VISP_HAVE_GDI
176 #elif defined VISP_HAVE_GTK
178 #elif defined VISP_HAVE_OPENCV
192 std::vector<vpPoint> model;
193 std::vector<vpCalibration> calibrator;
195 for (
int i = 0; i < s.boardSize.height; i++) {
196 for (
int j = 0; j < s.boardSize.width; j++) {
197 model.push_back(
vpPoint(j * s.squareSize, i * s.squareSize, 0));
201 while (!reader.
end()) {
208 std::vector<cv::Point2f> pointBuf;
212 switch (s.calibrationPattern)
214 case Settings::CHESSBOARD:
216 found = findChessboardCorners(cvI, s.boardSize, pointBuf,
217 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
218 cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_FAST_CHECK |
219 cv::CALIB_CB_NORMALIZE_IMAGE);
221 CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK |
222 CV_CALIB_CB_NORMALIZE_IMAGE);
225 case Settings::CIRCLES_GRID:
227 found = findCirclesGrid(cvI, s.boardSize, pointBuf, cv::CALIB_CB_SYMMETRIC_GRID);
229 case Settings::UNDEFINED:
231 std::cout <<
"Unkown calibration grid " << std::endl;
235 std::cout <<
"frame: " << frame_index <<
", status: " << found;
237 std::cout <<
", image rejected" << std::endl;
239 std::cout <<
", image used as input data" << std::endl;
243 std::vector<vpImagePoint> data;
245 if (s.calibrationPattern == Settings::CHESSBOARD) {
247 cornerSubPix(cvI, pointBuf, cv::Size(11, 11), cv::Size(-1, -1),
248 #
if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
249 cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 30, 0.1));
251 cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
254 std::stringstream ss;
255 ss <<
"image " << frame_index;
257 for (
unsigned int i = 0; i < pointBuf.size(); i++) {
267 for (
unsigned int i = 0; i < model.size(); i++) {
268 calib.
addPoint(model[i].get_oX(), model[i].get_oY(), model[i].get_oZ(), data[i]);
274 calibrator.push_back(calib);
283 if (s.tempo > 10.f) {
295 if (calibrator.empty()) {
296 std::cerr <<
"Unable to calibrate. Image processing failed !" << std::endl;
300 std::stringstream ss_additional_info;
302 ss_additional_info <<
"<nb_calibration_images>" << calibrator.size() <<
"</nb_calibration_images>";
303 ss_additional_info <<
"<calibration_pattern_type>";
305 switch (s.calibrationPattern) {
306 case Settings::CHESSBOARD:
307 ss_additional_info <<
"Chessboard";
310 case Settings::CIRCLES_GRID:
311 ss_additional_info <<
"Circles grid";
314 case Settings::UNDEFINED:
316 ss_additional_info <<
"Undefined";
319 ss_additional_info <<
"</calibration_pattern_type>";
320 ss_additional_info <<
"<board_size>" << s.boardSize.width <<
"x" << s.boardSize.height <<
"</board_size>";
321 ss_additional_info <<
"<square_size>" << s.squareSize <<
"</square_size>";
323 std::cout <<
"\nCalibration without distortion in progress on " << calibrator.size() <<
" images..." << std::endl;
326 std::cout << cam << std::endl;
327 std::cout <<
"Global reprojection error: " << error << std::endl;
328 ss_additional_info <<
"<global_reprojection_error><without_distortion>" << error <<
"</without_distortion>";
330 #ifdef VISP_HAVE_PUGIXML
335 std::cout <<
"Camera parameters without distortion successfully saved in \"" << outputFileName <<
"\""
338 std::cout <<
"Failed to save the camera parameters without distortion in \"" << outputFileName <<
"\""
340 std::cout <<
"A file with the same name exists. Remove it to be able "
341 "to save the parameters..."
346 std::cout <<
"Calibration without distortion failed." << std::endl;
350 std::cout <<
"\nCalibration with distortion in progress on " << calibrator.size() <<
" images..." << std::endl;
353 std::cout << cam << std::endl;
354 std::cout <<
"Global reprojection error: " << error << std::endl;
355 ss_additional_info <<
"<with_distortion>" << error <<
"</with_distortion></global_reprojection_error>";
357 #ifdef VISP_HAVE_PUGIXML
360 if (xml.
save(cam, outputFileName.c_str(),
"Camera", I.
getWidth(), I.
getHeight(), ss_additional_info.str()) ==
362 std::cout <<
"Camera parameters without distortion successfully saved in \"" << outputFileName <<
"\""
365 std::cout <<
"Failed to save the camera parameters without distortion in \"" << outputFileName <<
"\""
367 std::cout <<
"A file with the same name exists. Remove it to be able "
368 "to save the parameters..."
372 std::cout << std::endl;
373 for (
unsigned int i = 0; i < calibrator.size(); i++)
374 std::cout <<
"Estimated pose on input data " << i <<
": " <<
vpPoseVector(calibrator[i].cMo_dist).
t()
378 std::cout <<
"Calibration with distortion failed." << std::endl;
384 std::cout <<
"Catch an exception: " << e << std::endl;
391 std::cout <<
"OpenCV 2.3.0 or higher is requested to run the calibration." << std::endl;
392 std::cout <<
"Tip:" << std::endl;
393 std::cout <<
"- Install OpenCV, configure again ViSP using cmake and build again this example" << std::endl;