Visual Servoing Platform  version 3.6.1 under development (2025-02-15)
vpRBInitializationHelper.cpp
1 #include <visp3/rbt/vpRBInitializationHelper.h>
2 
3 #include <visp3/vision/vpPose.h>
4 #include <visp3/core/vpDisplay.h>
5 #include <visp3/core/vpImage.h>
6 #include <visp3/io/vpImageIo.h>
7 #include <visp3/core/vpIoTools.h>
8 
9 #ifdef VISP_HAVE_MODULE_GUI
10 #include <visp3/gui/vpDisplayFactory.h>
11 #endif
12 
13 BEGIN_VISP_NAMESPACE
14 
15 void vpRBInitializationHelper::removeComment(std::ifstream &fileId)
16 {
17  char c;
18 
19  fileId.get(c);
20  while (!fileId.fail() && (c == '#')) {
21  fileId.ignore(std::numeric_limits<std::streamsize>::max(), fileId.widen('\n'));
22  fileId.get(c);
23  }
24  if (fileId.fail()) {
25  throw(vpException(vpException::ioError, "Reached end of file"));
26  }
27  fileId.unget();
28 }
29 
30 void vpRBInitializationHelper::savePose(const std::string &filename) const
31 {
32  vpPoseVector init_pos;
33  std::fstream finitpos;
34  finitpos.open(filename.c_str(), std::ios::out);
35 
36  init_pos.buildFrom(m_cMo);
37  finitpos << init_pos;
38  finitpos.close();
39 }
40 
41 #ifdef VISP_HAVE_MODULE_GUI
42 
43 template <typename T>
44 void vpRBInitializationHelper::initClick(const vpImage<T> &I, const std::string &initFile, bool displayHelp)
45 {
46  std::cout << "Starting init click!" << std::endl;
47  vpHomogeneousMatrix last_cMo;
48  vpPoseVector init_pos;
49  vpImagePoint ip;
51 
52  std::string ext = ".init";
53  std::string str_pose = "";
54  size_t pos = initFile.rfind(ext);
55 
56  // Load the last poses from files
57  std::fstream finitpos;
58  std::ifstream finit;
59  std::stringstream ss;
60  std::string poseSavingFilename;
61  if (poseSavingFilename.empty()) {
62  if (pos != std::string::npos)
63  str_pose = initFile.substr(0, pos) + ".0.pos";
64  else
65  str_pose = initFile + ".0.pos";
66 
67  finitpos.open(str_pose.c_str(), std::ios::in);
68  ss << str_pose;
69  }
70  else {
71  finitpos.open(poseSavingFilename.c_str(), std::ios::in);
72  ss << poseSavingFilename;
73  }
74  if (finitpos.fail()) {
75  std::cout << "Cannot read " << ss.str() << std::endl << "cMo set to identity" << std::endl;
76  last_cMo.eye();
77  }
78  else {
79  for (unsigned int i = 0; i < 6; i += 1) {
80  finitpos >> init_pos[i];
81  }
82 
83  finitpos.close();
84  last_cMo.buildFrom(init_pos);
85 
86  std::cout << "Tracker initial pose read from " << ss.str() << ": " << std::endl << last_cMo << std::endl;
87 
89  vpDisplay::displayFrame(I, last_cMo, m_cam, 0.05, vpColor::green);
91 
92 
93  std::cout << "No modification : left click " << std::endl;
94  std::cout << "Modify initial pose : right click " << std::endl;
95 
96 
97  vpDisplay::displayText(I, 15, 10, "left click to validate, right click to modify initial pose", vpColor::red);
98 
100 
101  while (!vpDisplay::getClick(I, ip, button)) {
102  vpTime::sleepMs(10);
103  }
104  }
105 
106  if (!finitpos.fail() && button == vpMouseButton::button1) {
107  m_cMo = last_cMo;
108  }
109  else {
110  vpDisplay *d_help = nullptr;
111 
113  vpDisplay::flush(I);
114 
115  vpPose pose;
116 
117  pose.clearPoint();
118 
119  // Clear string stream that previously contained the path to the "object.0.pos" file.
120  ss.str(std::string());
121 
122  // file parser
123  // number of points
124  // X Y Z
125  // X Y Z
126  if (pos != std::string::npos) {
127  ss << initFile;
128  }
129  else {
130  ss << initFile;
131  ss << ".init";
132  }
133 
134  std::cout << "Load 3D points from: " << ss.str() << std::endl;
135 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
136  finit.open(ss.str());
137 #else
138  finit.open(ss.str().c_str());
139 #endif
140  if (finit.fail()) {
141  std::cout << "Cannot read " << ss.str() << std::endl;
142  throw vpException(vpException::ioError, "Cannot open model-based tracker init file %s", ss.str().c_str());
143  }
144 
145 #ifdef VISP_HAVE_MODULE_IO
146  // Display window creation and initialisation
147  try {
148  if (displayHelp) {
149  const std::string imgExtVec[] = { ".ppm", ".pgm", ".jpg", ".jpeg", ".png" };
150  std::string dispF;
151  bool foundHelpImg = false;
152  if (pos != std::string::npos) {
153  for (size_t i = 0; i < 5 && !foundHelpImg; i++) {
154  dispF = initFile.substr(0, pos) + imgExtVec[i];
155  foundHelpImg = vpIoTools::checkFilename(dispF);
156  }
157  }
158  else {
159  for (size_t i = 0; i < 5 && !foundHelpImg; i++) {
160  dispF = initFile + imgExtVec[i];
161  foundHelpImg = vpIoTools::checkFilename(dispF);
162  }
163  }
164 
165  if (foundHelpImg) {
166  std::cout << "Load image to help initialization: " << dispF << std::endl;
167 
168  std::shared_ptr<vpDisplay> d_help = vpDisplayFactory::createDisplay();
169 
170  vpImage<vpRGBa> Iref;
171  vpImageIo::read(Iref, dispF);
172 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV)
173  const int winXPos = I.display->getWindowXPosition();
174  const int winYPos = I.display->getWindowYPosition();
175  unsigned int width = I.getWidth();
176  d_help->init(Iref, winXPos + (int)width + 80, winYPos, "Where to initialize...");
177  vpDisplay::display(Iref);
178  vpDisplay::flush(Iref);
179 #endif
180  }
181  }
182  }
183  catch (...) {
184  if (d_help != nullptr) {
185  delete d_help;
186  d_help = nullptr;
187  }
188  }
189 #else //#ifdef VISP_HAVE_MODULE_IO
190  (void)(displayHelp);
191 #endif //#ifdef VISP_HAVE_MODULE_IO
192  // skip lines starting with # as comment
193  removeComment(finit);
194 
195  unsigned int n3d;
196  finit >> n3d;
197  finit.ignore(256, '\n'); // skip the rest of the line
198  std::cout << "Number of 3D points " << n3d << std::endl;
199  if (n3d > 100000) {
200  throw vpException(vpException::badValue, "In %s file, the number of 3D points exceed the max allowed",
201  ss.str().c_str());
202  }
203 
204  std::vector<vpPoint> P(n3d);
205  for (unsigned int i = 0; i < n3d; i++) {
206  // skip lines starting with # as comment
207  removeComment(finit);
208 
209  vpColVector pt_3d(4, 1.0);
210  finit >> pt_3d[0];
211  finit >> pt_3d[1];
212  finit >> pt_3d[2];
213  finit.ignore(256, '\n'); // skip the rest of the line
214 
215  vpColVector pt_3d_tf = pt_3d;
216  std::cout << "Point " << i + 1 << " with 3D coordinates: " << pt_3d_tf[0] << " " << pt_3d_tf[1] << " "
217  << pt_3d_tf[2] << std::endl;
218 
219  P[i].setWorldCoordinates(pt_3d_tf[0], pt_3d_tf[1], pt_3d_tf[2]); // (X,Y,Z)
220  }
221 
222  finit.close();
223 
224  bool isWellInit = false;
225  while (!isWellInit) {
226  std::vector<vpImagePoint> mem_ip;
227  for (unsigned int i = 0; i < n3d; i++) {
228  std::ostringstream text;
229  text << "Click on point " << i + 1;
230 
232  vpDisplay::displayText(I, 15, 10, text.str(), vpColor::red);
233  for (unsigned int k = 0; k < mem_ip.size(); k++) {
234  vpDisplay::displayCross(I, mem_ip[k], 10, vpColor::green, 2);
235  }
236  vpDisplay::flush(I);
237 
238  std::cout << "Click on point " << i + 1 << " ";
239  double x = 0, y = 0;
240 
241  vpDisplay::getClick(I, ip);
242  mem_ip.push_back(ip);
243  vpDisplay::flush(I);
244 
245  vpPixelMeterConversion::convertPoint(m_cam, ip, x, y);
246  P[i].set_x(x);
247  P[i].set_y(y);
248 
249  std::cout << "with 2D coordinates: " << ip << std::endl;
250 
251  pose.addPoint(P[i]); // and added to the pose computation point list
252  }
253  vpDisplay::flush(I);
255 
256  std::cout << "Before optim: " << m_cam << std::endl;
258  std::cout << "Pose computation from points failed!" << std::endl;
259  for (unsigned int i = 0; i < n3d; ++i) {
260  std::cout << "Point " << i << ": " << std::endl;
261  std::cout << " 3D: " << pose.getPoints()[i].get_oP().t() << std::endl;
262  std::cout << "2D: " << pose.getPoints()[i].get_x() << ", " << pose.getPoints()[i].get_y() << std::endl;
263  }
264  }
265  std::cout << "POSE after optim: " << m_cMo << std::endl;
266 
267  vpDisplay::displayText(I, 15, 10, "left click to validate, right click to re initialize object", vpColor::red);
268 
269  vpDisplay::flush(I);
270 
271  button = vpMouseButton::button1;
272  while (!vpDisplay::getClick(I, ip, button)) {
273  }
274 
275  if (button == vpMouseButton::button1) {
276  isWellInit = true;
277  }
278  else {
279  pose.clearPoint();
281  vpDisplay::flush(I);
282  }
283 
284  }
285  vpDisplay::displayFrame(I, m_cMo, m_cam, 0.05, vpColor::red);
286 
287  // save the pose into file
288  if (poseSavingFilename.empty())
289  savePose(str_pose);
290  else
291  savePose(poseSavingFilename);
292 
293  if (d_help != nullptr) {
294  delete d_help;
295  d_help = nullptr;
296  }
297  }
298 
299 }
300 template void vpRBInitializationHelper::initClick<unsigned char>(const vpImage<unsigned char> &I, const std::string &initFile, bool displayHelp);
301 template void vpRBInitializationHelper::initClick<vpRGBa>(const vpImage<vpRGBa> &I, const std::string &initFile, bool displayHelp);
302 #endif
303 
304 END_VISP_NAMESPACE
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
static const vpColor red
Definition: vpColor.h:198
static const vpColor green
Definition: vpColor.h:201
Class that defines generic functionalities for display.
Definition: vpDisplay.h:178
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
int getWindowXPosition() const
Definition: vpDisplay.h:237
static void displayFrame(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double size, const vpColor &color=vpColor::none, unsigned int thickness=1, const vpImagePoint &offset=vpImagePoint(0, 0), const std::string &frameName="", const vpColor &textColor=vpColor::black, const vpImagePoint &textOffset=vpImagePoint(15, 15))
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
int getWindowYPosition() const
Definition: vpDisplay.h:242
static void flush(const vpImage< unsigned char > &I)
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:60
@ ioError
I/O error.
Definition: vpException.h:67
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:73
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpHomogeneousMatrix & buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:147
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
Definition of the vpImage class member functions.
Definition: vpImage.h:131
unsigned int getWidth() const
Definition: vpImage.h:242
vpDisplay * display
Definition: vpImage.h:136
static bool checkFilename(const std::string &filename)
Definition: vpIoTools.cpp:786
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
Implementation of a pose vector and operations on poses.
Definition: vpPoseVector.h:203
vpPoseVector & buildFrom(const double &tx, const double &ty, const double &tz, const double &tux, const double &tuy, const double &tuz)
Class used for pose computation from N points (pose from point only). Some of the algorithms implemen...
Definition: vpPose.h:77
void addPoint(const vpPoint &P)
Definition: vpPose.cpp:96
@ DEMENTHON_LAGRANGE_VIRTUAL_VS
Definition: vpPose.h:98
bool computePose(vpPoseMethodType method, vpHomogeneousMatrix &cMo, FuncCheckValidityPose func=nullptr)
Definition: vpPose.cpp:385
std::vector< vpPoint > getPoints() const
Definition: vpPose.h:497
void clearPoint()
Definition: vpPose.cpp:89
void savePose(const std::string &filename) const
void removeComment(std::ifstream &fileId)
std::shared_ptr< vpDisplay > createDisplay()
Return a smart pointer vpDisplay specialization if a GUI library is available or nullptr otherwise.
VISP_EXPORT void sleepMs(double t)