63 #include <visp/vpDebug.h>
64 #include <visp/vpParseArgv.h>
65 #include <visp/vpIoTools.h>
72 #include <visp/vpImage.h>
73 #include <visp/vpImageIo.h>
74 #include <visp/vpCalibration.h>
75 #include <visp/vpDisplayX.h>
76 #include <visp/vpDisplayGDI.h>
77 #include <visp/vpDisplayGTK.h>
78 #include <visp/vpDisplayD3D.h>
79 #include <visp/vpMouseButton.h>
81 #include <visp/vpPose.h>
82 #include <visp/vpDot.h>
83 #include <visp/vpDot2.h>
84 #include <visp/vpPixelMeterConversion.h>
85 #include <visp/vpMeterPixelConversion.h>
87 #ifdef VISP_HAVE_OPENCV
88 # include <visp/vpOpenCVGrabber.h>
89 #elif defined(VISP_HAVE_V4L2)
90 # include <visp/vpV4l2Grabber.h>
91 #elif defined(VISP_HAVE_DIRECTSHOW)
92 # include <visp/vpDirectShowGrabber.h>
93 #elif defined(VISP_HAVE_DC1394_2)
94 # include <visp/vp1394TwoGrabber.h>
98 #define GETOPTARGS "di:p:hf:g:n:s:l:cv:"
115 void usage(
const char *name,
const char *badparam, std::string ipath, std::string ppath,
116 double gray,
unsigned first,
unsigned nimages,
unsigned step,
double lambda)
119 Read images of a calibration grid from the disk and \n\
120 calibrate the camera used for grabbing it.\n\
121 Each image corresponds to a PGM file.\n\
122 The calibration grid used here is available in : \n\
123 ViSP-images/calibration/grid2d.{fig,pdf} or \n\
124 ./example/calibration/grid2d.fig\n\
125 This is a 6*6 dots calibration grid where dots centers \n\
126 are spaced by 0.03 meter. You can obviously use another \n\
127 calibration grid changing its parameters in the program.\n\
128 Then you have to grab some images of this grid (you can use \n\
129 grab examples of ViSP to do it), save them as PGM files and\n\
130 precise their names with the -p option.\n\
133 %s [-i <test image path>] [-p <personal image path>]\n\
134 [-g <gray level precision>] [-f <first image>] \n\
135 [-n <number of images>] [-s <step>] [-l lambda] \n\
141 -i <test image path> %s\n\
142 Set image input path.\n\
143 From this path read \"ViSP-images/calibration/grid36-%%02d.pgm\"\n\
144 images and the calibration grid data. \n\
145 These images come from ViSP-images-x.y.z.tar.gz\n\
146 available on the ViSP website.\n\
147 Setting the VISP_INPUT_IMAGE_PATH environment\n\
148 variable produces the same behaviour than using\n\
151 -p <personal image path> %s\n\
152 Specify a personal sequence containing images \n\
154 By image sequence, we mean one file per image.\n\
155 The following image file formats PNM (PGM P5, PPM P6)\n\
156 are supported. The format is selected by analysing \n\
157 the filename extension.\n\
158 Example : \"/Temp/ViSP-images/calibration/grid36-%%02d.pgm\"\n\
159 %%02d is for the image numbering.\n\
161 -g <gray level precision> %f\n\
162 Specify a gray level precision to detect dots.\n\
163 A number between 0 and 1.\n\
164 precision of the gray level of the dot. \n\
165 It is a double precision float witch \n\
166 value is in ]0,1]. 1 means full precision, \n\
167 whereas values close to 0 show a very bad \n\
170 -f <first image> %u\n\
171 First image number of the sequence.\n\
173 -n <number of images> %u\n\
174 Number of images used to compute calibration.\n\
177 Step between two images.\n\
180 Gain of the virtual visual servoing.\n\
183 Disable the image display. This can be useful \n\
184 for automatic tests using crontab under Unix or \n\
185 using the task manager under Windows.\n\
187 -v <generic image name> \n\
188 Record a serie of images using a webcam. A framegrabber (either \n\
189 vpOpenCVGrabber, vpDirectShowGrabber, vp1394TwoGrabber or vpV4l2Grabber) is\n\
190 required. The images are recorded in the disk using the generic name in \n\
191 parameter (for example \"/tmp/img-%%03d.pgm\").\n\
194 Disable the mouse click.\n\
195 If the image display is disabled (using -d)\n\
196 this option is without effect.\n\
199 Print the help.\n\n",
200 ipath.c_str(),ppath.c_str(), gray ,first, nimages, step,lambda);
203 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
234 bool getOptions(
int argc,
const char **argv, std::string &ipath, std::string &ppath,
235 double &gray,
unsigned &first,
unsigned &nimages,
unsigned &step,
236 double &lambda,
bool &display,
bool &click,
bool& opt_video, std::string& opt_video_image_path)
243 case 'd': display =
false;
break;
244 case 'i': ipath = optarg;
break;
245 case 'p': ppath = optarg;
break;
246 case 'g': gray = atof(optarg);
break;
247 case 'f': first = (unsigned) atoi(optarg);
break;
248 case 'n': nimages = (unsigned) atoi(optarg);
break;
249 case 's': step = (unsigned) atoi(optarg);
break;
250 case 'l': lambda = atof(optarg);
break;
251 case 'c': click =
false;
break;
252 case 'v': opt_video =
true; opt_video_image_path = optarg;
break;
253 case 'h': usage(argv[0], NULL, ipath, ppath,gray, first, nimages, step, lambda);
257 usage(argv[0], optarg, ipath, ppath, gray,first, nimages, step, lambda);
262 if ((c == 1) || (c == -1)) {
264 usage(argv[0], NULL, ipath, ppath,gray, first, nimages, step, lambda);
265 std::cerr <<
"ERROR: " << std::endl;
266 std::cerr <<
" Bad argument " << optarg << std::endl << std::endl;
273 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_D3D9))
275 #if defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_V4L2) || defined(VISP_HAVE_DIRECTSHOW) || defined(VISP_HAVE_DC1394_2)
287 unsigned int recordImageSequence(
const std::string& out_path,
const unsigned int opt_step,
const unsigned int first_image);
290 int main(
int argc,
const char ** argv)
305 double sizePrecision = 0.5 ;
309 unsigned int sizeX = 6;
310 unsigned int sizeY = 6;
311 unsigned int nbpt = sizeX*sizeY;
313 const unsigned int nptPose = 4;
322 std::list<double> LoX,LoY,LoZ;
334 for (
unsigned int i=0 ; i < sizeX ; i++){
335 for(
unsigned int j=0 ; j < sizeY ; j++){
336 LoX.push_back(i*Lx) ;
337 LoY.push_back(j*Ly) ;
344 std::string env_ipath;
345 std::string opt_ipath;
347 std::string opt_ppath;
349 std::string filename;
350 std::string filename_out;
351 char comment[FILENAME_MAX];
352 double opt_gray = 0.7;
353 unsigned opt_first = 1;
354 unsigned opt_nimages = 4;
355 unsigned opt_step = 1;
356 double opt_lambda = 0.5;
357 bool opt_display =
true;
358 bool opt_click =
true;
360 bool opt_video =
false;
361 std::string opt_video_image_path;
365 char *ptenv = getenv(
"VISP_INPUT_IMAGE_PATH");
370 if (! env_ipath.empty())
374 if (getOptions(argc, argv, opt_ipath, opt_ppath,opt_gray,opt_first, opt_nimages,
375 opt_step, opt_lambda, opt_display, opt_click, opt_video, opt_video_image_path) ==
false) {
380 #if (defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_V4L2) || defined(VISP_HAVE_DIRECTSHOW) || defined(VISP_HAVE_DC1394_2))
382 std::cerr << std::endl
383 <<
"ERROR:" << std::endl;
384 std::cerr <<
"Incompatible options -v and -d." << std::endl;
388 std::cerr << std::endl
389 <<
"ERROR:" << std::endl;
390 std::cerr <<
"Incompatible options -v and -c." << std::endl;
393 if(!opt_ipath.empty()){
394 std::cerr << std::endl
395 <<
"ERROR:" << std::endl;
396 std::cerr <<
"Incompatible options -v and -i." << std::endl;
399 if(!opt_ppath.empty()){
400 std::cerr << std::endl
401 <<
"ERROR:" << std::endl;
402 std::cerr <<
"Incompatible options -v and -p." << std::endl;
405 if(opt_video_image_path.empty()){
406 std::cerr << std::endl
407 <<
"ERROR:" << std::endl;
408 std::cerr <<
"output image path empty." << std::endl;
412 opt_nimages = recordImageSequence(opt_video_image_path, opt_step, opt_first);
418 opt_ipath = opt_video_image_path;
419 opt_ppath = opt_video_image_path;
422 std::cerr << std::endl
423 <<
"ERROR:" << std::endl;
424 std::cerr <<
"No framegrabber installed with ViSP. Cannot record images from video stream." << std::endl;
434 if (!opt_ipath.empty())
439 if (opt_ipath.empty() && opt_ppath.empty()) {
440 if (ipath != env_ipath) {
441 std::cout << std::endl
442 <<
"WARNING: " << std::endl;
443 std::cout <<
" Since -i <visp image path=" << ipath <<
"> "
444 <<
" is different from VISP_INPUT_IMAGE_PATH=" << env_ipath << std::endl
445 <<
" we skip the environment variable." << std::endl;
450 if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty() ){
451 usage(argv[0], NULL, ipath, opt_ppath, opt_gray, opt_first, opt_nimages,
452 opt_step, opt_lambda);
453 std::cerr << std::endl
454 <<
"ERROR:" << std::endl;
455 std::cerr <<
" Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
457 <<
" environment variable to specify the location of the " << std::endl
458 <<
" image path where test images are located." << std::endl
459 <<
" Use -p <personal image path> option if you want to "<<std::endl
460 <<
" use personal images." << std::endl
471 unsigned iter = opt_first;
472 std::ostringstream s;
473 char cfilename[FILENAME_MAX];
475 if (opt_ppath.empty()){
495 s.setf(std::ios::right, std::ios::adjustfield);
496 s <<
"grid36-" << std::setw(2) << std::setfill(
'0') << iter <<
".pgm";
497 filename = dirname + s.str();
501 sprintf(cfilename,opt_ppath.c_str(), iter) ;
502 filename = cfilename;
519 std::cerr << std::endl
520 <<
"ERROR:" << std::endl;
521 std::cerr <<
" Cannot read " << filename << std::endl;
522 std::cerr <<
" Check your -i " << ipath <<
" option, " << std::endl
523 <<
" or your -p " << opt_ppath <<
" option " <<std::endl
524 <<
" or VISP_INPUT_IMAGE_PATH environment variable"
533 unsigned int niter = 0;
536 while (iter < opt_first + opt_nimages*opt_step) {
540 if (opt_ppath.empty()){
542 s <<
"grid36-" << std::setw(2) << std::setfill(
'0') << iter<<
".pgm";
543 filename = dirname + s.str();
546 sprintf(cfilename, opt_ppath.c_str(), iter) ;
547 filename = cfilename;
549 filename_out = filename +
".txt";
551 std::cout <<
"read : " << filename << std::endl;
561 #if defined VISP_HAVE_GDI
563 #elif defined VISP_HAVE_GTK
565 #elif defined VISP_HAVE_X11
567 #elif defined VISP_HAVE_D3D9
577 sprintf(title,
"Calibration initialization on image %s", (s.str()).c_str());
578 display.
init(I, 100, 100, title) ;
600 for(
unsigned int i=0;i<nptPose;i++) {
618 std::printf(
"click in the dot %d of coordinates\nx=%f y=%f z=%f \n",
619 i+1 ,P[i].get_oX(),P[i].get_oY(),P[i].get_oZ());
620 std::sprintf(comment,
"Click in the dot %d",i+1 );
626 for(
unsigned int j = 0;j<i;j++)
681 for (
unsigned int i=0 ; i < nptPose ; i++){
695 for (
unsigned int i=0 ; i < nptPose ; i++){
700 calib.
addPoint(P[i].get_oX(),P[i].get_oY(),P[i].get_oZ(), cog);
730 "A left click to define other dots.",
735 "A middle click to don't care of this pose.",
738 std::cout <<
"\nPose computation failed." << std::endl;
739 std::cout <<
"A left click to define other dots." << std::endl;
740 std::cout <<
"A middle click to don't care of this pose." << std::endl;
745 std::cout <<
"Left click has been pressed." << std::endl;
748 std::cout <<
"Right click has been pressed." << std::endl;
751 std::cout <<
"Middle click has been pressed." << std::endl;
766 for(
unsigned int j = 0;j<nptPose;j++)
775 "A left click to display grid.",
780 "A right click to define other dots.",
783 std::cout <<
"\nA a left click to display grid." << std::endl;
784 std::cout <<
"A right click to define other dots." << std::endl;
789 std::cout <<
"Left click has been pressed." << std::endl;
792 std::cout <<
"Middle click has been pressed." << std::endl;
795 std::cout <<
"Right click has been pressed." << std::endl;
803 for(
unsigned i =0 ; i<nptPose ;i++){
810 for(
unsigned int i=0;i<nbpt;i++){
836 std::list<double>::const_iterator it_LoX = LoX.begin();
837 std::list<double>::const_iterator it_LoY = LoY.begin();
838 std::list<double>::const_iterator it_LoZ = LoZ.begin();
840 for(
unsigned int i = 0 ; i < nbpt ; i++){
849 bool* valid =
new bool[nbpt];
850 for (
unsigned int i=0 ; i < nbpt ; i++){
876 mP[i].
display(I,cMoTmp,camTmp) ;
884 else {valid[i] =
false;}
895 table_cal[niter].
writeData(filename_out.c_str());
898 sprintf(title,
"Extracted 2D data from image %s", (s.str()).c_str());
904 "A left click to validate this pose.",
909 "A right click to retry.",
914 "A middle click to don't care of this pose.",
918 std::cout <<
"\nA left click to validate this pose." << std::endl;
919 std::cout <<
"A right click to retry." << std::endl;
920 std::cout <<
"A middle click to don't care of this pose." << std::endl;
925 std::cout <<
"\nLeft click has been pressed." << std::endl;
928 std::cout <<
"Middle click has been pressed." << std::endl;
929 for (
unsigned int i=0 ; i < nbpt ; i++)
933 std::cout <<
"Right click has been pressed." << std::endl;
938 for (
unsigned int i=0 ; i < nbpt ; i++){
942 table_cal[niter].
addPoint(mP[i].get_oX(),mP[i].get_oY(),mP[i].get_oZ(), cog) ;
970 while (iter < opt_first + opt_nimages*opt_step) {
974 if (opt_ppath.empty()){
976 s <<
"grid36-" << std::setw(2) << std::setfill(
'0') << iter<<
".pgm";
977 filename = dirname + s.str();
980 sprintf(cfilename, opt_ppath.c_str(), iter) ;
981 filename = cfilename;
984 std::cout <<
"read : " << filename << std::endl;
987 if(table_cal[niter].get_npt()!=0){
988 std::cout <<
"\nCompute standard deviation for pose " << niter <<std::endl;
989 double deviation, deviation_dist ;
991 std::cout <<
"deviation for model without distortion : "
992 << deviation << std::endl;
993 std::cout <<
"deviation for model with distortion : "
994 << deviation_dist << std::endl;
998 std::cout <<
"This image has not been used!" << std::endl;
1000 #if defined VISP_HAVE_GDI
1002 #elif defined VISP_HAVE_GTK
1004 #elif defined VISP_HAVE_X11
1007 #elif defined VISP_HAVE_D3D9
1016 sprintf(title,
"Calibration results for image %s", (s.str()).c_str());
1017 display.
init(I, 100, 100, title) ;
1027 delete [] table_cal;
1042 std::cout <<
"\nA click to continue..." << std::endl;
1049 delete [] table_cal;
1056 delete [] table_cal;
1061 #if defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_V4L2) || defined(VISP_HAVE_DIRECTSHOW) || defined(VISP_HAVE_DC1394_2)
1062 unsigned int recordImageSequence(
const std::string& out_path,
const unsigned int opt_step,
const unsigned int first_image)
1064 unsigned int nbImg = first_image;
1065 unsigned int index = 0;
1067 #ifdef VISP_HAVE_OPENCV
1069 #elif defined(VISP_HAVE_V4L2)
1071 #elif defined(VISP_HAVE_DIRECTSHOW)
1073 #elif defined(VISP_HAVE_DC1394_2)
1083 #if defined VISP_HAVE_GDI
1085 #elif defined VISP_HAVE_GTK
1087 #elif defined VISP_HAVE_X11
1089 #elif defined VISP_HAVE_D3D9
1092 display.
init(I, 100, 100,
"record sequence for the calibration.");
1094 bool isOver =
false;
1095 std::cout <<
"Left click to record the current image." << std::endl;
1096 std::cout <<
"Right click to stop the acquisition." << std::endl;
1111 char curImgName[FILENAME_MAX];
1112 sprintf(curImgName, out_path.c_str(), nbImg);
1116 std::cout <<
"write image : " << curImgName << std::endl;
1120 std::cerr << std::endl
1121 <<
"ERROR." << std::endl
1122 <<
"Cannot record the image : " << curImgName << std::endl
1123 <<
"Check the path and the permissions." << std::endl;
1141 #else // (defined (VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)...)
1146 vpTRACE(
"X11 or GTK or GDI or D3D functionnality is not available...") ;
1148 #endif // (defined (VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)...)
void set_j(const double j)
void projection(const vpColVector &_cP, vpColVector &_p)
Projection onto the image plane of a point. Input: the 3D coordinates in the camera frame _cP...
int displayGrid(vpImage< unsigned char > &I, vpColor color=vpColor::yellow, unsigned int thickness=1)
static void readPGM(vpImage< unsigned char > &I, const char *filename)
unsigned int getWidth() const
The class provides a data structure for the homogeneous matrices as well as a set of operations on th...
static void convertPoint(const vpCameraParameters &cam, const double &x, const double &y, double &u, double &v)
Point coordinates conversion from normalized coordinates in meter to pixel coordinates ...
Display for windows using GDI (available on any windows 32 platform).
void display(const vpImage< unsigned char > &I, const vpCameraParameters &cam, const vpColor &color=vpColor::green, const unsigned int thickness=1)
Define the X11 console to display images.
void set_i(const double i)
static void writePGM(const vpImage< unsigned char > &I, const char *filename)
int addPoint(double X, double Y, double Z, vpImagePoint &ip)
void set_x(const double x)
Set the point x coordinate in the image plane.
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
Point coordinates conversion from pixel coordinates to normalized coordinates in meter...
class for windows direct show devices
Tools for perspective camera calibration.
void acquire(vpImage< unsigned char > &I)
This tracker is meant to track a blob (connex pixels with same gray level) on a vpImage.
static void flush(const vpImage< unsigned char > &I)
int computeCalibration(vpCalibrationMethodType method, vpHomogeneousMatrix &cMo, vpCameraParameters &cam, bool verbose=false)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
static Type abs(const Type &x)
Class that defines what is a point.
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)
vpImagePoint getCog() const
void open(vpImage< unsigned char > &I)
Display for windows using Direct3D.
void setGrayLevelPrecision(const double &grayLevelPrecision)
static void display(vpImage< unsigned char > &I, vpHomogeneousMatrix &cMo, vpCameraParameters &cam, double size, vpColor col=vpColor::none)
int displayData(vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1)
int clearPoint()
Suppress all the point in the array of point.
static void display(const vpImage< unsigned char > &I)
Class used for pose computation from N points (pose from point only).
Generic class defining intrinsic camera parameters.
void set_y(const double y)
Set the point y coordinate in the image plane.
virtual void setTitle(const char *title)=0
static int computeCalibrationMulti(vpCalibrationMethodType method, unsigned int nbPose, vpCalibration table_cal[], vpCameraParameters &cam, bool verbose=false)
The vpDisplayGTK allows to display image using the GTK+ library version 1.2.
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const char *title=NULL)
static void close(const vpImage< unsigned char > &I)
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1)
Class for the Video4Linux2 video device.
void setSizePrecision(const double &sizePrecision)
Class that provides a data structure for the column vectors as well as a set of operations on these v...
virtual void displayCharString(const vpImagePoint &ip, const char *text, const vpColor &color=vpColor::green)=0
int writeData(const char *filename)
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
unsigned int getHeight() const
Class for firewire ieee1394 video devices using libdc1394-2.x api.
Defines a rectangle in the plane.
void computePose(vpPoseMethodType methode, vpHomogeneousMatrix &cMo)
compute the pose for a given method
virtual bool getClick(bool blocking=true)=0
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
void computeStdDeviation(double &deviation, double &deviation_dist)
void changeFrame(const vpHomogeneousMatrix &cMo, vpColVector &_cP)
static const vpColor yellow
void addPoint(const vpPoint &P)
Add a new point in this array.
void setGraphics(const bool activate)
Class for cameras video capture using OpenCV library.
static const vpColor blue
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...
void clearPoint()
suppress all the point in the array of point