Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
calibrate-camera.cpp
1/****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5 *
6 * This software is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 * See the file LICENSE.txt at the root directory of this source
11 * distribution for additional information about the GNU GPL.
12 *
13 * For using ViSP with software that can not be combined with the GNU
14 * GPL, please contact Inria about acquiring a ViSP Professional
15 * Edition License.
16 *
17 * See https://visp.inria.fr for more information.
18 *
19 * This software was developed at:
20 * Inria Rennes - Bretagne Atlantique
21 * Campus Universitaire de Beaulieu
22 * 35042 Rennes Cedex
23 * France
24 *
25 * If you have questions regarding the use of this file, please contact
26 * Inria at visp@inria.fr
27 *
28 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 *
31 * Description:
32 * Camera calibration with chessboard or circle calibration grid.
33 *
34*****************************************************************************/
35#include <iostream>
36
37#include <visp3/core/vpConfig.h>
38
39#if (VISP_HAVE_OPENCV_VERSION >= 0x030000) && defined(HAVE_OPENCV_CALIB3D) && defined(HAVE_OPENCV_HIGHGUI) && defined(HAVE_OPENCV_IMGPROC)
40
41#include <map>
42
43#include <opencv2/calib3d/calib3d.hpp>
44#include <opencv2/core/core.hpp>
45#include <opencv2/highgui/highgui.hpp>
46#include <opencv2/imgproc/imgproc.hpp>
47
48#include <visp3/vision/vpCalibration.h>
49
50#include <visp3/core/vpImageTools.h>
51#include <visp3/core/vpIoTools.h>
52#include <visp3/core/vpMeterPixelConversion.h>
53#include <visp3/core/vpPixelMeterConversion.h>
54#include <visp3/core/vpPoint.h>
55#include <visp3/core/vpXmlParserCamera.h>
56#include <visp3/gui/vpDisplayD3D.h>
57#include <visp3/gui/vpDisplayGDI.h>
58#include <visp3/gui/vpDisplayGTK.h>
59#include <visp3/gui/vpDisplayOpenCV.h>
60#include <visp3/gui/vpDisplayX.h>
61#include <visp3/io/vpVideoReader.h>
62
63#include "calibration-helper.hpp"
64
65using namespace calib_helper;
66
67void usage(const char *argv[], int error)
68{
69 std::cout << "Synopsis" << std::endl
70 << " " << argv[0] << " <configuration file>.cfg [--init-from-xml <camera-init.xml>]"
71 << " [--camera-name <name>] [--aspect-ratio <ratio>] [--output <file.xml>] [--help] [-h]" << std::endl
72 << std::endl;
73 std::cout << "Description" << std::endl
74 << " <configuration file>.cfg Configuration file. See example in" << std::endl
75 << " \"default-chessboard.cfg\" or in \"default-circles.cfg\"." << std::endl
76 << " Default: \"default.cfg\"." << std::endl
77 << std::endl
78 << " --init-from-xml <camera-init.xml> XML file that contains camera parameters" << std::endl
79 << " used to initialize the calibration process." << std::endl
80 << std::endl
81 << " --camera-name <name> Camera name in the XML file set using \"--init-from-xml\" option." << std::endl
82 << " Default: \"Camera\"." << std::endl
83 << std::endl
84 << " --aspect-ratio <ratio> Pixel aspect ratio. " << std::endl
85 << " To estimate px = py, use \"--aspect-ratio 1\" option. Set to -1" << std::endl
86 << " to unset any constraint for px and py parameters. " << std::endl
87 << " Default: -1." << std::endl
88 << std::endl
89 << " --output <file.xml> XML file containing estimated camera parameters." << std::endl
90 << " Default: \"camera.xml\"." << std::endl
91 << std::endl
92 << " --help, -h Print this helper message." << std::endl
93 << std::endl;
94 if (error) {
95 std::cout << "Error" << std::endl
96 << " "
97 << "Unsupported parameter " << argv[error] << std::endl;
98 }
99}
100
101int main(int argc, const char *argv[])
102{
103 try {
104 if (argc == 1) {
105 usage(argv, 0);
106 return EXIT_SUCCESS;
107 }
108 std::string opt_output_file_name = "camera.xml";
109 Settings s;
110 const std::string opt_inputSettingsFile = argc > 1 ? argv[1] : "default.cfg";
111 std::string opt_init_camera_xml_file;
112 std::string opt_camera_name = "Camera";
113 double opt_aspect_ratio = -1; // Not used
114
115 for (int i = 2; i < argc; i++) {
116 if (std::string(argv[i]) == "--init-from-xml" && i + 1 < argc) {
117 opt_init_camera_xml_file = std::string(argv[i + 1]);
118 i++;
119 } else if (std::string(argv[i]) == "--camera-name" && i + 1 < argc) {
120 opt_camera_name = std::string(argv[i + 1]);
121 i++;
122 } else if (std::string(argv[i]) == "--output" && i + 1 < argc) {
123 opt_output_file_name = std::string(argv[i + 1]);
124 i++;
125 } else if (std::string(argv[i]) == "--aspect-ratio" && i + 1 < argc) {
126 opt_aspect_ratio = std::atof(argv[i + 1]);
127 i++;
128 } else if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") {
129 usage(argv, 0);
130 return EXIT_SUCCESS;
131 } else {
132 usage(argv, i);
133 return EXIT_FAILURE;
134 }
135 }
136
137 std::cout << "Settings from config file: " << argv[1] << std::endl;
138 if (!s.read(opt_inputSettingsFile)) {
139 std::cout << "Could not open the configuration file: \"" << opt_inputSettingsFile << "\"" << std::endl;
140 usage(argv, 0);
141 return EXIT_FAILURE;
142 }
143
144 if (!s.goodInput) {
145 std::cout << "Invalid input detected. Application stopping. " << std::endl;
146 return EXIT_FAILURE;
147 }
148
149 std::cout << "\nSettings from command line options: " << std::endl;
150 if (!opt_init_camera_xml_file.empty()) {
151 std::cout << "Init parameters: " << opt_init_camera_xml_file << std::endl;
152 }
153 std::cout << "Ouput xml file : " << opt_output_file_name << std::endl;
154 std::cout << "Camera name : " << opt_camera_name << std::endl;
155
156 // Check if output file name exists
157 if (vpIoTools::checkFilename(opt_output_file_name)) {
158 std::cout << "\nOutput file name " << opt_output_file_name << " already exists." << std::endl;
159 std::cout << "Remove this file or change output file name using [--output <file.xml>] command line option."
160 << std::endl;
161 return EXIT_SUCCESS;
162 }
163
164 // Start the calibration code
166 vpVideoReader reader;
167 reader.setFileName(s.input);
168 try {
169 reader.open(I);
170 } catch (const vpException &e) {
171 std::cout << "Catch an exception: " << e.getStringMessage() << std::endl;
172 std::cout << "Check if input images name \"" << s.input << "\" set in " << opt_inputSettingsFile
173 << " config file is correct..." << std::endl;
174 return EXIT_FAILURE;
175 }
176
177#if defined(VISP_HAVE_X11)
179#elif defined(VISP_HAVE_GDI)
181#elif defined(VISP_HAVE_GTK)
183#elif defined(HAVE_OPENCV_HIGHGUI)
185#endif
186
187 vpCameraParameters cam_init;
188 bool init_from_xml = false;
189 if (!opt_init_camera_xml_file.empty()) {
190 if (!vpIoTools::checkFilename(opt_init_camera_xml_file)) {
191 std::cout << "Input camera file \"" << opt_init_camera_xml_file << "\" doesn't exist!" << std::endl;
192 std::cout << "Modify [--init-from-xml <camera-init.xml>] option value" << std::endl;
193 return EXIT_FAILURE;
194 }
195 init_from_xml = true;
196 }
197 if (init_from_xml) {
198 std::cout << "Initialize camera parameters from xml file: " << opt_init_camera_xml_file << std::endl;
199 vpXmlParserCamera parser;
200 if (parser.parse(cam_init, opt_init_camera_xml_file, opt_camera_name,
202 std::cout << "Unable to find camera with name \"" << opt_camera_name
203 << "\" in file: " << opt_init_camera_xml_file << std::endl;
204 std::cout << "Modify [--camera-name <name>] option value" << std::endl;
205 return EXIT_FAILURE;
206 }
207 } else {
208 std::cout << "Initialize camera parameters with default values " << std::endl;
209 // Initialize camera parameters
210 double px = cam_init.get_px();
211 double py = cam_init.get_py();
212 // Set (u0,v0) in the middle of the image
213 double u0 = I.getWidth() / 2;
214 double v0 = I.getHeight() / 2;
215 cam_init.initPersProjWithoutDistortion(px, py, u0, v0);
216 }
217
218 std::cout << "Camera parameters used for initialization:\n" << cam_init << std::endl;
219
220 std::vector<vpPoint> model;
221 std::vector<vpCalibration> calibrator;
222
223 for (int i = 0; i < s.boardSize.height; i++) {
224 for (int j = 0; j < s.boardSize.width; j++) {
225 model.push_back(vpPoint(j * s.squareSize, i * s.squareSize, 0));
226 }
227 }
228
229 std::vector<CalibInfo> calib_info;
230 std::multimap<double, vpCameraParameters, std::less<double> > map_cam_sorted; // Sorted by residual
231
232 map_cam_sorted.insert(std::make_pair(1000, cam_init));
233
234 do {
235 reader.acquire(I);
236 long frame_index = reader.getFrameIndex();
237 char filename[FILENAME_MAX];
238 snprintf(filename, FILENAME_MAX, s.input.c_str(), frame_index);
239 std::string frame_name = vpIoTools::getName(filename);
242
243 cv::Mat cvI;
244 std::vector<cv::Point2f> pointBuf;
246
247 std::cout << "Process frame: " << frame_name << std::flush;
248 bool found = extractCalibrationPoints(s, cvI, pointBuf);
249
250 std::cout << ", grid detection status: " << found;
251 if (!found)
252 std::cout << ", image rejected" << std::endl;
253 else
254 std::cout << ", image used as input data" << std::endl;
255
256 if (found) { // If image processing done with success
257 vpDisplay::setTitle(I, frame_name);
258
259 std::vector<vpImagePoint> data;
260 for (unsigned int i = 0; i < pointBuf.size(); i++) {
261 vpImagePoint ip(pointBuf[i].y, pointBuf[i].x);
262 data.push_back(ip);
264 }
265
266 // Calibration on a single mono image
267 std::vector<vpPoint> calib_points;
268 vpCalibration calib;
269 calib.setLambda(0.5);
270 calib.setAspectRatio(opt_aspect_ratio);
271 for (unsigned int i = 0; i < model.size(); i++) {
272 calib.addPoint(model[i].get_oX(), model[i].get_oY(), model[i].get_oZ(), data[i]);
273 calib_points.push_back(vpPoint(model[i].get_oX(), model[i].get_oY(), model[i].get_oZ()));
274 calib_points.back().set_x(data[i].get_u());
275 calib_points.back().set_y(data[i].get_v());
276 }
277
279 bool calib_status = false;
280 std::multimap<double, vpCameraParameters>::const_iterator it_cam;
281 for (it_cam = map_cam_sorted.begin(); it_cam != map_cam_sorted.end(); ++it_cam) {
282 vpCameraParameters cam = it_cam->second;
283 if (calib.computeCalibration(vpCalibration::CALIB_VIRTUAL_VS, cMo, cam, false) == EXIT_SUCCESS) {
284 calibrator.push_back(calib);
285 // Add calibration info
286 calib_info.push_back(CalibInfo(I, calib_points, data, frame_name));
287 calib_status = true;
288 double residual = calib.getResidual();
289 map_cam_sorted.insert(std::make_pair(residual, cam));
290 break;
291 }
292 }
293 if (!calib_status) {
294 std::cout << "frame: " << frame_name << ", unable to calibrate from single image, image rejected"
295 << std::endl;
296 found = false;
297 }
298 }
299
300 if (found)
302 "Image processing succeed", vpColor::green);
303 else
305 "Image processing failed", vpColor::green);
306
307 if (s.tempo > 10.f) {
309 "A click to process the next image", vpColor::green);
312 } else {
314 vpTime::wait(s.tempo * 1000);
315 }
316 } while (!reader.end());
317
318 // Now we consider the multi image calibration
319 // Calibrate by a non linear method based on virtual visual servoing
320 if (calibrator.empty()) {
321 std::cerr << "Unable to calibrate. Image processing failed !" << std::endl;
322 return EXIT_FAILURE;
323 }
324
325 // Display calibration pattern occupancy
326 drawCalibrationOccupancy(I, calib_info, s.boardSize.width);
327
328 cv::Mat1b img(I.getHeight(), I.getWidth());
330 cv::Mat3b imgColor(I.getHeight(), I.getWidth());
331 cv::applyColorMap(img, imgColor, cv::COLORMAP_JET);
332
333 // Draw calibration board corners
334 for (size_t idx1 = 0; idx1 < calib_info.size(); idx1++) {
335 const CalibInfo &calib = calib_info[idx1];
336
337 for (size_t idx2 = 0; idx2 < calib.m_imPts.size(); idx2++) {
338 const vpImagePoint &imPt = calib.m_imPts[idx2];
339 cv::rectangle(imgColor,
340 cv::Rect(static_cast<int>(imPt.get_u() - 2), static_cast<int>(imPt.get_v() - 2),
342 cv::Scalar(0, 0, 0), -1);
343 }
344 }
345
346 vpImage<vpRGBa> I_color;
347 vpImageConvert::convert(imgColor, I_color);
348 d.close(I);
349 d.init(I_color, 0, 0, "Calibration pattern occupancy");
350
351 vpDisplay::display(I_color);
353 15 * vpDisplay::getDownScalingFactor(I_color), "Calibration pattern occupancy in the image",
355
356 if (s.tempo > 10.f) {
357 vpDisplay::displayText(I_color, I_color.getHeight() - 20 * vpDisplay::getDownScalingFactor(I_color),
358 15 * vpDisplay::getDownScalingFactor(I_color), "Click to continue...", vpColor::red);
359 vpDisplay::flush(I_color);
360 vpDisplay::getClick(I_color);
361 }
362 else {
363 vpDisplay::flush(I_color);
364 vpTime::wait(s.tempo * 1000);
365 }
366
367 d.close(I_color);
368 d.init(I);
369
370 std::stringstream ss_additional_info;
371 ss_additional_info << "<date>" << vpTime::getDateTime() << "</date>";
372 ss_additional_info << "<nb_calibration_images>" << calibrator.size() << "</nb_calibration_images>";
373 ss_additional_info << "<calibration_pattern_type>";
374
375 switch (s.calibrationPattern) {
376 case Settings::CHESSBOARD:
377 ss_additional_info << "Chessboard";
378 break;
379
380 case Settings::CIRCLES_GRID:
381 ss_additional_info << "Circles grid";
382 break;
383
384 case Settings::UNDEFINED:
385 default:
386 ss_additional_info << "Undefined";
387 break;
388 }
389 ss_additional_info << "</calibration_pattern_type>";
390 ss_additional_info << "<board_size>" << s.boardSize.width << "x" << s.boardSize.height << "</board_size>";
391 ss_additional_info << "<square_size>" << s.squareSize << "</square_size>";
392
393 double error;
394 // Initialize with camera parameter that has the lowest residual
395 vpCameraParameters cam = map_cam_sorted.begin()->second;
396 std::cout << "\nCalibration without distortion in progress on " << calibrator.size() << " images..." << std::endl;
398 EXIT_SUCCESS) {
399 std::cout << cam << std::endl;
400 vpDisplay::setTitle(I, "Without distortion results");
401
402 for (size_t i = 0; i < calibrator.size(); i++) {
403 double reproj_error = sqrt(calibrator[i].getResidual() / calibrator[i].get_npt());
404
405 const CalibInfo &calib = calib_info[i];
406 std::cout << "Image " << calib.m_frame_name << " reprojection error: " << reproj_error << std::endl;
407 I = calib.m_img;
409
410 std::ostringstream ss;
411 ss << "Reprojection error: " << reproj_error;
413 calib.m_frame_name, vpColor::red);
415 ss.str(), vpColor::red);
417 "Extracted points", vpColor::red);
419 "Projected points", vpColor::green);
420
421 for (size_t idx = 0; idx < calib.m_points.size(); idx++) {
423
424 vpPoint pt = calib.m_points[idx];
425 pt.project(calibrator[i].cMo);
426 vpImagePoint imPt;
427 vpMeterPixelConversion::convertPoint(cam, pt.get_x(), pt.get_y(), imPt);
429 }
430
431 if (s.tempo > 10.f) {
433 15 * vpDisplay::getDownScalingFactor(I), "Click to continue...", vpColor::red);
436 }
437 else {
439 vpTime::wait(s.tempo * 1000);
440 }
441 }
442
443 std::cout << "\nGlobal reprojection error: " << error << std::endl;
444 ss_additional_info << "<global_reprojection_error><without_distortion>" << error << "</without_distortion>";
445
447
448 if (xml.save(cam, opt_output_file_name.c_str(), opt_camera_name, I.getWidth(), I.getHeight()) ==
450 std::cout << "Camera parameters without distortion successfully saved in \"" << opt_output_file_name << "\""
451 << std::endl;
452 else {
453 std::cout << "Failed to save the camera parameters without distortion in \"" << opt_output_file_name << "\""
454 << std::endl;
455 std::cout << "A file with the same name exists. Remove it to be able "
456 "to save the parameters..."
457 << std::endl;
458 }
459 } else {
460 std::cout << "Calibration without distortion failed." << std::endl;
461 return EXIT_FAILURE;
462 }
463 vpCameraParameters cam_without_dist = cam;
464 std::vector<vpCalibration> calibrator_without_dist = calibrator;
465
466 std::cout << "\n\nCalibration with distortion in progress on " << calibrator.size() << " images..." << std::endl;
468 EXIT_SUCCESS) {
469 std::cout << cam << std::endl;
470 vpDisplay::setTitle(I, "With distortion results");
471
472 for (size_t i = 0; i < calibrator.size(); i++) {
473 double reproj_error = sqrt(calibrator[i].getResidual_dist() / calibrator[i].get_npt());
474
475 const CalibInfo &calib = calib_info[i];
476 std::cout << "Image " << calib.m_frame_name << " reprojection error: " << reproj_error << std::endl;
477 I = calib.m_img;
479
480 std::ostringstream ss;
481 ss << "Reprojection error: " << reproj_error;
483 calib.m_frame_name, vpColor::red);
485 ss.str(), vpColor::red);
487 "Extracted points", vpColor::red);
489 "Projected points", vpColor::green);
490
491 for (size_t idx = 0; idx < calib.m_points.size(); idx++) {
493
494 vpPoint pt = calib.m_points[idx];
495 pt.project(calibrator[i].cMo_dist);
496 vpImagePoint imPt;
497 vpMeterPixelConversion::convertPoint(cam, pt.get_x(), pt.get_y(), imPt);
499 }
500
501 if (s.tempo > 10.f) {
503 15 * vpDisplay::getDownScalingFactor(I), "Click to continue...", vpColor::red);
506 }
507 else {
509 vpTime::wait(s.tempo * 1000);
510 }
511 }
512
513 std::cout << "\nGlobal reprojection error: " << error << std::endl;
514 ss_additional_info << "<with_distortion>" << error << "</with_distortion></global_reprojection_error>";
515
516 vpImage<unsigned char> I_undist;
517 vpImage<unsigned char> I_dist_undist(I.getHeight(), 2 * I.getWidth());
518 d.close(I);
519 d.init(I_dist_undist, 0, 0, "Straight lines have to be straight - distorted image / undistorted image");
520
521 for (size_t idx = 0; idx < calib_info.size(); idx++) {
522 std::cout << "\nThis tool computes the line fitting error (mean distance error) on image points extracted from "
523 "the raw distorted image."
524 << std::endl;
525
526 I = calib_info[idx].m_img;
527 vpImageTools::undistort(I, cam, I_undist);
528
529 I_dist_undist.insert(I, vpImagePoint(0, 0));
530 I_dist_undist.insert(I_undist, vpImagePoint(0, I.getWidth()));
531 vpDisplay::display(I_dist_undist);
532
533 vpDisplay::displayText(I_dist_undist, 15 * vpDisplay::getDownScalingFactor(I_dist_undist),
534 15 * vpDisplay::getDownScalingFactor(I_dist_undist),
535 calib_info[idx].m_frame_name + std::string(" distorted"), vpColor::red);
536 vpDisplay::displayText(I_dist_undist, 30 * vpDisplay::getDownScalingFactor(I_dist_undist),
537 15 * vpDisplay::getDownScalingFactor(I_dist_undist),
538 "Draw lines from first / last points.", vpColor::red);
539 std::vector<vpImagePoint> grid_points = calib_info[idx].m_imPts;
540 for (int i = 0; i < s.boardSize.height; i++) {
541 std::vector<vpImagePoint> current_line(grid_points.begin() + i * s.boardSize.width,
542 grid_points.begin() + (i + 1) * s.boardSize.width);
543
544 std::vector<vpImagePoint> current_line_undist = undistort(cam, current_line);
545 double a = 0, b = 0, c = 0;
546 double line_fitting_error = vpMath::lineFitting(current_line, a, b, c);
547 double line_fitting_error_undist = vpMath::lineFitting(current_line_undist, a, b, c);
548 std::cout << calib_info[idx].m_frame_name << " line " << i + 1
549 << " fitting error on distorted points: " << line_fitting_error
550 << " ; on undistorted points: " << line_fitting_error_undist << std::endl;
551
552 vpImagePoint ip1 = current_line.front();
553 vpImagePoint ip2 = current_line.back();
554 vpDisplay::displayLine(I_dist_undist, ip1, ip2, vpColor::red);
555 }
556
557 std::cout << "\nThis tool computes the line fitting error (mean distance error) on image points extracted from "
558 "the undistorted image"
559 << " (vpImageTools::undistort())." << std::endl;
560 cv::Mat cvI;
561 std::vector<cv::Point2f> pointBuf;
562 vpImageConvert::convert(I_undist, cvI);
563
564 bool found = extractCalibrationPoints(s, cvI, pointBuf);
565 if (found) {
566 std::vector<vpImagePoint> grid_points;
567 for (unsigned int i = 0; i < pointBuf.size(); i++) {
568 vpImagePoint ip(pointBuf[i].y, pointBuf[i].x);
569 grid_points.push_back(ip);
570 }
571
572 vpDisplay::displayText(I_dist_undist, 15 * vpDisplay::getDownScalingFactor(I_dist_undist),
573 I.getWidth() + 15 * vpDisplay::getDownScalingFactor(I_dist_undist),
574 calib_info[idx].m_frame_name + std::string(" undistorted"), vpColor::red);
575 for (int i = 0; i < s.boardSize.height; i++) {
576 std::vector<vpImagePoint> current_line(grid_points.begin() + i * s.boardSize.width,
577 grid_points.begin() + (i + 1) * s.boardSize.width);
578
579 double a = 0, b = 0, c = 0;
580 double line_fitting_error = vpMath::lineFitting(current_line, a, b, c);
581 std::cout << calib_info[idx].m_frame_name << " undistorted image, line " << i + 1
582 << " fitting error: " << line_fitting_error << std::endl;
583
584 vpImagePoint ip1 = current_line.front() + vpImagePoint(0, I.getWidth());
585 vpImagePoint ip2 = current_line.back() + vpImagePoint(0, I.getWidth());
586 vpDisplay::displayLine(I_dist_undist, ip1, ip2, vpColor::red);
587 }
588 } else {
589 std::string msg("Unable to detect grid on undistorted image");
590 std::cout << msg << std::endl;
591 std::cout << "Check that the grid is not too close to the image edges" << std::endl;
592 vpDisplay::displayText(I_dist_undist, 15 * vpDisplay::getDownScalingFactor(I_dist_undist),
593 15 * vpDisplay::getDownScalingFactor(I_dist_undist),
594 calib_info[idx].m_frame_name + std::string(" undistorted"), vpColor::red);
595 vpDisplay::displayText(I_dist_undist, 30 * vpDisplay::getDownScalingFactor(I_dist_undist),
596 15 * vpDisplay::getDownScalingFactor(I_dist_undist), msg, vpColor::red);
597 }
598
599 if (s.tempo > 10.f) {
601 I_dist_undist, I_dist_undist.getHeight() - 20 * vpDisplay::getDownScalingFactor(I_dist_undist),
602 15 * vpDisplay::getDownScalingFactor(I_dist_undist), "Click to continue...", vpColor::red);
603 vpDisplay::flush(I_dist_undist);
604 vpDisplay::getClick(I_dist_undist);
605 }
606 else {
607 vpDisplay::flush(I_dist_undist);
608 vpTime::wait(s.tempo * 1000);
609 }
610 }
611
612 std::cout << std::endl;
614
615 // Camera poses
616 ss_additional_info << "<camera_poses>";
617 for (size_t i = 0; i < calibrator.size(); i++) {
618 vpPoseVector pose(calibrator[i].cMo);
619 ss_additional_info << "<cMo>" << pose.t() << "</cMo>";
620 }
621 for (size_t i = 0; i < calibrator.size(); i++) {
622 vpPoseVector pose(calibrator[i].cMo_dist);
623 ss_additional_info << "<cMo_dist>" << pose.t() << "</cMo_dist>";
624 }
625 ss_additional_info << "</camera_poses>";
626
627 if (xml.save(cam, opt_output_file_name.c_str(), opt_camera_name, I.getWidth(), I.getHeight(),
628 ss_additional_info.str()) == vpXmlParserCamera::SEQUENCE_OK)
629 std::cout << "Camera parameters without distortion successfully saved in \"" << opt_output_file_name << "\""
630 << std::endl;
631 else {
632 std::cout << "Failed to save the camera parameters without distortion in \"" << opt_output_file_name << "\""
633 << std::endl;
634 std::cout << "A file with the same name exists. Remove it to be able "
635 "to save the parameters..."
636 << std::endl;
637 }
638 std::cout << std::endl;
639 std::cout << "Estimated pose using vpPoseVector format: [tx ty tz tux tuy tuz] with translation in meter and "
640 "rotation in rad"
641 << std::endl;
642 for (unsigned int i = 0; i < calibrator.size(); i++)
643 std::cout << "Estimated pose on input data extracted from " << calib_info[i].m_frame_name << ": "
644 << vpPoseVector(calibrator[i].cMo_dist).t() << std::endl;
645 } else {
646 std::cout << "Calibration with distortion failed." << std::endl;
647 return EXIT_FAILURE;
648 }
649
650 std::cout << "\nCamera calibration succeeded. Results are savec in " << "\"" << opt_output_file_name << "\"" << std::endl;
651 return EXIT_SUCCESS;
652 } catch (const vpException &e) {
653 std::cout << "Catch an exception: " << e << std::endl;
654 return EXIT_FAILURE;
655 }
656}
657#else
658int main()
659{
660 std::cout << "OpenCV 2.3.0 or higher is requested to run the calibration." << std::endl;
661 std::cout << "Tip:" << std::endl;
662 std::cout << "- Install OpenCV, configure again ViSP using cmake and build again this example" << std::endl;
663 return EXIT_SUCCESS;
664}
665#endif
Tools for perspective camera calibration.
static void setLambda(const double &lambda)
int computeCalibration(vpCalibrationMethodType method, vpHomogeneousMatrix &cMo_est, vpCameraParameters &cam_est, bool verbose=false)
double getResidual(void) const
int addPoint(double X, double Y, double Z, vpImagePoint &ip)
static int computeCalibrationMulti(vpCalibrationMethodType method, std::vector< vpCalibration > &table_cal, vpCameraParameters &cam_est, double &globalReprojectionError, bool verbose=false)
void setAspectRatio(double aspect_ratio)
Generic class defining intrinsic camera parameters.
void initPersProjWithoutDistortion(double px, double py, double u0, double v0)
@ perspectiveProjWithoutDistortion
Perspective projection without distortion model.
static const vpColor red
Definition vpColor.h:211
static const vpColor green
Definition vpColor.h:214
Display for windows using GDI (available on any windows 32 platform).
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition vpDisplayX.h:132
void init(vpImage< unsigned char > &I, int win_x=-1, int win_y=-1, const std::string &win_title="")
static void close(vpImage< unsigned char > &I)
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1, bool segment=true)
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void setTitle(const vpImage< unsigned char > &I, const std::string &windowtitle)
static void flush(const vpImage< unsigned char > &I)
unsigned int getDownScalingFactor()
Definition vpDisplay.h:231
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
error that can be emitted by ViSP classes.
Definition vpException.h:59
const std::string & getStringMessage() const
Implementation of an homogeneous matrix and operations on such kind of matrices.
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
double get_u() const
double get_v() const
static void undistort(const vpImage< Type > &I, const vpCameraParameters &cam, vpImage< Type > &newI, unsigned int nThreads=2)
Definition of the vpImage class member functions.
Definition vpImage.h:135
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:184
static bool checkFilename(const std::string &filename)
static std::string getName(const std::string &pathname)
static double lineFitting(const std::vector< vpImagePoint > &imPts, double &a, double &b, double &c)
Definition vpMath.cpp:382
static void convertPoint(const vpCameraParameters &cam, const double &x, const double &y, double &u, double &v)
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
Definition vpPoint.h:77
double get_y() const
Get the point y coordinate in the image plane.
Definition vpPoint.cpp:469
double get_x() const
Get the point x coordinate in the image plane.
Definition vpPoint.cpp:467
Implementation of a pose vector and operations on poses.
vpRowVector t() const
Class that enables to manipulate easily a video file or a sequence of images. As it inherits from the...
void acquire(vpImage< vpRGBa > &I)
void open(vpImage< vpRGBa > &I)
void setFileName(const std::string &filename)
long getFrameIndex() const
XML parser to load and save intrinsic camera parameters.
int save(const vpCameraParameters &cam, const std::string &filename, const std::string &camera_name, unsigned int image_width=0, unsigned int image_height=0, const std::string &additionalInfo="", bool verbose=true)
int parse(vpCameraParameters &cam, const std::string &filename, const std::string &camera_name, const vpCameraParameters::vpCameraParametersProjType &projModel, unsigned int image_width=0, unsigned int image_height=0, bool verbose=true)
VISP_EXPORT int wait(double t0, double t)
VISP_EXPORT std::string getDateTime(const std::string &format="%Y/%m/%d %H:%M:%S")