Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
GenSynthMatchesRig.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 #include <iostream>
26 #include <sstream>
27 #include <string>
28 #include <climits>
29 #include <cfloat>
30 
31 #include <Base/Debug/LogFacility.hh>
32 #include "GenSynthMatchesRig.hh"
33 #include <Base/ImageUtils/ImageDraw.hh>
34 #include <Geometry/PMatrix.hh>
35 
36 using namespace BIAS;
37 using namespace std;
38 
39 /**
40  Prints the contained GenSynthMatches objects to the given ostream.
41 */
42 ostream& BIAS::operator<<(ostream& os, const GenSynthMatchesRig& m)
43 {
44  std::vector<BIAS::GenSynthMatches> cams = m.GetCams();
45  std::vector<BIAS::GenSynthMatches>::iterator it;
46  int i;
47  for (it = cams.begin(), i=0;
48  it != cams.end();
49  it++, i++) {
50  os << "Camera " << i << ": " << std::endl
51  << *it << std::endl;
52  }
53  return os;
54 }
55 
56 /**
57  Constructor. Registers the needed parameters in the param object. The values
58  can then be filled externally, e.g. by a param file. The object GenMatches_
59  of type #BIAS::GenSynthMatches is initialized with the param object - this
60  way GenMatches will register all parameters needed for a GenSynthMatches
61  object in the argument of the constructor. In #AddParameters_() the special
62  parameters of this class will become registered.
63  @param para A parameter object.
64  @see BIAS::Param for information on Param objects.
65  @note The parameters should be set externally. First the parameters have to
66  be registered. Then, before creating matches, the values should be filled
67  by the user (e.g. reading the parameters from a file).
68  */
70  : GenMatches_(para)
71 {
72  allParams_=&para;
73  //change the param values - moving points are not yet supported
74  *para.GetParamInt("NumPoints") = *para.GetParamInt("NumPoints")
75  - *para.GetParamInt("NumMovingPoints");
76  *para.GetParamInt("NumMovingPoints") = 0;
77  *para.GetParamInt("NumMovingObjects") = 0;
78  //add parameters needed for this class
80 }
81 
82 /**
83  Default destructor...
84 */
86 {}
87 
88 /**
89  Here the values of the param (object/file) are assigned to the member
90  variables with the #GetParameters_() method. In the next step, the vector
91  #SlaveCamsGlobal_ containing the global poses of the slave cameras is being
92  filled. The global poses are computed by applying the movement of the
93  master camera (first camera) to the slave cameras (which have known relative
94  transforms to the master camera).
95  @pre The vector containing the moving information must contain at least
96  as many elements as number of images given in the param object.
97  @pre The number of cameras must not be greater then
98  #GENSYNTHMATCHESRIG_MAX_NR_OF_CAMERAS.
99  */
101  //read the parameters from the param object
102  GetParameters_();
103 
104  int numImages = *(allParams_->GetParamInt("NumImages"));
105 
106  //for each slave cam
107  //- the # of slave cams is # of cams without the master cam
108  for (int slavecam = 0; slavecam < *NumCameras_-1; slavecam++) {
109 
110  std::vector<std::map<std::string, double> > tmpVec;
111  //for each timestep
112  for (int timestep = 0; timestep < numImages; timestep++) {
113  //get the coordinate transform of the master camera:
114  BIAS::Vector3<double> CMaster(MasterCenterX_[timestep],
115  MasterCenterY_[timestep],
116  MasterCenterZ_[timestep]);
118 
119  RMaster.SetXYZ(MasterAnglesX_[timestep],
120  MasterAnglesY_[timestep],
121  MasterAnglesZ_[timestep]);
122  //set the (global) master camera transform to the given center
123  //and angles
124  RMatrix RMasterInv = RMaster;
125  RMasterInv.TransposeIP();
126  BIAS::Matrix4x4<double> masterTransform(RMaster, CMaster);
127  //and get the inverse of the master coordinate transform:
128  RMaster.TransposeIP();
129  BIAS::Vector3<double> CMasterInv = RMaster * (-1.0 * CMaster);
130  BIAS::Matrix4x4<double> masterTransformInv(RMaster, CMasterInv);
131 
132  //get the relative transform between master and current slave camera:
133  BIAS::Vector3<double> CSlave(SlaveCamsRelative_[slavecam]["relPosX"],
134  SlaveCamsRelative_[slavecam]["relPosY"],
135  SlaveCamsRelative_[slavecam]["relPosZ"]);
136 
138  RSlave.SetXYZ(SlaveCamsRelative_[slavecam]["relRotX"],
139  SlaveCamsRelative_[slavecam]["relRotY"],
140  SlaveCamsRelative_[slavecam]["relRotZ"]);
141 
142  //set the local transform relative to the master camera:
143  // BIAS::Matrix4x4<double> slaveTransform(RSlave, RSlave * CSlave);
144  RMatrix RSlaveInv = RSlave.Transpose();
145  BIAS::Matrix4x4<double> slaveTransform(RSlave, CSlave);
146 
147  BIAS::Matrix4x4<double> slaveTransformInv(RSlaveInv, RSlaveInv * (-1.0 * CSlave));
148 
149  //////////////////
150  /*
151  BIAS::Vector3<double> CMaster2(MasterCenterX_[timestep],
152  MasterCenterY_[timestep],
153  MasterCenterZ_[timestep]);
154  BIAS::RMatrix RMaster2(BIAS::MatrixIdentity);
155 
156  RMaster2.SetXYZ(MasterAnglesX_[timestep],
157  MasterAnglesY_[timestep],
158  MasterAnglesZ_[timestep]);
159 
160  BIAS::Vector3<double> CSlave2(SlaveCamsRelative_[slavecam]["relPosX"],
161  SlaveCamsRelative_[slavecam]["relPosY"],
162  SlaveCamsRelative_[slavecam]["relPosZ"]);
163 
164  BIAS::RMatrix RSlave2 = BIAS::RMatrix(BIAS::MatrixIdentity);
165  RSlave2.SetXYZ(SlaveCamsRelative_[slavecam]["relRotX"],
166  SlaveCamsRelative_[slavecam]["relRotY"],
167  SlaveCamsRelative_[slavecam]["relRotZ"]);
168 
169  RMatrix RSlaveGlobal2 = RMaster2 * RSlave2;
170 
171  BIAS::Vector3<double> SlaveCGlobal =
172  RMaster2 * CSlave2 + CMaster2;
173 
174  std::map<std::string, double> tmpMap;
175  //get the global center of the slave cam - read from the global
176  //coord transform matrix
177  tmpMap["GlobalPosX"] = SlaveCGlobal[0];
178  tmpMap["GlobalPosY"] = SlaveCGlobal[1];
179  tmpMap["GlobalPosZ"] = SlaveCGlobal[2];
180 
181  double aX, aY, aZ;
182  RSlaveGlobal2.GetRotationAnglesXYZ(aX, aY, aZ);
183  tmpMap["GlobalAnglesX"] = aX;
184  tmpMap["GlobalAnglesY"] = aY;
185  tmpMap["GlobalAnglesZ"] = aZ;
186 
187  ///////////////////
188  */
189  //get global coord transform of the current slave camera:
190  BIAS::Matrix4x4<double> TGlobal = masterTransform * slaveTransform;
191  // * masterTransformInv;
192  // TGlobal = BIAS::Matrix4x4<double>(RSlave * RMaster, RMaster * CSlave);
193  // cout << TGlobal;
194  //map to store the computed global pose of the current slave camera
195  std::map<std::string, double> tmpMap;
196  //get the global center of the slave cam - read from the global
197  //coord transform matrix
198  tmpMap["GlobalPosX"] = TGlobal[0][3];
199  tmpMap["GlobalPosY"] = TGlobal[1][3];
200  tmpMap["GlobalPosZ"] = TGlobal[2][3];
201 
202  //set up the rotation matrix of the global transform of the slave camera
203  BIAS::Matrix<double> RGlobal(3,3);
204  RGlobal[0][0] = TGlobal[0][0];
205  RGlobal[0][1] = TGlobal[0][1];
206  RGlobal[0][2] = TGlobal[0][2];
207 
208  RGlobal[1][0] = TGlobal[1][0];
209  RGlobal[1][1] = TGlobal[1][1];
210  RGlobal[1][2] = TGlobal[1][2];
211 
212  RGlobal[2][0] = TGlobal[2][0];
213  RGlobal[2][1] = TGlobal[2][1];
214  RGlobal[2][2] = TGlobal[2][2];
215 
216  //convert to a matrix of type rotation matrix (BIAS::RMatrix).
217  BIAS::RMatrix RGlobal2(RGlobal);
218  //read the global rotation angles to the vectors of the slave camera.
219  double aX, aY, aZ;
220  RGlobal2.GetRotationAnglesXYZ(aX, aY, aZ);
221  tmpMap["GlobalAnglesX"] = aX;
222  tmpMap["GlobalAnglesY"] = aY;
223  tmpMap["GlobalAnglesZ"] = aZ;
224 
225  /* cout << "GlobalX: " << TGlobal[0][3]
226  << "GlobalY: " << TGlobal[1][3]
227  << "GlobalZ: " << TGlobal[2][3]
228  << "AngleX: " << aX
229  << "AngleY: " << aY
230  << "AngleZ: " << aZ << endl;
231  */
232  //store the global pose of the current slave cam in the vector
233  //containing all poses (for each timestep) of that slave camera.
234  tmpVec.push_back(std::map<std::string, double>(tmpMap));
235  } //for each time step
236  //store the current slave cam in the vector containing the poses of all
237  //slave cams at each time step.
238  SlaveCamsGlobal_.push_back(VecOMapOStrDbl(tmpVec));
239  } //for each slave cam
240 
241 #ifdef BIAS_DEBUG
242  /*
243  //print out the global poses of the slave cameras:
244  cout << *NumCameras_ << "x" << numImages << " Images: " << endl;
245  std::vector<VecOMapOStrDbl >::iterator slaves;
246  std::vector<std::map<std::string, double> >::iterator timest;
247  std::map<std::string, double>::iterator data;
248  int a,b;
249  for (slaves = SlaveCamsGlobal_.begin(), a=0;
250  slaves != SlaveCamsGlobal_.end(); slaves++, a++) {
251  cout << "slave cam " << a << ":" << endl;
252  for (timest = ((*slaves).vecOMaps).begin(), b=0;
253  timest != ((*slaves).vecOMaps).end();
254  timest++, b++) {
255  cout << "\t" << "timestep " << b << ":" << endl;
256  for (data = (*timest).begin(); data != (*timest).end(); data++) {
257  cout << "\t\t" << data->first << " ==> " << data->second << endl;
258  }
259  }
260  }
261  */
262 #endif
263 }
264 
265 /**
266  Read the parameters from the param object. The relative transformations
267  of the slave cameras to the master camera are stored in #SlaveCamsRelative_.
268 */
270 {
271 #ifdef BIASASSERT_ISACTIVE
272  int numImages = *(allParams_->GetParamInt("NumImages"));
273 #endif
274 
275  NumCameras_ = allParams_->GetParamInt("NumCameras");
276  if (*NumCameras_ > GENSYNTHMATCHESRIG_MAX_NR_OF_CAMERAS) {
277  BIASERR("Only " << GENSYNTHMATCHESRIG_MAX_NR_OF_CAMERAS << " allowed...");
278  BIASABORT;
279  }
280  //these values do exist, because they will be filled by the GenSynthMatches
281  //class. They can be reset by changing the values of the param object passed
282  //to the constructor.
283  MasterCenterX_ = *(allParams_->GetParamVecDbl("MotionVecX"));
284  BIASASSERT(MasterCenterX_.size() >= numImages);
285  MasterCenterY_ = *(allParams_->GetParamVecDbl("MotionVecY"));
286  BIASASSERT(MasterCenterY_.size() >= numImages);
287  MasterCenterZ_ = *(allParams_->GetParamVecDbl("MotionVecZ"));
288  BIASASSERT(MasterCenterZ_.size() >= numImages);
289  MasterAnglesX_ = *(allParams_->GetParamVecDbl("RotVecX"));
290  BIASASSERT(MasterAnglesX_.size() >= numImages);
291  MasterAnglesY_ = *(allParams_->GetParamVecDbl("RotVecY"));
292  BIASASSERT(MasterAnglesY_.size() >= numImages);
293  MasterAnglesZ_ = *(allParams_->GetParamVecDbl("RotVecZ"));
294  BIASASSERT(MasterAnglesZ_.size() >= numImages);
295 
296  std::map<std::string, double> myMap;
297  stringstream oss;
298  SlaveCamsRelative_.clear();
299  for (int i = 1; i <= GENSYNTHMATCHESRIG_MAX_NR_OF_CAMERAS; i++) {
300  oss << i;
301  //X component
302  myMap["relPosX"] =
303  *(allParams_->GetParamDouble("Cam" + oss.str() + "_RelPosX"));
304  //Y component
305  myMap["relPosY"] =
306  *(allParams_->GetParamDouble("Cam" + oss.str() + "_RelPosY"));
307  //Z component
308  myMap["relPosZ"] =
309  *(allParams_->GetParamDouble("Cam" + oss.str() + "_RelPosZ"));
310  //rotation angle X
311  myMap["relRotX"] =
312  *(allParams_->GetParamDouble("Cam" + oss.str() + "_RelRotX"));
313  //rotation angle Y
314  myMap["relRotY"] =
315  *(allParams_->GetParamDouble("Cam" + oss.str() + "_RelRotY"));
316  //rotation angle Z
317  myMap["relRotZ"] =
318  *(allParams_->GetParamDouble("Cam" + oss.str() + "_RelRotZ"));
319 
320  SlaveCamsRelative_.push_back(myMap);
321  oss.str(""); //clear the stream
322  } //for each slave camera
323 }
324 
325 /**
326  Generates 3D Points an creates the 2D matches for each camera at each time
327  step. At first #Setup_() is beenig called to compute the poses of the slave
328  cameras in the global coord system (which hast its origin at the center of
329  the master camera).
330  For each camera an BIAS::GenSynthMatches object will be created. The object
331  assigned to the master cam creates random 3D Points which will be passed to
332  the slave cameras. So all cameras work with the same 3D points and try to
333  generate 2D matches for them. If a 3D point has no match with an image plane
334  of a camera, the 3D point will be replaced. After 1000 reties the computation
335  will abort.
336  @return 0, if OK. -1, if too many iterations.
337  @todo Moving objects not yet supported.
338 */
340 {
341  //allParams_->ShowData();
342  Setup_();
343  //GenSynthMatches object for the master camera
344  BIAS::GenSynthMatches masterCam(*allParams_);
345 
346  //create 3D points for the master camera
347  masterCam.Create3DPoints();
348 
349  int res = -1; //result of the creation of the 2D matches.
350  int counter = 0; //counter - not to loop forever...
351 
352  while (res != 0 && counter < 1000) {
353  //create matches for the newly generated point(s)
354  int index;
355  if (masterCam.CreateMatches(index) ==
356  GSM_RETURN_ERROR_HANDLING_STATIC_POINT) {
357  BIASERR("Could not set up master camera.");
358  BIASABORT;
359  }
360 
361  //get the newly generated static 3D points of the master camera
362  std::vector<BIAS::HomgPoint3D> staticPoints;
363  masterCam.GetStatic3DPoints(staticPoints);
364 
365  //get the newly generated moving 3D points of the master camera
366  std::vector<BIAS::HomgPoint3D> movingPoints;
367  masterCam.GetMoving3DPoints(movingPoints);
368 
369  //store the GenSynthMatches object in the vector
370  CamMatches_.push_back(masterCam);
371 
372  //for each slave camera (starting with 1 because 0 is the master camera)
373  for (int slaveCamIndex = 1; slaveCamIndex < *NumCameras_; slaveCamIndex++){
374  //update the parameters for the current slave cam. (cam motion)
375  UpdateParams_(slaveCamIndex);
376  //create a new object for the slave cam
378  slaveCam.CreateCamMovement();
379  slaveCam.CreateMovingTransforms();
380  //set up the 3D points equal to the 3D points of the master camera
381  slaveCam.SetStatic3DPoints(staticPoints);
382  slaveCam.SetMoving3DPoints(movingPoints);
383  //Create 2D matches for the slave cam
384  res = slaveCam.CreateMatches(index);
385  //store the matches
386  CamMatches_.push_back(slaveCam);
387  //if an error occured (a 3D point could not be projected into the current
388  //image plane) the bad point will be replaced in the master cam an all
389  //computation for the slave cams will restart.
390  if (res == GSM_RETURN_ERROR_HANDLING_STATIC_POINT) {
391  BLD("bad index was " << index << " static object not seen "
392  << "in slaveCam "
393  << slaveCamIndex
394  << " - trying again... (" << counter+1 << "/1000)" << endl);
395  CamMatches_.clear();
396  //generate a new 3D point and replace the bad 3D point
397  masterCam.CreateStatic3DPoint(index);
398  counter++;
399  break;
400  } else if (res == GSM_RETURN_ERROR_HANDLING_MOVING_POINT) {
401  BLD("bad index was " << index << " moving object not seen "
402  << "in slaveCam "
403  << slaveCamIndex
404  << " - trying again... (" << counter+1 << "/1000)" << endl);
405  CamMatches_.clear();
406  //generate a new 3D point and replace the bad 3D point
407  masterCam.CreateMoving3DPoint(index);
408  counter++;
409  break;
410  } else if (res != GSM_RETURN_OK) {
411  BIASERR("Unexpected result ( " << res << ")");
412  BIASABORT;
413  }
414  } //for each slave camera
415  } //while
416  if (counter >= 1000) {
417  BIASERR("Could not find a solution for all cameras (1000 trials). Maybe no"
418  << " common viewing volume.");
419  return -1;
420  }
421  return 0;
422 }
423 
424 
425 /**
426  Updates the parameters for a given slave camera. The parameters are updated
427  before the 2D matches are computed for a #BIAS::GenSynthMatches object of
428  a slave camera. The values of the poses (motion/rotation vectors) of the
429  camera of the #BIAS::GenSynthMatches object will be filled with the global
430  poses of the given slave cam.
431  @param[in] camID The ID of the camera to be updated.
432  @note The master cam must not be updated. All values are set initially.
433 */
435  //be sure we don't have the master cam here.
436  BIASASSERT(camID > 0);
437  //get the number of images to be computed
438  int numImages = *(allParams_->GetParamInt("NumImages"));
439  //set up the global pose vectors with the needed length
440  BIAS::Vector<double> centerX(numImages);
441  BIAS::Vector<double> centerY(numImages);
442  BIAS::Vector<double> centerZ(numImages);
443  BIAS::Vector<double> anglesX(numImages);
444  BIAS::Vector<double> anglesY(numImages);
445  BIAS::Vector<double> anglesZ(numImages);
446 
447  //master cam is ID 0. slave cams start with 1, but are stored starting with
448  //index 0 in the SlaveCamsGlobal_ vector.
449  std::vector<std::map<std::string, double> > currentSlave =
450  SlaveCamsGlobal_[camID -1].vecOMaps;
451  //for number of images
452  for (int i = 0; i < numImages; i++) {
453  //set up the vectors with the global poses of the slave cam
454  centerX[i] = currentSlave[i]["GlobalPosX"];
455  centerY[i] = currentSlave[i]["GlobalPosY"];
456  centerZ[i] = currentSlave[i]["GlobalPosZ"];
457  anglesX[i] = currentSlave[i]["GlobalAnglesX"];
458  anglesY[i] = currentSlave[i]["GlobalAnglesY"];
459  anglesZ[i] = currentSlave[i]["GlobalAnglesZ"];
460  }
461 
462 #ifdef BIAS_DEBUG
463  /*
464  cout << "Centers of slaveCam " << camID << ":";
465  cout << centerX << "/" << centerY <<"/" << centerZ << endl;
466  cout << "angles:";
467  cout << anglesX << "/" << anglesY <<"/" << anglesZ << endl;
468  */
469 #endif
470 
471  //assign the vectors to the parameters
472  *(allParams_->GetParamVecDbl("MotionVecX")) = centerX;
473  *(allParams_->GetParamVecDbl("MotionVecY")) = centerY;
474  *(allParams_->GetParamVecDbl("MotionVecZ")) = centerZ;
475  *(allParams_->GetParamVecDbl("RotVecX")) = anglesX;
476  *(allParams_->GetParamVecDbl("RotVecY")) = anglesY;
477  *(allParams_->GetParamVecDbl("RotVecZ")) = anglesZ;
478  // cout << "centerX: " << centerX << " ParamCenterX: "
479  // << *(allParams_->GetParamVecDbl("MotionVecX")) << endl;
480 }
481 
482 /**
483  Create images for all cameras showing the matches.
484  @param[out] imgs The vector containing the computed images. The image will
485  be drawn based the ground truth data.
486  @param[in] minindex The index (time step) to start with.
487  @param[in] maxindex The index (time step) to end with.
488  */
490  &imgs, int minindex, int maxindex) const
491 {
492  for (int i = 0; i < *NumCameras_; i++) {
494  CamMatches_[i].DrawTrue(im, minindex, maxindex);
495  imgs.push_back(im);
496  }
497 }
498 
499 /**
500  Create an image for a camera.
501  @param[out] img The resulting image. The image will be drawn
502  based on the ground truth data.
503  @param[in] minindex The index (time step) to start with.
504  @param[in] maxindex The index (time step) to end with.
505  @param[in] camIndex The index of the camera to get the image from.
506 */
508  int maxindex, int camIndex) const
509 {
510  if (camIndex < (int)CamMatches_.size() && camIndex >= 0) {
511  CamMatches_[camIndex].DrawTrue(img, minindex, maxindex);
512  } else {
513  BIASERR("Could not draw image for camera at index " << camIndex << ". "
514  << "only " << CamMatches_.size() << " cameras available.");
515  }
516 }
517 
518 /**
519  Create images for all cameras showing the matches.
520  @param[out] imgs The vector containing the computed images. The image will
521  be drawn based on the noisy data.
522  @param[in] minindex The index (time step) to start with.
523  @param[in] maxindex The index (time step) to end with.
524  */
526  int minindex, int maxindex) const
527 {
528  for (int i = 0; i < *NumCameras_; i++) {
530  CamMatches_[i].DrawNoisy(im, minindex, maxindex);
531  imgs.push_back(im);
532  }
533 }
534 
535 /**
536  Create an image for a camera.
537  @param[out] img The resulting image. The image will be drawn
538  based on the noisy data.
539  @param[in] minindex The index (time step) to start with.
540  @param[in] maxindex The index (time step) to end with.
541  @param[in] camIndex The index of the camera to get the image from.
542 */
544  int maxindex, int camIndex) const
545 {
546  if (camIndex < (int)CamMatches_.size() && camIndex >= 0) {
547  CamMatches_[camIndex].DrawNoisy(img, minindex, maxindex);
548  } else {
549  BIASERR("Could not draw image for camera at index " << camIndex << ". "
550  << "only " << CamMatches_.size() << " cameras available.");
551  }
552 }
553 
554 /**
555  Write the necessary components of this object to an xml file. These are:
556  - The contained GenStynthMatches objects, which is stored by setting a
557  file name in the attribute of each "Camera" node. These will be stored
558  to <given_filename>.cam0, <given_filename>.cam1, ...
559  - The number of cameras to be used, which is stored by the number of
560  "Camera" nodes written to the xml file.
561  @param[in] file The file name to store the file. The extension (.xml) should
562  be contained in the file name.
563  @return < 0, if an error occured.
564  @see Read() to read this object from a file and to see an example xml file.
565  */
566 int GenSynthMatchesRig::Write(string file) const
567 {
568 #ifdef BIAS_HAVE_XML2
569  XMLIO xmlObject;
570  stringstream camFile;
571 
572  xmlNodePtr rootNode = xmlObject.create("GenSynthMatchesRigData");
573  xmlObject.addAttribute(rootNode, "Version", 0.1);
574  for (unsigned int i=0; i<CamMatches_.size(); i++) {
575  camFile << file.c_str() << ".cam" << i;
576  xmlNodePtr camNode = xmlObject.addChildNode(rootNode, "Camera");
577  xmlObject.addAttribute(camNode, "FileName", camFile.str());
578 
579  CamMatches_[i].Write(camFile.str());
580  camFile.str("");
581  }
582  return xmlObject.write(file);
583 
584 #else
585  BIASERR("BIAS_HAVE_XML2 must be defined to write to a file.");
586  BIASABORT;
587  return -1;
588 #endif
589 }
590 
591 /**
592  Fill the necessary parts of this object from a file. These are:
593  - The contained GenStynthMatches objects
594  - The number of cameras to be used
595  @param[in] The file name to read from.
596  @return
597  - 0: all right
598  - -1: error reading from file
599  - -2: no child nodes of root node found
600  - -3: attribute not found in the child node
601 
602  Here is an example for an xml file:
603  @code
604  <?xml version="1.0" encoding="ISO-8859-1"?>
605  <GenSynthMatchesRigData Version="0.1">
606  <Camera FileName="dataRig.xml.cam0"/>
607  <Camera FileName="dataRig.xml.cam1"/>
608  </GenSynthMatchesRigData>
609  @endcode
610  @todo Check if the nodes and attributes have the expected names.
611 */
612 int GenSynthMatchesRig::Read(string file)
613 {
614 #ifdef BIAS_HAVE_XML2
615  //reset the GenSynthMatches
616  CamMatches_.clear();
617  XMLIO xmlObject;
618  //get the root node and fill xmlobject with the read xml tree
619  xmlNodePtr rootNode = xmlObject.read(file);
620  if (! rootNode) {
621  BIASERR("GenSynthMatchesRig: Error reading file " << file);
622  return -1;
623  }
624  std::vector<xmlNodePtr> cams;
625  //get all child nodes of the root node
626  xmlObject.GetChildren(rootNode, cams);
627  if (cams.size() == 0) {
628  BIASERR("Child Node of root node (named \"Camera\") expected but does "
629  << "not exist.");
630  return -2;
631  }
632 
633  int i; //count the number of cams
634  //for each child node
635  for (i = 0; i < (int)cams.size(); i++) {
636  xmlAttrPtr fileNameAttr = xmlObject.getFirstAttribute(cams[i]);
637  if (! fileNameAttr) {
638  BIASERR("GenSynthMatchesRig: All Camera nodes must have an \"FileName\""
639  << "attribute.");
640  return -3;
641  }
642  //get the file name
643  std::string fileName = xmlObject.getAttributeValueString(fileNameAttr);
644 
646  //read GenSynthMatches object from file
647  cam.Read(fileName);
648 
649  //store the object
650  CamMatches_.push_back(cam);
651  }
652 
653  //store the number of cameras
654  *NumCameras_ = i;
655 
656  return 0;
657 
658 #else
659  BIASERR("BIAS_HAVE_XML2 must be defined to read from a file.");
660  BIASABORT;
661  return -1;
662 #endif
663 }
664 
665 
666 /**
667  Print out the camera poses of each camera and each time step
668 */
670  cout << "master Cam:" << endl
671  << "[ " << MasterCenterX_ << ", " << MasterCenterY_ << ", "
672  << MasterCenterZ_ << " ]" << " " << "[ " << MasterAnglesX_
673  << ", " << MasterAnglesY_ << ", " << MasterAnglesZ_ << " ]" << endl;
674  int i;
675  std::vector<std::map<std::string, double> >::iterator it;
676  for (it = SlaveCamsRelative_.begin(), i = 0;
677  it!= SlaveCamsRelative_.end(); it++, i++) {
678  cout << "slave Cam " << i << ":" << endl
679  << "[ " << (*it)["relPosX"] << ", " << (*it)["relPosY"] << ", "
680  << (*it)["relPosZ"] << " ]" << " " << "[ " << (*it)["relRotX"]
681  << ", " << (*it)["relRotY"] << ", " << (*it)["relRotZ"] << " ]"
682  << endl;
683  }
684 }
685 
686 /**
687  Register needed parameters. The parameters needed by the
688  #BIAS::GenSynthMatches objects are registered by a dummy object in the
689  constructor.
690  @param[out] para The parameter object to be updated.
691  */
693 {
694  int grp;
695 
696  if (para.CheckParam("NumImages")){
697  grp=para.GetGroupID("NumImages");
698  } else {
699  grp=para.GetFreeGroupID();
700  }
701  // cerr << "GenSynthMatches: using ID "<<grp<<" for group num\n";
702 
703 
704  //add NumCameras to group numbers
705  if (para.CheckParam("NumCameras")){
706  NumCameras_ = para.GetParamInt("NumCameras");
707  } else {
708  NumCameras_ = para.AddParamInt("NumCameras", "number of cameras used",
709  2, 0, INT_MAX, 0, grp);
710  }
711  if (para.IsUsedGroupID(grp))
712  para.SetGroupName(grp, "numbers");
713 
714  //add relative positions and rotations of slave cameras
715  grp = para.GetFreeGroupID();
716  std::map<std::string, double> myMap;
717  stringstream oss;
718  //for each (possible) slave camera
719  for (int i = 1; i <= GENSYNTHMATCHESRIG_MAX_NR_OF_CAMERAS; i++) {
720  oss << i;
721 
722  //X component
723  if ( para.CheckParam("Cam" + oss.str() + "_RelPosX") ){
724  myMap["relPosX"] =
725  *(para.GetParamDouble("Cam" + oss.str() + "_RelPosX"));
726  } else {
727  myMap["relPosX"] =
728  *(para.AddParamDouble("Cam" + oss.str() + "_RelPosX",
729  "relative tranlation (X component)"
730  "of camera " + oss.str(),
731  2.0, 0.0, DBL_MAX, 0, grp));
732  }
733 
734  //Y component
735  if ( para.CheckParam("Cam" + oss.str() + "_RelPosY") ){
736  myMap["relPosY"] =
737  *(para.GetParamDouble("Cam" + oss.str() + "_RelPosY"));
738  } else {
739  myMap["relPosY"] =
740  *(para.AddParamDouble("Cam" + oss.str() + "_RelPosY",
741  "relative tranlation (Y component)"
742  "of camera " + oss.str(),
743  0.0, 0.0, DBL_MAX, 0, grp));
744  }
745 
746  //Z component
747  if ( para.CheckParam("Cam" + oss.str() + "_RelPosZ") ){
748  myMap["relPosZ"] =
749  *(para.GetParamDouble("Cam" + oss.str() + "_RelPosZ"));
750  } else {
751  myMap["relPosZ"] =
752  *(para.AddParamDouble("Cam" + oss.str() + "_RelPosZ",
753  "relative tranlation (Z component)"
754  "of camera " + oss.str(),
755  0.0, 0.0, DBL_MAX, 0, grp));
756  }
757 
758  //rotation angle X
759  if ( para.CheckParam("Cam" + oss.str() + "_RelRotX") ){
760  myMap["relRotX"] =
761  *(para.GetParamDouble("Cam" + oss.str() + "_RelRotX"));
762  } else {
763  myMap["relRotX"] =
764  *(para.AddParamDouble("Cam" + oss.str() + "_RelRotX",
765  "relative rotation (rad) (X component)"
766  "of camera " + oss.str(),
767  0.0, 0.0, DBL_MAX, 0, grp));
768  }
769 
770  //rotation angle Y
771  if ( para.CheckParam("Cam" + oss.str() + "_RelRotY") ){
772  myMap["relRotY"] =
773  *(para.GetParamDouble("Cam" + oss.str() + "_RelRotY"));
774  } else {
775  myMap["relRotY"] =
776  *(para.AddParamDouble("Cam" + oss.str() + "_RelRotY",
777  "relative rotation (rad) (Y component)"
778  "of camera " + oss.str(),
779  0.0, 0.0, DBL_MAX, 0, grp));
780  }
781 
782  //rotation angle Z
783  if ( para.CheckParam("Cam" + oss.str() + "_RelRotZ") ){
784  myMap["relRotZ"] =
785  *(para.GetParamDouble("Cam" + oss.str() + "_RelRotZ"));
786  } else {
787  myMap["relRotZ"] =
788  *(para.AddParamDouble("Cam" + oss.str() + "_RelRotZ",
789  "relative rotation (rad) (Z component)"
790  "of camera " + oss.str(),
791  0.0, 0.0, DBL_MAX, 0, grp));
792  }
793 
794  SlaveCamsRelative_.push_back(myMap);
795  oss.str(""); //clear the stream
796 
797  } //for each slave camera
798 
799  if (para.IsUsedGroupID(grp))
800  para.SetGroupName(grp, "slave camera values");
801 
802 } //end of _AddParameter()
803 
804 
void addAttribute(const xmlNodePtr Node, const std::string &AttributeName, bool AttributeValue)
Add an attribute to a node.
Definition: XMLIO.cpp:156
double * GetParamDouble(const std::string &name) const
Definition: Param.cpp:665
int write(const std::string &Filename, bool AutoAddCompressionSuffix=true) const
Write the whole tree that was constructed in memory to disk.
Definition: XMLIO.cpp:379
void SetXYZ(ROTATION_MATRIX_TYPE PhiX, ROTATION_MATRIX_TYPE PhiY, ROTATION_MATRIX_TYPE PhiZ)
Set Euler angles (in rad) in order XYZ.
void TransposeIP()
tranpose this matrix &quot;in place&quot; example: 0 1 2 –&gt; 0 3 6 3 4 5 –&gt; 1 4 7 6 7 8 –&gt; 2 5 8 ...
Definition: Matrix3x3.hh:385
xmlNodePtr read(const std::string &Filename)
Read and parse an XML file from disk, DtD validation is not yet implemented.
Definition: XMLIO.cpp:416
int GetMoving3DPoints(std::vector< BIAS::HomgPoint3D > &points)
read the moving 3D points used for computaion
void CreateCamMovement(const bool fixed_error=false)
see _CreateCamMovement for docu
std::vector< VecOMapOStrDbl > SlaveCamsGlobal_
BIAS::Vector< double > MasterAnglesY_
void PrintCamPoses_()
Print the poses of the cameras. For debugging only.
int Read(std::string file)
read in xml/ascii file format
void DrawNoisy(std::vector< Image< unsigned char > > &im, int minindex=0, int maxindex=1) const
Creates images showing the 2D matches for all cameras.
xmlNodePtr create(const std::string &RootNodeName)
Create the base of a new XML-Tree in memory, already with a one and only root node.
Definition: XMLIO.cpp:88
double * AddParamDouble(const std::string &name, const std::string &help, double deflt=0.0, double min=-DBL_MAX, double max=DBL_MAX, char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:351
int CreateMatches()
Creates 3D points and generates 2D matches for them.
BIAS::Vector< double > MasterCenterZ_
virtual ~GenSynthMatchesRig()
Default destructor...
int SetStatic3DPoints(const std::vector< BIAS::HomgPoint3D > &points)
set the static 3D points used for computation
xmlAttrPtr getFirstAttribute(const xmlNodePtr Node)
Get the first attribute of a given parent, or NULL for no attributes.
Definition: XMLIO.cpp:624
class for generating synthetic matches
int Read(const std::string &fname)
binary read
BIAS::Vector< double > MasterCenterX_
motion vectors read from the param file
3D rotation matrix
Definition: RMatrix.hh:49
std::string getAttributeValueString(const xmlAttrPtr Attribute) const
Definition: XMLIO.cpp:716
int SetMoving3DPoints(const std::vector< BIAS::HomgPoint3D > &points)
set the moving 3D points used for computation
int CreateMoving3DPoint(int index)
Replace the moving 3D point at index by a newly generated one.
Param * allParams_
Pointer to the parameter object.
BIAS::Vector< double > MasterCenterY_
int CreateStatic3DPoint(int index)
Replace the static 3D point at index by a newly generated one.
bool IsUsedGroupID(const int group_id)
returns if the group id is used
Definition: Param.cpp:1496
Wrapper class for reading and writing XML files based on the XML library libxml2. ...
Definition: XMLIO.hh:72
bool CheckParam(const std::string &name)
Check if parameter has already been added.
Definition: Param.cpp:527
xmlNodePtr addChildNode(const xmlNodePtr ParentNode, const std::string &NewNodeName)
Add a child node to an incoming node with the given name.
Definition: XMLIO.cpp:131
void CreateMovingTransforms()
fills _MovingTransform
BIAS::Vector< double > * GetParamVecDbl(const std::string &name) const
Definition: Param.cpp:680
int GetStatic3DPoints(std::vector< BIAS::HomgPoint3D > &points)
read the static 3D points used for computation
std::vector< GenSynthMatches > CamMatches_
Vector containing the cameras.
int CreateMatches(bool points3D_set_by_user=false, bool fixed_errors=false)
returns negative value, if error occurs, 0 on success see _CreateCamMovement for explanation of param...
void GetChildren(const xmlNodePtr ParentNode, const std::string &ChildName, std::vector< xmlNodePtr > &childrenWithSameName)
Convenience wrapper: returns a vector of pointors to every (direct) child with the specified name...
Definition: XMLIO.cpp:506
int * GetParamInt(const std::string &name) const
Definition: Param.cpp:618
int GetFreeGroupID()
returns unused group id
Definition: Param.cpp:1421
BIAS::Vector< double > MasterAnglesZ_
Generates synthetic matches for cameras in a rig.
std::ostream & operator<<(std::ostream &os, const Array2D< T > &arg)
Definition: Array2D.hh:260
BIAS::Vector< double > MasterAnglesX_
void AddParameters_(Param &para)
Add parameters to the param object.
void UpdateParams_(int camID)
Update the param object for the given slave camera.
int Write(std::string file) const
write in xml/ascii file format
void DrawTrue(std::vector< Image< unsigned char > > &im, int minindex=0, int maxindex=1) const
Create images for all cameras showing the matches.
This class Param provides generic support for parameters.
Definition: Param.hh:231
void GetParameters_()
read the parameters from the param object.
int SetGroupName(const int group_id, const std::string &name)
sets the name for a group
Definition: Param.cpp:1448
Matrix3x3< T > Transpose() const
returns transposed matrix tested 12.06.2002
Definition: Matrix3x3.cpp:167
int GetRotationAnglesXYZ(double &PhiX, double &PhiY, double &PhiZ) const
Get Euler angles for this rotation matrix in order XYZ.
void Setup_()
Setup the global poses of the cameras and read the parameters.
std::vector< std::map< std::string, double > > SlaveCamsRelative_
int Create3DPoints(bool fixed_errors=false)
Create static and moving 3D points see _CreateCamMovement for explanation of parameter.
GenSynthMatchesRig(Param &para)
Constructor - register parameters.
int * AddParamInt(const std::string &name, const std::string &help, int deflt=0, int min=std::numeric_limits< int >::min(), int max=std::numeric_limits< int >::max(), char cmdshort=0, int Group=GRP_NOSHOW)
For all adding routines:
Definition: Param.cpp:276
int * NumCameras_
The number of cameras used. Read from the param object.
std::vector< BIAS::GenSynthMatches > GetCams() const
returns the vector of the used GenSynthMatches object
int GetGroupID(const std::string &name)
returns group id of parameter with name
Definition: Param.cpp:1430
Subscript size() const
Definition: vec.h:262