ViSP  2.8.0
camera_calibration.cpp
1 /****************************************************************************
2  *
3  * $Id: camera_calibration.cpp 4286 2013-06-26 20:28:16Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Camera calibration with chessboard or circle calibration grid.
36  *
37  * Authors:
38  * Fabien Spindler
39  *
40  *****************************************************************************/
41 #include <iostream>
42 
43 #include <visp/vpConfig.h>
44 
45 #if VISP_HAVE_OPENCV_VERSION >= 0x020300
46 
47 #include <opencv2/core/core.hpp>
48 #include <opencv2/imgproc/imgproc.hpp>
49 #include <opencv2/calib3d/calib3d.hpp>
50 #include <opencv2/highgui/highgui.hpp>
51 
52 #include <visp/vpCalibration.h>
53 
54 #include <visp/vpDisplayX.h>
55 #include <visp/vpDisplayGDI.h>
56 #include <visp/vpDisplayOpenCV.h>
57 #include <visp/vpDisplayD3D.h>
58 #include <visp/vpDisplayGTK.h>
59 #include <visp/vpIoTools.h>
60 #include <visp/vpPoint.h>
61 #include <visp/vpVideoReader.h>
62 #include <visp/vpXmlParserCamera.h>
63 
64 class Settings
65 {
66 public:
67  Settings() : goodInput(false) {}
69 
70  bool read(const std::string &filename) // Read the parameters
71  {
72  // reading configuration file
73  if (! vpIoTools::loadConfigFile(filename) )
74  return false;
75  vpIoTools::readConfigVar("BoardSize_Width:", boardSize.width);
76  vpIoTools::readConfigVar("BoardSize_Height:", boardSize.height);
77  vpIoTools::readConfigVar("Square_Size:", squareSize);
78  vpIoTools::readConfigVar("Calibrate_Pattern:", patternToUse);
80 
81  std::cout << "grid width : " << boardSize.width << std::endl;
82  std::cout << "grid height: " << boardSize.height << std::endl;
83  std::cout << "square size: " << squareSize << std::endl;
84  std::cout << "pattern : " << patternToUse << std::endl;
85  std::cout << "input seq : " << input << std::endl;
86  interprate();
87  return true;
88  }
89  void interprate()
90  {
91  goodInput = true;
92  if (boardSize.width <= 0 || boardSize.height <= 0) {
93  std::cerr << "Invalid Board size: " << boardSize.width << " " << boardSize.height << std::endl;
94  goodInput = false;
95  }
96  if (squareSize <= 10e-6) {
97  std::cerr << "Invalid square size " << squareSize << std::endl;
98  goodInput = false;
99  }
100 
101  if (input.empty()) // Check for valid input
102  goodInput = false;
103 
105  if (!patternToUse.compare("CHESSBOARD")) calibrationPattern = CHESSBOARD;
106  if (!patternToUse.compare("CIRCLES_GRID")) calibrationPattern = CIRCLES_GRID;
107  if (calibrationPattern == UNDEFINED) {
108  std::cerr << " Inexistent camera calibration mode: " << patternToUse << std::endl;
109  goodInput = false;
110  }
111  }
112 
113 public:
114  cv::Size boardSize; // The size of the board -> Number of items by width and height
115  Pattern calibrationPattern;// One of the Chessboard, circles, or asymmetric circle pattern
116  float squareSize; // The size of a square in your defined unit (point, millimeter,etc).
117  std::string input; // The input image sequence
118  bool goodInput;
119 
120 private:
121  std::string patternToUse;
122 };
123 
124 int main(int argc, const char ** argv)
125 {
126  std::string outputFileName = "camera.xml";
127 
128  Settings s;
129  const std::string inputSettingsFile = argc > 1 ? argv[1] : "default.cfg";
130  if (! s.read(inputSettingsFile) ) {
131  std::cout << "Could not open the configuration file: \"" << inputSettingsFile << "\"" << std::endl;
132  std::cout << std::endl << "Usage: " << argv[0] << " <configuration file>.cfg" << std::endl;
133  return -1;
134  }
135 
136  if (! s.goodInput)
137  {
138  std::cout << "Invalid input detected. Application stopping. " << std::endl;
139  return -1;
140  }
141 
142  // Start the calibration code
144  vpVideoReader reader;
145  reader.setFileName(s.input);
146  reader.open(I);
147 
148 #ifdef VISP_HAVE_X11
149  vpDisplayX d(I);
150 #elif defined VISP_HAVE_GDI
151  vpDisplayGDI d(I);
152 #elif defined VISP_HAVE_GTK
153  vpDisplayGTK d(I);
154 #elif defined VISP_HAVE_OPENCV
155  vpDisplayOpenCV d(I);
156 #endif
157 
158  std::vector<vpPoint> model;
159  std::vector<vpCalibration> calibrator;
160 
161  for (int i=0; i< s.boardSize.height; i++) {
162  for (int j=0; j< s.boardSize.width; j++) {
163  vpPoint P;
165  model.push_back(P);
166  }
167  }
168 
169  long frame_index;
170  while(! reader.end()) {
171  frame_index = reader.getFrameIndex();
172  reader.acquire(I);
174 
175  cv::Mat cvI;
176  std::vector<cv::Point2f> pointBuf;
177  vpImageConvert::convert(I, cvI);
178 
179  bool found;
180  switch( s.calibrationPattern ) // Find feature points on the input format
181  {
183  found = findChessboardCorners( cvI, s.boardSize, pointBuf,
184  CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE);
185  break;
187  found = findCirclesGrid( cvI, s.boardSize, pointBuf, cv::CALIB_CB_SYMMETRIC_GRID );
188  break;
189  default:
190  break;
191  }
192 
193  std::cout << "frame: " << frame_index << " status: " << found << std::endl;
194 
195  if ( found) // If done with success,
196  {
197  std::vector<vpImagePoint> data;
198 
200  // improve the found corners' coordinate accuracy for chessboard
201  cornerSubPix( cvI, pointBuf, cv::Size(11,11),
202  cv::Size(-1,-1), cv::TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));
203  }
204  char title[20]; sprintf(title, "image %ld", frame_index);
205  vpDisplay::setTitle(I, title);
206  for (unsigned int i=0; i < pointBuf.size(); i++) {
207  vpImagePoint ip(pointBuf[i].y, pointBuf[i].x);
208  data.push_back(ip);
210 
211  }
212 
213  // Calibration on a single mono image
214  vpCalibration calib;
215  calib.setLambda(0.5);
216  calib.clearPoint();
217  for (unsigned int i=0; i<model.size(); i++) {
218  calib.addPoint(model[i].get_oX(), model[i].get_oY(), model[i].get_oZ(), data[i]);
219  }
221  vpCameraParameters cam;
222 
223  // Set (u0,v0) in the middle of the image
224  double px = cam.get_px();
225  double py = cam.get_px();
226  double u0 = I.getWidth()/2;
227  double v0 = I.getHeight()/2;
228  cam.initPersProjWithoutDistortion(px, py, u0, v0);
229 
230  if (calib.computeCalibration(vpCalibration::CALIB_VIRTUAL_VS, cMo, cam, false) == 0) {
231  //std::cout << "camera parameters: " << cam << std::endl;
232  calibrator.push_back(calib);
233  }
234  }
235 
236  vpDisplay::flush(I);
237  //vpDisplay::getClick(I);
238  }
239 
240  // Now we consider the multi image calibration
241  // Calibrate by a non linear method based on virtual visual servoing
242  if (calibrator.empty()) {
243  std::cerr << "Unable to calibrate. Image processing failed !" << std::endl;
244  return 0;
245  }
246 
247  std::cout << "\nCalibration without distorsion in progress on " << calibrator.size() << " images..." << std::endl;
248  vpCameraParameters cam;
249  double error;
250  if (vpCalibration::computeCalibrationMulti(vpCalibration::CALIB_VIRTUAL_VS, calibrator, cam, error, false) == 0) {
251  std::cout << cam << std::endl;
252  std::cout << "Global reprojection error: " << error << std::endl;
253 #ifdef VISP_HAVE_XML2
254  vpXmlParserCamera xml;
255 
256  if(xml.save(cam, outputFileName.c_str(), "Camera", I.getWidth(), I.getHeight()) == vpXmlParserCamera::SEQUENCE_OK)
257  std::cout << "Camera parameters without distortion successfully saved in \"" << outputFileName << "\"" << std::endl;
258  else {
259  std::cout << "Failed to save the camera parameters without distortion in \"" << outputFileName << "\"" << std::endl;
260  std::cout << "A file with the same name exists. Remove it to be able to save the parameters..." << std::endl;
261  }
262 #endif
263  }
264  else
265  std::cout << "Calibration without distortion failed." << std::endl;
266 
267  std::cout << "\nCalibration with distorsion in progress on " << calibrator.size() << " images..." << std::endl;
268  if (vpCalibration::computeCalibrationMulti(vpCalibration::CALIB_VIRTUAL_VS_DIST, calibrator, cam, error, false) == 0) {
269  std::cout << cam << std::endl;
270  std::cout << "Global reprojection error: " << error << std::endl;
271 #ifdef VISP_HAVE_XML2
272  vpXmlParserCamera xml;
273 
274  if(xml.save(cam, outputFileName.c_str(), "Camera", I.getWidth(), I.getHeight()) == vpXmlParserCamera::SEQUENCE_OK)
275  std::cout << "Camera parameters without distortion successfully saved in \"" << outputFileName << "\"" << std::endl;
276  else {
277  std::cout << "Failed to save the camera parameters without distortion in \"" << outputFileName << "\"" << std::endl;
278  std::cout << "A file with the same name exists. Remove it to be able to save the parameters..." << std::endl;
279  }
280 #endif
281  }
282  else
283  std::cout << "Calibration with distortion failed." << std::endl;
284 }
285 #else
286 int main()
287 {
288  std::cout << "OpenCV 2.3.0 or higher is requested to run the calibration." << std::endl;
289 }
290 #endif
long getFrameIndex() const
unsigned int getWidth() const
Definition: vpImage.h:159
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
The class provides a data structure for the homogeneous matrices as well as a set of operations on th...
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:133
Define the X11 console to display images.
Definition: vpDisplayX.h:152
Class that enables to manipulate easily a video file or a sequence of images. As it inherits from the...
cv::Size boardSize
int addPoint(double X, double Y, double Z, vpImagePoint &ip)
int save(const vpCameraParameters &cam, const char *filename, const std::string &camera_name, const unsigned int image_width=0, const unsigned int image_height=0)
Tools for perspective camera calibration.
Definition: vpCalibration.h:78
XML parser to load and save intrinsic camera parameters.
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:1991
int computeCalibration(vpCalibrationMethodType method, vpHomogeneousMatrix &cMo, vpCameraParameters &cam, bool verbose=false)
static const vpColor red
Definition: vpColor.h:167
Class that defines what is a point.
Definition: vpPoint.h:65
static void setLambda(const double &lambda)
set the gain for the virtual visual servoing algorithm
void initPersProjWithoutDistortion(const double px, const double py, const double u0, const double v0)
void open(vpImage< vpRGBa > &I)
int clearPoint()
Suppress all the point in the array of point.
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:203
The vpDisplayOpenCV allows to display image using the opencv library.
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
Generic class defining intrinsic camera parameters.
virtual void setTitle(const char *title)=0
The vpDisplayGTK allows to display image using the GTK+ library version 1.2.
Definition: vpDisplayGTK.h:145
void acquire(vpImage< vpRGBa > &I)
void setFileName(const char *filename)
double get_px() const
Pattern calibrationPattern
unsigned int getHeight() const
Definition: vpImage.h:150
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
static bool readConfigVar(const std::string &var, float &value)
Definition: vpIoTools.cpp:811
std::string input
static int computeCalibrationMulti(vpCalibrationMethodType method, std::vector< vpCalibration > &table_cal, vpCameraParameters &cam, double &globalReprojectionError, bool verbose=false)
bool read(const std::string &filename)
static bool loadConfigFile(const std::string &confFile)
Definition: vpIoTools.cpp:760
void setWorldCoordinates(const double ox, const double oy, const double oz)
Set the point world coordinates. We mean here the coordinates of the point in the object frame...
Definition: vpPoint.cpp:74