stereo-vision
All Data Structures Namespaces Functions Modules Pages
DispModule.cpp
1 /*
2  * Copyright (C) 2015 RobotCub Consortium
3  * Author: Sean Ryan Fanello, Giulia Pasquale
4  * email: sean.fanello@iit.it giulia.pasquale@iit.it
5  * website: www.robotcub.org
6  * Permission is granted to copy, distribute, and/or modify this program
7  * under the terms of the GNU General Public License, version 2 or any
8  * later version published by the Free Software Foundation.
9  *
10  * A copy of the license can be found at
11  * http://www.robotcub.org/icub/license/gpl.txt
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details
17  */
18 
19 #include <cmath>
20 #include <algorithm>
21 #include <yarp/cv/Cv.h>
22 #include "DispModule.h"
23 
24 // --- DEBUG ---
25 // this code left on purpose, it was used to carry out profiling
26 // of the different subroutines in the code
27 //
28 // --- SAMPLE USE ---
29 //
30 // have a "debug_count" flag and a "debug_timings[]"" array stored stored in your main loop, starting at 0,
31 // then for every function to be profiled use:
32 //
33 // PROF_S
34 // method_to_be_profiled()
35 // PROF_E(<number>)
36 //
37 // then you can print every 100 iterations in a way similar to:
38 //
39 // if(++debug_count == 100)
40 // {
41 // std::cout << std::endl << "---- DISPMODULE: AVERAGE TIMING OVER " << debug_count << " FRAMES ----" << std::endl;
42 // for(int i = 0; i < this->debug_num_timings; i++)
43 // {
44 // std::cout << debug_strings[i] << ": " << (this->debug_timings[i] / debug_count) / 1000. << " ms" << std::endl;
45 // this->debug_timings[i] = 0;
46 // }
47 // debug_count = 0;
48 // }
49 //
50 // the "debug_strings[]" array stores the strings associated with
51 // the different <number> values used in PROF_E(<number>)
52 //
53 //#include <chrono>
54 //#define PROF_S {start = std::chrono::high_resolution_clock::now();}
55 //#define PROF_E(N) {stop = std::chrono::high_resolution_clock::now();duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start); this->debug_timings[N] += duration.count();}
56 //
57 // char const *debug_strings[] = {
58 // "updateViaKinematics",
59 // "updateViaGazeCtrl",
60 // "getCameraHGazkillGUIeCtrlx2",
61 // "gui.recalibrate",
62 // "runRecalibration",
63 // "gui.isUpdated",
64 // "computeDisparity",
65 // "bilateralFilter",
66 // "wlsFilter",
67 // "ouputDisparity",
68 // "outputDepth"
69 // };
70 
71 using namespace yarp::cv;
72 
73 
74 void DispModule::printParameters()
75 {
76  std::cout << "params ("
77  << this->stereo_parameters.minDisparity << " "
78  << this->useBestDisp << " "
79  << this->stereo_parameters.numberOfDisparities << " "
80  << this->stereo_parameters.SADWindowSize << " "
81  << this->stereo_parameters.disp12MaxDiff << " "
82  << this->stereo_parameters.preFilterCap << " "
83  << this->stereo_parameters.uniquenessRatio << " "
84  << this->stereo_parameters.speckleWindowSize << " "
85  << this->stereo_parameters.speckleRange << " "
86  << this->stereo_parameters.sigmaColorBLF << " "
87  << this->stereo_parameters.sigmaSpaceBLF << " "
88  << this->stereo_parameters.wls_lambda << " "
89  << this->stereo_parameters.wls_sigma << " "
90  << this->stereo_parameters.stereo_matching << " "
91  << this->stereo_parameters.BLFfiltering << " "
92  << this->stereo_parameters.WLSfiltering
93  << ")" << std::endl;
94 }
95 
96 
97 
98 bool DispModule::configure(ResourceFinder & rf)
99 {
100  // populate local variables with infos from the context
101 
102  string name=rf.check("name",Value("DisparityModule")).asString();
103  string robot=rf.check("robot",Value("icub")).asString();
104  string left=rf.check("leftPort",Value("/left:i")).asString();
105  string right=rf.check("rightPort",Value("/right:i")).asString();
106  string SFMFile=rf.check("SFMFile",Value("SFM.ini")).asString();
107 
108  string sname="/"+name;
109  left=sname+left;
110  right=sname+right;
111 
112  // set up output disparity and depth ports
113 
114  string outDispName=rf.check("outDispPort",Value("/disp:o")).asString();
115  string outDepthName=rf.check("outDepthPort",Value("/depth:o")).asString();
116 
117  outDepthName=sname+outDepthName;
118  outDispName=sname+outDispName;
119 
120  // load the calibration infos from file
121 
122  this->localCalibration.setDefaultContext("cameraCalibration");
123  this->localCalibration.setDefaultConfigFile(SFMFile.c_str());
124  this->localCalibration.configure(0,NULL);
125 
126  this->camCalibFile=this->localCalibration.getHomeContextPath();
127  this->camCalibFile+="/"+SFMFile;
128 
129  // prepares the name for the RPC port
130 
131  string rpc_name=sname+"/rpc";
132 
133  // open the ports
134 
135  leftImgPort.open(left);
136  rightImgPort.open(right);
137  outDepth.open(outDepthName);
138  outDisp.open(outDispName);
139  handlerPort.open(rpc_name);
140  attach(handlerPort);
141 
142  // create the stereocamera and load the
143  // intrinsic/extrinsic parameters
144 
145  this->stereo = new StereoCamera(true);
146 
147  Mat KL, KR, DistL, DistR;
148 
149  loadIntrinsics(rf,KL,KR,DistL,DistR);
150  loadConfigurationFile(this->localCalibration,R0,T0,eyes0);
151 
152  // stores the original parameters
153 
154  this->original_parameters = this->stereo_parameters;
155 
156  // auxiliary initialization calls
157 
158  eyes.resize(eyes0.length(),0.0);
159 
160  stereo->setIntrinsics(KL,KR,DistL,DistR);
161 
162  // initialize the matrices describing the
163  // transformation between reference systems
164 
165  this->HL_root=Mat::zeros(4,4,CV_64F);
166  this->HR_root=Mat::zeros(4,4,CV_64F);
167 
168  bool useCalibrated = rf.check("useCalibrated");
169 
170  // TODO: check whether this part next is needed or not
171 
172  if (useCalibrated)
173  {
174  Mat KL=this->stereo->getKleft();
175  Mat KR=this->stereo->getKright();
176  Mat zeroDist=Mat::zeros(1,8,CV_64FC1);
177  this->stereo->setIntrinsics(KL,KR,zeroDist,zeroDist);
178  }
179 
180  // auxiliary variables for the calibration process
181 
182  this->init=true;
183  this->numberOfTrials=0;
184 
185 #ifdef USING_GPU
186  utils=new Utilities();
187  utils->initSIFT_GPU();
188 #endif
189 
190  Property optionHead;
191  optionHead.put("device","remote_controlboard");
192  optionHead.put("remote","/"+robot+"/head");
193  optionHead.put("local",sname+"/headClient");
194 
195  if (headCtrl.open(optionHead))
196  {
197  headCtrl.view(iencs);
198  iencs->getAxes(&nHeadAxes);
199  }
200  else
201  {
202  std::cout << "[DisparityModule] Devices not available" << std::endl;
203  return false;
204  }
205 
206  // set up to interface with the GazeController
207 
208  Property optionGaze;
209  optionGaze.put("device","gazecontrollerclient");
210  optionGaze.put("remote","/iKinGazeCtrl");
211  optionGaze.put("local",sname+"/gazeClient");
212  if (gazeCtrl.open(optionGaze))
213  gazeCtrl.view(igaze);
214  else
215  {
216  std::cout << "[DisparityModule] Devices not available" << std::endl;
217  headCtrl.close();
218  return false;
219  }
220 
221  // set up the translation and rotation parameters of the stereo system
222 
223  if (!R0.empty() && !T0.empty())
224  {
225  stereo->setRotation(R0,0);
226  stereo->setTranslation(T0,0);
227  }
228  else
229  {
230  std::cout << "[DisparityModule] No local calibration file found in " << camCalibFile
231  << "[DisparityModule] ... Using Kinematics and Running SFM once." << std::endl;
232  updateViaGazeCtrl(true);
233  R0=this->stereo->getRotation();
234  T0=this->stereo->getTranslation();
235  }
236 
237  this->runRecalibration=false;
238  this->updateViaGazeCtrl(false);
239 
240  // select the stereo matching algorithm, filtering
241  // methods on the basis of the parameters the
242  // module has been invoked with, in case the user
243  // prefers to specify it via command line and not
244  // using the GUI
245 
246  if (rf.check("sgbm"))
247  this->stereo_parameters.stereo_matching = SM_MATCHING_ALG::SGBM_OPENCV;
248  else if(rf.check("sgbm_cuda"))
249  this->stereo_parameters.stereo_matching = SM_MATCHING_ALG::SGBM_CUDA;
250  else if(rf.check("libelas"))
251  this->stereo_parameters.stereo_matching = SM_MATCHING_ALG::LIBELAS;
252 
253  if (rf.check("blf"))
254  this->stereo_parameters.BLFfiltering = SM_BLF_FILTER::BLF_ORIGINAL;
255  else if(rf.check("blf_cuda"))
256  this->stereo_parameters.BLFfiltering = SM_BLF_FILTER::BLF_CUDA;
257  else if(rf.check("no_blf"))
258  this->stereo_parameters.BLFfiltering = SM_BLF_FILTER::BLF_DISABLED;
259 
260  if (rf.check("wls"))
261  this->stereo_parameters.WLSfiltering = SM_WLS_FILTER::WLS_ENABLED;
262  else if(rf.check("wls_lr"))
263  this->stereo_parameters.WLSfiltering = SM_WLS_FILTER::WLS_LRCHECK;
264  else if(rf.check("no_wls"))
265  this->stereo_parameters.WLSfiltering = SM_WLS_FILTER::WLS_DISABLED;
266 
267  // if specified via CMake, compile using the GUI
268  // based on cvui.h and here checks whether to initialize
269  // it or not
270 
271 #ifdef USE_GUI
272  this->debugWindow = rf.check("gui");
273 
274  if(this->debugWindow)
275  {
276  this->gui.initializeGUI(this->stereo_parameters.minDisparity,
277  this->stereo_parameters.numberOfDisparities,
278  this->stereo_parameters.SADWindowSize,
279  this->stereo_parameters.disp12MaxDiff,
280  this->stereo_parameters.preFilterCap,
281  this->stereo_parameters.uniquenessRatio,
282  this->stereo_parameters.speckleWindowSize,
283  this->stereo_parameters.speckleRange,
284  this->stereo_parameters.sigmaColorBLF,
285  this->stereo_parameters.sigmaSpaceBLF,
286  this->stereo_parameters.wls_lambda,
287  this->stereo_parameters.wls_sigma,
288  this->stereo_parameters.BLFfiltering,
289  this->stereo_parameters.WLSfiltering,
290  this->stereo_parameters.stereo_matching);
291  }
292 #endif
293 
294  // initialize the StereoMatcher object
295 
296  this->matcher = new StereoMatcherNew(rf, this->stereo);
297 
298  this->matcher->setParameters(this->stereo_parameters.minDisparity,
299  this->stereo_parameters.numberOfDisparities,
300  this->stereo_parameters.SADWindowSize,
301  this->stereo_parameters.disp12MaxDiff,
302  this->stereo_parameters.preFilterCap,
303  this->stereo_parameters.uniquenessRatio,
304  this->stereo_parameters.speckleWindowSize,
305  this->stereo_parameters.speckleRange,
306  this->stereo_parameters.sigmaColorBLF,
307  this->stereo_parameters.sigmaSpaceBLF,
308  this->stereo_parameters.wls_lambda,
309  this->stereo_parameters.wls_sigma,
310  this->stereo_parameters.BLFfiltering,
311  this->stereo_parameters.WLSfiltering,
312  this->stereo_parameters.stereo_matching);
313 
314  this->matcher->updateCUDAParams();
315 
316  return true;
317 }
318 
319 
320 cv::Mat DispModule::depthFromDisparity(Mat disparity, Mat Q, Mat R)
321 {
322  // compute the depth from the disparity map
323 
324  cv::Mat depth;
325 
326  depth = disparity.clone();
327 
328  depth.convertTo(depth, CV_32FC1, 1./16.);
329 
330  // extract the subelements of the R and Q matrices,
331  // to simplify the further calculations
332 
333  float r02 = float(R.at<double>(0,2));
334  float r12 = float(R.at<double>(1,2));
335  float r22 = float(R.at<double>(2,2));
336 
337  float q00 = float(Q.at<double>(0,0));
338  float q03 = float(Q.at<double>(0,3));
339  float q11 = float(Q.at<double>(1,1));
340  float q13 = float(Q.at<double>(1,3));
341  float q23 = float(Q.at<double>(2,3));
342  float q32 = float(Q.at<double>(3,2));
343  float q33 = float(Q.at<double>(3,3));
344 
345  const Mat& Mapper=this->stereo->getMapperL();
346 
347  if (Mapper.empty())
348  return depth;
349 
350  float usign, vsign;
351 
352  for (int u = 0; u < depth.rows; u++)
353  for (int v = 0; v < depth.cols; v++)
354  {
355  usign=cvRound(Mapper.ptr<float>(u)[2*v]);
356  vsign=cvRound(Mapper.ptr<float>(u)[2*v+1]);
357 
358  if ((usign<0) || (usign>=depth.cols) || (vsign<0) || (vsign>=depth.rows))
359  depth.at<float>(u,v) = 0.0;
360  else
361  depth.at<float>(u,v) = (r02*(float(vsign)*q00+q03)+r12*(float(usign)*q11+q13)+r22*q23)/(depth.at<float>(vsign,usign)*q32+q33);
362 
363  }
364 
365  return depth;
366 }
367 
368 
369 void DispModule::initializeStereoParams()
370 {
371  this->useBestDisp=true;
372 
373  this->stereo_parameters.uniquenessRatio=15;
374  this->stereo_parameters.speckleWindowSize=50;
375  this->stereo_parameters.speckleRange=16;
376  this->stereo_parameters.SADWindowSize=7;
377  this->stereo_parameters.minDisparity=0;
378  this->stereo_parameters.preFilterCap=63;
379  this->stereo_parameters.disp12MaxDiff=0;
380 
381  this->stereo_parameters.numberOfDisparities = 96;
382 
383  this->stereo_parameters.sigmaColorBLF = 10.0;
384  this->stereo_parameters.sigmaSpaceBLF = 10.0;
385 
386  this->stereo_parameters.wls_lambda = 4500.;
387  this->stereo_parameters.wls_sigma = 1.0;
388 
389  this->stereo_parameters.stereo_matching = SM_MATCHING_ALG::SGBM_OPENCV;
390  this->stereo_parameters.BLFfiltering = SM_BLF_FILTER::BLF_DISABLED;
391  this->stereo_parameters.WLSfiltering = SM_WLS_FILTER::WLS_DISABLED;
392 
393  this->original_parameters = this->stereo_parameters;
394 }
395 
396 
397 void DispModule::updateViaKinematics(const yarp::sig::Vector& deyes)
398 {
399  double dpan=CTRL_DEG2RAD*deyes[1];
400  double dver=CTRL_DEG2RAD*deyes[2];
401 
402  yarp::sig::Vector rot_l_pan(4,0.0);
403  rot_l_pan[1]=1.0;
404  rot_l_pan[3]=dpan+dver/2.0;
405  Matrix L1=axis2dcm(rot_l_pan);
406 
407  yarp::sig::Vector rot_r_pan(4,0.0);
408  rot_r_pan[1]=1.0;
409  rot_r_pan[3]=dpan-dver/2.0;
410  Matrix R1=axis2dcm(rot_r_pan);
411 
412  Mat RT0=buildRotTras(R0,T0);
413  Matrix H0; convert(RT0,H0);
414  Matrix H=SE3inv(R1)*H0*L1;
415 
416  Mat R=Mat::zeros(3,3,CV_64F);
417  Mat T=Mat::zeros(3,1,CV_64F);
418 
419  for (int i=0; i<R.rows; i++)
420  for(int j=0; j<R.cols; j++)
421  R.at<double>(i,j)=H(i,j);
422 
423  for (int i=0; i<T.rows; i++)
424  T.at<double>(i,0)=H(i,3);
425 
426  this->stereo->setRotation(R,0);
427  this->stereo->setTranslation(T,0);
428 }
429 
430 
431 
432 void DispModule::updateViaGazeCtrl(const bool update)
433 {
434  Matrix L1=getCameraHGazeCtrl(LEFT);
435  Matrix R1=getCameraHGazeCtrl(RIGHT);
436 
437  Matrix RT=SE3inv(R1)*L1;
438 
439  Mat R=Mat::zeros(3,3,CV_64F);
440  Mat T=Mat::zeros(3,1,CV_64F);
441 
442  for (int i=0; i<R.rows; i++)
443  for(int j=0; j<R.cols; j++)
444  R.at<double>(i,j)=RT(i,j);
445 
446  for (int i=0; i<T.rows; i++)
447  T.at<double>(i,0)=RT(i,3);
448 
449  if (update)
450  {
451  stereo->setRotation(R,0);
452  stereo->setTranslation(T,0);
453  }
454  else
455  stereo->setExpectedPosition(R,T);
456 }
457 
458 
459 
460 bool DispModule::interruptModule()
461 {
462  leftImgPort.interrupt();
463  rightImgPort.interrupt();
464  outDisp.interrupt();
465  outDepth.interrupt();
466  handlerPort.interrupt();
467 
468  return true;
469 }
470 
471 
472 
473 bool DispModule::close()
474 {
475  leftImgPort.close();
476  rightImgPort.close();
477  outDisp.close();
478  outDepth.close();
479  handlerPort.close();
480 
481  headCtrl.close();
482  gazeCtrl.close();
483 
484  delete stereo;
485 
486 #ifdef USING_GPU
487  delete utils;
488 #endif
489 
490 
491  return true;
492 }
493 
494 
495 void DispModule::recalibrate()
496 {
497 
498 #ifdef USING_GPU
499  utils->extractMatch_GPU(leftMat,rightMat);
500  vector<Point2f> leftM,rightM;
501  utils->getMatches(leftM,rightM);
502  mutexDisp.lock();
503  this->stereo->setMatches(leftM,rightM);
504 #else
505 
506  mutexDisp.lock();
507  stereo->findMatch(false);
508 #endif
509 
510  stereo->estimateEssential();
511  bool ok=stereo->essentialDecomposition();
512  mutexDisp.unlock();
513 
514  // if the calibration process has been successfull,
515  // stores the parameters estimated, otherwise stops the
516  // calibration process in case it has failed for five
517  // times in a row
518 
519  if (ok)
520  {
521  this->calibUpdated=true;
522  this->runRecalibration=false;
523  calibEndEvent.signal();
524 
525  R0=stereo->getRotation();
526  T0=stereo->getTranslation();
527  eyes0=eyes;
528 
529  std::cout << "[DisparityModule] Calibration Successful!" << std::endl;
530 
531  }
532  else
533  {
534  if (++numberOfTrials>5)
535  {
536  this->calibUpdated=false;
537  this->runRecalibration=false;
538  calibEndEvent.signal();
539 
540  std::cout << "[DisparityModule] Calibration failed after 5 trials.." << std::endl <<
541  "[DisparityModule] ..please show a non planar scene." << std::endl;
542 
543  }
544  }
545 }
546 
547 
548 #ifdef USE_GUI
549 void DispModule::handleGuiUpdate()
550 {
551 
552  // the calls to gui.set/getParameters and to
553  // matcher->set/getParameters() can be definitely
554  // improved, by wrapping everything in a Params struct
555  // as defined in StereoMatcher.h, this has to be implemented
556 
557  if(this->gui.toRecalibrate())
558  {
559  std::cout << "[DisparityModule] Updating calibration.." << std::endl;
560 
561  mutexRecalibration.lock();
562  numberOfTrials=0;
563  this->runRecalibration=true;
564  mutexRecalibration.unlock();
565 
566  }
567  else if(this->gui.toSaveCalibration())
568  {
569  std::cout << "[DisparityModule] Saving current calibration.." << std::endl;
570  updateConfigurationFile(R0,T0,eyes0,"STEREO_DISPARITY");
571  }
572  else if(this->gui.toLoadParameters())
573  {
574  std::cout << "[DisparityModule] Loading stereo parameters from file.." << std::endl;
575 
576  this->stereo_parameters = this->original_parameters;
577 
578  this->gui.setParameters(this->stereo_parameters.minDisparity,
579  this->stereo_parameters.numberOfDisparities,
580  this->stereo_parameters.SADWindowSize,
581  this->stereo_parameters.disp12MaxDiff,
582  this->stereo_parameters.preFilterCap,
583  this->stereo_parameters.uniquenessRatio,
584  this->stereo_parameters.speckleWindowSize,
585  this->stereo_parameters.speckleRange,
586  this->stereo_parameters.sigmaColorBLF,
587  this->stereo_parameters.sigmaSpaceBLF,
588  this->stereo_parameters.wls_lambda,
589  this->stereo_parameters.wls_sigma,
590  this->stereo_parameters.BLFfiltering,
591  this->stereo_parameters.WLSfiltering,
592  this->stereo_parameters.stereo_matching);
593 
594  this->matcher->setParameters(this->stereo_parameters.minDisparity,
595  this->stereo_parameters.numberOfDisparities,
596  this->stereo_parameters.SADWindowSize,
597  this->stereo_parameters.disp12MaxDiff,
598  this->stereo_parameters.preFilterCap,
599  this->stereo_parameters.uniquenessRatio,
600  this->stereo_parameters.speckleWindowSize,
601  this->stereo_parameters.speckleRange,
602  this->stereo_parameters.sigmaColorBLF,
603  this->stereo_parameters.sigmaSpaceBLF,
604  this->stereo_parameters.wls_lambda,
605  this->stereo_parameters.wls_sigma,
606  this->stereo_parameters.BLFfiltering,
607  this->stereo_parameters.WLSfiltering,
608  this->stereo_parameters.stereo_matching);
609 
610  this->matcher->updateCUDAParams();
611  }
612  else if(this->gui.toSaveParameters())
613  {
614  std::cout << "[DisparityModule] Saving stereo parameters.." << std::endl;
615  updateConfigurationFile(R0,T0,eyes0,"STEREO_DISPARITY");
616  }
617  else
618  {
619 
620  this->gui.getParameters(this->stereo_parameters.minDisparity,
621  this->stereo_parameters.numberOfDisparities,
622  this->stereo_parameters.SADWindowSize,
623  this->stereo_parameters.disp12MaxDiff,
624  this->stereo_parameters.preFilterCap,
625  this->stereo_parameters.uniquenessRatio,
626  this->stereo_parameters.speckleWindowSize,
627  this->stereo_parameters.speckleRange,
628  this->stereo_parameters.sigmaColorBLF,
629  this->stereo_parameters.sigmaSpaceBLF,
630  this->stereo_parameters.wls_lambda,
631  this->stereo_parameters.wls_sigma,
632  this->stereo_parameters.BLFfiltering,
633  this->stereo_parameters.WLSfiltering,
634  this->stereo_parameters.stereo_matching);
635 
636  this->matcher->setParameters(this->stereo_parameters.minDisparity,
637  this->stereo_parameters.numberOfDisparities,
638  this->stereo_parameters.SADWindowSize,
639  this->stereo_parameters.disp12MaxDiff,
640  this->stereo_parameters.preFilterCap,
641  this->stereo_parameters.uniquenessRatio,
642  this->stereo_parameters.speckleWindowSize,
643  this->stereo_parameters.speckleRange,
644  this->stereo_parameters.sigmaColorBLF,
645  this->stereo_parameters.sigmaSpaceBLF,
646  this->stereo_parameters.wls_lambda,
647  this->stereo_parameters.wls_sigma,
648  this->stereo_parameters.BLFfiltering,
649  this->stereo_parameters.WLSfiltering,
650  this->stereo_parameters.stereo_matching);
651 
652  this->matcher->updateCUDAParams();
653 
654  }
655 
656  this->gui.resetState();
657 }
658 #endif
659 
660 
661 bool DispModule::updateModule()
662 {
663  // acquire the left and right images
664 
665  ImageOf<PixelRgb> *yarp_imgL=leftImgPort.read(true);
666  ImageOf<PixelRgb> *yarp_imgR=rightImgPort.read(true);
667 
668  Stamp stamp_left, stamp_right;
669  leftImgPort.getEnvelope(stamp_left);
670  rightImgPort.getEnvelope(stamp_right);
671 
672  if ((yarp_imgL==NULL) || (yarp_imgR==NULL))
673  return true;
674 
675  // read encoders
676 
677  iencs->getEncoder(nHeadAxes-3,&eyes[0]);
678  iencs->getEncoder(nHeadAxes-2,&eyes[1]);
679  iencs->getEncoder(nHeadAxes-1,&eyes[2]);
680 
681  // updated the internal state by reading the information
682  // from the kinematics of the robot and from the GazeController
683 
684  updateViaKinematics(eyes-eyes0);
685  updateViaGazeCtrl(false);
686 
687  leftMat=toCvMat(*yarp_imgL);
688  rightMat=toCvMat(*yarp_imgR);
689 
690  // updates left/right eyes pose
691 
692  getCameraHGazeCtrl(LEFT);
693  getCameraHGazeCtrl(RIGHT);
694 
695  // stores the images in the StereoCamera object
696 
697  this->stereo->setImages(leftMat,rightMat);
698 
699 #ifdef USE_GUI
700  if(this->debugWindow && this->gui.isUpdated())
701  this->handleGuiUpdate();
702 #endif
703 
704  mutexRecalibration.lock();
705 
706  if(this->runRecalibration)
707  this->recalibrate();
708 
709  mutexRecalibration.unlock();
710 
711  // compute the current disparity map
712 
713  mutexDisp.lock();
714 
715  matcher->compute();
716 
717  mutexDisp.unlock();
718 
719  // execute the bilateral filtering of the
720  // disparity map, if selected
721 
722  matcher->filterBLF("base");
723 
724  // execute the WLS filtering, if selected
725 
726  matcher->filterWLS("blf");
727 
728  // if the disparity output port is active, sends
729  // the current (filtered) one
730 
731  if (outDisp.getOutputCount() > 0)
732  {
733 
734  // here, gets the disparity map after the WLS filtering,
735  // which does not imply that it has been actually been
736  // filtered in that way, it's just a convention so to
737  // get the "most" filtered disparity map available, on the
738  // basis of the selection of parameters by the user
739 
740  cv::Mat disp_vis = matcher->getDisparity("wls");
741 
742  if(!disp_vis.empty())
743  {
744 
745 #ifdef USE_GUI
746  if(gui.toRefine())
747  {
748  orig = disp_vis.clone();
749 
750  if(!old_d.empty())
751  disp_vis = refineDisparity(old_d, disp_vis, gui.getRefineTh());
752 
753  old_d = orig.clone();
754  }
755 #endif
756 
757  ImageOf<PixelMono> &outim = outDisp.prepare();
758 
759  outim = fromCvMat<PixelMono>(disp_vis);
760  outDisp.write();
761  }
762  }
763 
764  // if the output port is active, computes the depth
765  // map for the current disparity map (the filtered one,
766  // in case the bilateral filtering is selected)
767 
768  if (outDepth.getOutputCount() > 0)
769  {
770  cv::Mat disp_depth = matcher->getDisparity16("wls");
771 
772  if (disp_depth.empty())
773  {
774  std::cout << "[DisparityModule] Impossible to compute the depth map.." << std::endl <<
775  "[DisparityModule] ..the disparity map is not available!" << std::endl;
776  }
777  else
778  {
779 
780 #ifdef USE_GUI
781  if(gui.toRefine())
782  {
783  orig = disp_depth.clone();
784 
785  if(!old_de.empty())
786  disp_depth = refineDisparity(old_de, disp_depth, gui.getRefineTh());
787 
788  old_de = orig.clone();
789  }
790 #endif
791 
792  outputDepth = this->depthFromDisparity(disp_depth, this->stereo->getQ(), this->stereo->getRLrect());
793 
794  ImageOf<PixelFloat> &outim = outDepth.prepare();
795 
796  outim = fromCvMat<PixelFloat>(outputDepth);
797 
798  outDepth.write();
799  }
800  }
801 
802  // if the GUI is used, handles the interaction
803  // with it and updates its state
804 
805 #ifdef USE_GUI
806  if(this->debugWindow && !this->gui.isDone())
807  this->gui.updateGUI();
808 
809  if(this->gui.isDone())
810  this->gui.killGUI();
811 #endif
812 
813  return true;
814 }
815 
816 
817 double DispModule::getPeriod()
818 {
819  // the updateModule() method gets synchronized
820  // with camera input => no need for periodicity
821  return 0.0;
822 }
823 
824 
825 bool DispModule::loadExtrinsics(yarp::os::ResourceFinder& rf, Mat& Ro, Mat& To, yarp::sig::Vector& eyes)
826 {
827  Bottle extrinsics=rf.findGroup("STEREO_DISPARITY");
828 
829  eyes.resize(3,0.0);
830  if (Bottle *bEyes=extrinsics.find("eyes").asList())
831  {
832  size_t sz=std::min(eyes.length(),(size_t)bEyes->size());
833  for (size_t i=0; i<sz; i++)
834  eyes[i]=bEyes->get(i).asFloat64();
835  }
836 
837  std::cout << "[DisparityModule] Read Eyes Configuration = ("<<eyes.toString(3,3)<<")" << std::endl;
838 
839  if (Bottle *pXo=extrinsics.find("HN").asList())
840  {
841  Ro=Mat::zeros(3,3,CV_64FC1);
842  To=Mat::zeros(3,1,CV_64FC1);
843  for (int i=0; i<(pXo->size()-4); i+=4)
844  {
845  Ro.at<double>(i/4,0)=pXo->get(i).asFloat64();
846  Ro.at<double>(i/4,1)=pXo->get(i+1).asFloat64();
847  Ro.at<double>(i/4,2)=pXo->get(i+2).asFloat64();
848  To.at<double>(i/4,0)=pXo->get(i+3).asFloat64();
849  }
850  }
851  else
852  return false;
853 
854  return true;
855 }
856 
857 
858 bool DispModule::loadConfigurationFile(yarp::os::ResourceFinder& rf, Mat& Ro, Mat& To, yarp::sig::Vector& eyes)
859 {
860 
861  Bottle extrinsics=rf.findGroup("STEREO_DISPARITY");
862 
863  // loads the eyes configuration from file
864 
865  eyes.resize(3,0.0);
866  if (Bottle *bEyes=extrinsics.find("eyes").asList())
867  {
868  size_t sz = std::min(eyes.length(),(size_t)bEyes->size());
869  for (size_t i=0; i<sz; i++)
870  eyes[i] = bEyes->get(i).asFloat64();
871  }
872 
873  std::cout << "[DisparityModule] Read Eyes Configuration = ("
874  << eyes.toString(3,3) << ")" << std::endl;
875 
876  // loads the calibration matrix associated with the
877  // stereo system
878 
879  if (Bottle *pXo=extrinsics.find("HN").asList())
880  {
881  Ro=Mat::zeros(3,3,CV_64FC1);
882  To=Mat::zeros(3,1,CV_64FC1);
883  for (int i=0; i<(pXo->size()-4); i+=4)
884  {
885  Ro.at<double>(i/4,0) = pXo->get(i).asFloat64();
886  Ro.at<double>(i/4,1) = pXo->get(i+1).asFloat64();
887  Ro.at<double>(i/4,2) = pXo->get(i+2).asFloat64();
888  To.at<double>(i/4,0) = pXo->get(i+3).asFloat64();
889  }
890  }
891  else
892  return false;
893 
894  // loads the stereo parameters from the configuration file
895 
896  if (Bottle *pXo=extrinsics.find("params").asList())
897  {
898 
899  this->stereo_parameters.minDisparity = pXo->get(0).asInt32();
900  this->useBestDisp = pXo->get(1).asBool();
901  this->stereo_parameters.numberOfDisparities = pXo->get(2).asInt32();
902  this->stereo_parameters.SADWindowSize = pXo->get(3).asInt32();
903  this->stereo_parameters.disp12MaxDiff = pXo->get(4).asInt32();
904  this->stereo_parameters.preFilterCap = pXo->get(5).asInt32();
905  this->stereo_parameters.uniquenessRatio = pXo->get(6).asInt32();
906  this->stereo_parameters.speckleWindowSize = pXo->get(7).asInt32();
907  this->stereo_parameters.speckleRange = pXo->get(8).asInt32();
908 
909  this->stereo_parameters.sigmaColorBLF = pXo->get(9).asFloat64();
910  this->stereo_parameters.sigmaSpaceBLF = pXo->get(10).asFloat64();
911 
912  this->stereo_parameters.wls_lambda = pXo->get(11).asFloat64();
913  this->stereo_parameters.wls_sigma = pXo->get(12).asFloat64();
914 
915  this->stereo_parameters.stereo_matching = static_cast<SM_MATCHING_ALG>(pXo->get(13).asInt32());
916  this->stereo_parameters.BLFfiltering = static_cast<SM_BLF_FILTER>(pXo->get(14).asInt32());
917  this->stereo_parameters.WLSfiltering = static_cast<SM_WLS_FILTER>(pXo->get(15).asInt32());
918 
919  }
920  else
921  this->initializeStereoParams();
922 
923  return true;
924 }
925 
926 
927 bool DispModule::loadIntrinsics(yarp::os::ResourceFinder &rf, Mat &KL, Mat &KR, Mat &DistL,
928  Mat &DistR)
929 {
930  Bottle left=rf.findGroup("CAMERA_CALIBRATION_LEFT");
931  if(!left.check("fx") || !left.check("fy") || !left.check("cx") || !left.check("cy"))
932  return false;
933 
934  double fx=left.find("fx").asFloat64();
935  double fy=left.find("fy").asFloat64();
936 
937  double cx=left.find("cx").asFloat64();
938  double cy=left.find("cy").asFloat64();
939 
940  double k1=left.check("k1",Value(0)).asFloat64();
941  double k2=left.check("k2",Value(0)).asFloat64();
942 
943  double p1=left.check("p1",Value(0)).asFloat64();
944  double p2=left.check("p2",Value(0)).asFloat64();
945 
946  DistL=Mat::zeros(1,8,CV_64FC1);
947  DistL.at<double>(0,0)=k1;
948  DistL.at<double>(0,1)=k2;
949  DistL.at<double>(0,2)=p1;
950  DistL.at<double>(0,3)=p2;
951 
952  KL=Mat::eye(3,3,CV_64FC1);
953  KL.at<double>(0,0)=fx;
954  KL.at<double>(0,2)=cx;
955  KL.at<double>(1,1)=fy;
956  KL.at<double>(1,2)=cy;
957 
958  Bottle right=rf.findGroup("CAMERA_CALIBRATION_RIGHT");
959  if(!right.check("fx") || !right.check("fy") || !right.check("cx") || !right.check("cy"))
960  return false;
961 
962  fx=right.find("fx").asFloat64();
963  fy=right.find("fy").asFloat64();
964 
965  cx=right.find("cx").asFloat64();
966  cy=right.find("cy").asFloat64();
967 
968  k1=right.check("k1",Value(0)).asFloat64();
969  k2=right.check("k2",Value(0)).asFloat64();
970 
971  p1=right.check("p1",Value(0)).asFloat64();
972  p2=right.check("p2",Value(0)).asFloat64();
973 
974  DistR=Mat::zeros(1,8,CV_64FC1);
975  DistR.at<double>(0,0)=k1;
976  DistR.at<double>(0,1)=k2;
977  DistR.at<double>(0,2)=p1;
978  DistR.at<double>(0,3)=p2;
979 
980  KR=Mat::eye(3,3,CV_64FC1);
981  KR.at<double>(0,0)=fx;
982  KR.at<double>(0,2)=cx;
983  KR.at<double>(1,1)=fy;
984  KR.at<double>(1,2)=cy;
985 
986  return true;
987 }
988 
989 
990 
991 bool DispModule::updateExtrinsics(Mat& Rot, Mat& Tr, yarp::sig::Vector& eyes,
992  const string& groupname)
993 {
994  ofstream out;
995  out.open(camCalibFile.c_str());
996  if (out.is_open())
997  {
998  out << endl;
999  out << "["+groupname+"]" << endl;
1000  out << "eyes (" << eyes.toString() << ")" << endl;
1001  out << "HN ("
1002  << Rot.at<double>(0,0) << " "
1003  << Rot.at<double>(0,1) << " "
1004  << Rot.at<double>(0,2) << " "
1005  << Tr.at<double>(0,0) << " "
1006  << Rot.at<double>(1,0) << " "
1007  << Rot.at<double>(1,1) << " "
1008  << Rot.at<double>(1,2) << " "
1009  << Tr.at<double>(1,0) << " "
1010  << Rot.at<double>(2,0) << " "
1011  << Rot.at<double>(2,1) << " "
1012  << Rot.at<double>(2,2) << " "
1013  << Tr.at<double>(2,0) << " "
1014  << 0.0 << " " << 0.0 << " " << 0.0 << " " << 1.0 << ")"
1015  << endl;
1016 
1017  out.close();
1018  return true;
1019  }
1020  else
1021  return false;
1022 }
1023 
1024 
1025 bool DispModule::updateConfigurationFile(Mat& Rot, Mat& Tr, yarp::sig::Vector& eyes,
1026  const string& groupname)
1027 {
1028  ofstream out;
1029  out.open(camCalibFile.c_str());
1030  if (out.is_open())
1031  {
1032  out << endl;
1033  out << "["+groupname+"]" << endl;
1034  out << "eyes (" << eyes.toString() << ")" << endl;
1035  out << "HN ("
1036  << Rot.at<double>(0,0) << " "
1037  << Rot.at<double>(0,1) << " "
1038  << Rot.at<double>(0,2) << " "
1039  << Tr.at<double>(0,0) << " "
1040  << Rot.at<double>(1,0) << " "
1041  << Rot.at<double>(1,1) << " "
1042  << Rot.at<double>(1,2) << " "
1043  << Tr.at<double>(1,0) << " "
1044  << Rot.at<double>(2,0) << " "
1045  << Rot.at<double>(2,1) << " "
1046  << Rot.at<double>(2,2) << " "
1047  << Tr.at<double>(2,0) << " "
1048  << 0.0 << " " << 0.0 << " " << 0.0 << " " << 1.0 << ")"
1049  << endl;
1050 
1051  // TODO: change the following code and insert the stereo
1052  // parameters in the corresponding struct as defined in StereoMatcher.h
1053 
1054  out << "params ("
1055  << this->stereo_parameters.minDisparity << " "
1056  << this->useBestDisp << " "
1057  << this->stereo_parameters.numberOfDisparities << " "
1058  << this->stereo_parameters.SADWindowSize << " "
1059  << this->stereo_parameters.disp12MaxDiff << " "
1060  << this->stereo_parameters.preFilterCap << " "
1061  << this->stereo_parameters.uniquenessRatio << " "
1062  << this->stereo_parameters.speckleWindowSize << " "
1063  << this->stereo_parameters.speckleRange << " "
1064  << this->stereo_parameters.sigmaColorBLF << " "
1065  << this->stereo_parameters.sigmaSpaceBLF << " "
1066  << this->stereo_parameters.wls_lambda << " "
1067  << this->stereo_parameters.wls_sigma << " "
1068  << this->stereo_parameters.stereo_matching << " "
1069  << this->stereo_parameters.BLFfiltering << " "
1070  << this->stereo_parameters.WLSfiltering << ")"
1071  << endl;
1072 
1073  out.close();
1074  return true;
1075  }
1076  else
1077  return false;
1078 }
1079 
1080 
1081 void DispModule::setDispParameters(bool _useBestDisp, int _uniquenessRatio,
1082  int _speckleWindowSize,int _speckleRange,
1083  int _numberOfDisparities, int _SADWindowSize,
1084  int _minDisparity, int _preFilterCap, int _disp12MaxDiff)
1085 {
1086  this->mutexDisp.lock();
1087 
1088  this->useBestDisp=_useBestDisp;
1089  this->stereo_parameters.uniquenessRatio=_uniquenessRatio;
1090  this->stereo_parameters.speckleWindowSize=_speckleWindowSize;
1091  this->stereo_parameters.speckleRange=_speckleRange;
1092  this->stereo_parameters.numberOfDisparities=_numberOfDisparities;
1093  this->stereo_parameters.SADWindowSize=_SADWindowSize;
1094  this->stereo_parameters.minDisparity=_minDisparity;
1095  this->stereo_parameters.preFilterCap=_preFilterCap;
1096  this->stereo_parameters.disp12MaxDiff=_disp12MaxDiff;
1097 
1098  this->mutexDisp.unlock();
1099 
1100 }
1101 
1102 
1103 Point3f DispModule::get3DPoints(int u, int v, const string &drive)
1104 {
1105  Point3f point(0.0f,0.0f,0.0f);
1106  if ((drive!="RIGHT") && (drive!="LEFT") && (drive!="ROOT"))
1107  return point;
1108 
1109  std::lock_guard<std::mutex> lg(mutexDisp);
1110 
1111  // Mapping from Rectified Cameras to Original Cameras
1112  const Mat& Mapper=this->stereo->getMapperL();
1113  if (Mapper.empty())
1114  return point;
1115 
1116  float usign=Mapper.ptr<float>(v)[2*u];
1117  float vsign=Mapper.ptr<float>(v)[2*u+1];
1118 
1119  u=cvRound(usign);
1120  v=cvRound(vsign);
1121 
1122  const Mat& disp16m=this->matcher->getDisparity16("wls");
1123  if (disp16m.empty() || (u<0) || (u>=disp16m.cols) || (v<0) || (v>=disp16m.rows))
1124  return point;
1125 
1126  const Mat& Q=this->stereo->getQ();
1127  IplImage disp16=disp16m;
1128  CvScalar scal=cvGet2D(&disp16,v,u);
1129  double disparity=scal.val[0]/16.0;
1130  float w=(float)(disparity*Q.at<double>(3,2)+Q.at<double>(3,3));
1131  point.x=(float)((usign+1)*Q.at<double>(0,0)+Q.at<double>(0,3));
1132  point.y=(float)((vsign+1)*Q.at<double>(1,1)+Q.at<double>(1,3));
1133  point.z=(float)Q.at<double>(2,3);
1134 
1135  point.x/=w;
1136  point.y/=w;
1137  point.z/=w;
1138 
1139  // discard points far more than 10 meters or with not valid disparity (<0)
1140 
1141  // TODO: "discards" means it returns the point in the same way?
1142 
1143  if ((point.z>10.0f) || (point.z<0.0f))
1144  return point;
1145 
1146  if (drive=="ROOT")
1147  {
1148  const Mat& RLrect=this->stereo->getRLrect().t();
1149  Mat Tfake=Mat::zeros(0,3,CV_64F);
1150  Mat P(4,1,CV_64FC1);
1151  P.at<double>(0,0)=point.x;
1152  P.at<double>(1,0)=point.y;
1153  P.at<double>(2,0)=point.z;
1154  P.at<double>(3,0)=1.0;
1155 
1156  Mat Hrect=buildRotTras(RLrect,Tfake);
1157  P=HL_root*Hrect*P;
1158  point.x=(float)(P.at<double>(0,0)/P.at<double>(3,0));
1159  point.y=(float)(P.at<double>(1,0)/P.at<double>(3,0));
1160  point.z=(float)(P.at<double>(2,0)/P.at<double>(3,0));
1161  }
1162  else if (drive=="LEFT")
1163  {
1164  Mat P(3,1,CV_64FC1);
1165  P.at<double>(0,0)=point.x;
1166  P.at<double>(1,0)=point.y;
1167  P.at<double>(2,0)=point.z;
1168 
1169  P=this->stereo->getRLrect().t()*P;
1170  point.x=(float)P.at<double>(0,0);
1171  point.y=(float)P.at<double>(1,0);
1172  point.z=(float)P.at<double>(2,0);
1173  }
1174  else if (drive=="RIGHT")
1175  {
1176  const Mat& Rright=this->stereo->getRotation();
1177  const Mat& Tright=this->stereo->getTranslation();
1178  const Mat& RRright=this->stereo->getRRrect().t();
1179  Mat TRright=Mat::zeros(0,3,CV_64F);
1180 
1181  Mat HRL=buildRotTras(Rright,Tright);
1182  Mat Hrect=buildRotTras(RRright,TRright);
1183 
1184  Mat P(4,1,CV_64FC1);
1185  P.at<double>(0,0)=point.x;
1186  P.at<double>(1,0)=point.y;
1187  P.at<double>(2,0)=point.z;
1188  P.at<double>(3,0)=1.0;
1189 
1190  P=Hrect*HRL*P;
1191  point.x=(float)(P.at<double>(0,0)/P.at<double>(3,0));
1192  point.y=(float)(P.at<double>(1,0)/P.at<double>(3,0));
1193  point.z=(float)(P.at<double>(2,0)/P.at<double>(3,0));
1194  }
1195 
1196  return point;
1197 }
1198 
1199 
1200 Mat DispModule::buildRotTras(const Mat& R, const Mat& T)
1201 {
1202  Mat A=Mat::eye(4,4,CV_64F);
1203  for (int i=0; i<R.rows; i++)
1204  {
1205  double* Mi=A.ptr<double>(i);
1206  const double* MRi=R.ptr<double>(i);
1207  for (int j=0; j<R.cols; j++)
1208  Mi[j]=MRi[j];
1209  }
1210 
1211  for (int i=0; i<T.rows; i++)
1212  {
1213  double* Mi=A.ptr<double>(i);
1214  const double* MRi=T.ptr<double>(i);
1215  Mi[3]=MRi[0];
1216  }
1217 
1218  return A;
1219 }
1220 
1221 
1222 
1223 Matrix DispModule::getCameraHGazeCtrl(int camera)
1224 {
1225  yarp::sig::Vector x_curr;
1226  yarp::sig::Vector o_curr;
1227  bool check=false;
1228  if(camera==LEFT)
1229  check=igaze->getLeftEyePose(x_curr, o_curr);
1230  else
1231  check=igaze->getRightEyePose(x_curr, o_curr);
1232 
1233  if(!check)
1234  {
1235  Matrix H_curr(4, 4);
1236  return H_curr;
1237  }
1238 
1239  Matrix R_curr=axis2dcm(o_curr);
1240  Matrix H_curr=R_curr;
1241  H_curr.setSubcol(x_curr,0,3);
1242 
1243  if(camera==LEFT)
1244  {
1245  mutexDisp.lock();
1246  convert(H_curr,HL_root);
1247  mutexDisp.unlock();
1248  }
1249  else if(camera==RIGHT)
1250  {
1251  mutexDisp.lock();
1252  convert(H_curr,HR_root);
1253  mutexDisp.unlock();
1254  }
1255 
1256  return H_curr;
1257 }
1258 
1259 
1260 
1261 void DispModule::convert(Matrix& matrix, Mat& mat)
1262 {
1263  mat=cv::Mat(matrix.rows(),matrix.cols(),CV_64FC1);
1264  for(int i=0; i<matrix.rows(); i++)
1265  for(int j=0; j<matrix.cols(); j++)
1266  mat.at<double>(i,j)=matrix(i,j);
1267 }
1268 
1269 
1270 
1271 void DispModule::convert(Mat& mat, Matrix& matrix)
1272 {
1273  matrix.resize(mat.rows,mat.cols);
1274  for(int i=0; i<mat.rows; i++)
1275  for(int j=0; j<mat.cols; j++)
1276  matrix(i,j)=mat.at<double>(i,j);
1277 }
1278 
1279 
1280 
1281 bool DispModule::respond(const Bottle& command, Bottle& reply)
1282 {
1283  if(command.size()==0)
1284  return false;
1285 
1286  if (command.get(0).asString()=="quit") {
1287  std::cout << "[DisparityModule] Closing..." << std::endl;
1288  return false;
1289  }
1290 
1291  if (command.get(0).asString()=="help") {
1292  reply.addVocab32("many");
1293  reply.addString("Available commands are:");
1294  reply.addString("- [calibrate]: It recomputes the camera positions once.");
1295  reply.addString("- [save]: It saves the current camera positions and uses it when the module starts.");
1296  reply.addString("- [getH]: It returns the calibrated stereo matrix.");
1297  reply.addString("- [setNumDisp NumOfDisparities]: It sets the expected number of disparity (in pixel). Values must be divisible by 32. ");
1298  reply.addString("- [Point x y]: Given the pixel coordinate x,y in the Left image the response is the 3D Point: X Y Z computed using the depth map wrt the LEFT eye.");
1299  reply.addString("- [x y]: Given the pixel coordinate x,y in the Left image the response is the 3D Point: X Y Z ur vr computed using the depth map wrt the the ROOT reference system.(ur vr) is the corresponding pixel in the Right image. ");
1300  reply.addString("- [Left x y]: Given the pixel coordinate x,y in the Left image the response is the 3D Point: X Y Z computed using the depth map wrt the LEFT eye. Points with non valid disparity (i.e. occlusions) are handled with the value (0.0,0.0,0.0). ");
1301  reply.addString("- [Right x y]: Given the pixel coordinate x,y in the Left image the response is the 3D Point: X Y Z computed using the depth map wrt the RIGHT eye. Points with non valid disparity (i.e. occlusions) are handled with the value (0.0,0.0,0.0).");
1302  reply.addString("- [Root x y]: Given the pixel coordinate x,y in the Left image the response is the 3D Point: X Y Z computed using the depth map wrt the ROOT reference system. Points with non valid disparity (i.e. occlusions) are handled with the value (0.0,0.0,0.0).");
1303  reply.addString("- [Rect tlx tly w h step]: Given the pixels in the rectangle defined by {(tlx,tly) (tlx+w,tly+h)} (parsed by columns), the response contains the corresponding 3D points in the ROOT frame. The optional parameter step defines the sampling quantum; by default step=1.");
1304  reply.addString("- [Points u_1 v_1 ... u_n v_n]: Given a list of n pixels, the response contains the corresponding 3D points in the ROOT frame.");
1305  reply.addString("- [Flood3D x y dist]: Perform 3D flood-fill on the seed point (x,y), returning the following info: [u_1 v_1 x_1 y_1 z_1 ...]. The optional parameter dist expressed in meters regulates the fill (by default = 0.004).");
1306  reply.addString("- [uL_1 vL_1 uR_1 vR_1 ... uL_n vL_n uR_n vR_n]: Given n quadruples uL_i vL_i uR_i vR_i, where uL_i vL_i are the pixel coordinates in the Left image and uR_i vR_i are the coordinates of the matched pixel in the Right image, the response is a set of 3D points (X1 Y1 Z1 ... Xn Yn Zn) wrt the ROOT reference system.");
1307  reply.addString("- [cart2stereo X Y Z]: Given a world point X Y Z wrt to ROOT reference frame the response is the projection (uL vL uR vR) in the Left and Right images.");
1308  reply.addString("- [doBLF flag]: activate Bilateral filter for flag = true, and skip it for flag = false.");
1309  reply.addString("- [bilatfilt sigmaColor sigmaSpace]: Set the parameters for the bilateral filer (default sigmaColor = 10.0, sigmaSpace = 10.0).");
1310  reply.addString("- [algorithm name]: Set the stereo matching algorithm used (default = SGMB(cpu)).");
1311  reply.addString("For more details on the commands, check the module's documentation");
1312  return true;
1313  }
1314 
1315  if (command.get(0).asString()=="calibrate")
1316  {
1317  mutexRecalibration.lock();
1318  numberOfTrials=0;
1319  this->runRecalibration=true;
1320  mutexRecalibration.unlock();
1321 
1322  calibEndEvent.reset();
1323  calibEndEvent.wait();
1324 
1325  if (this->calibUpdated)
1326  {
1327  R0=this->stereo->getRotation();
1328  T0=this->stereo->getTranslation();
1329  eyes0=eyes;
1330 
1331  reply.addString("ACK");
1332  }
1333  else
1334  reply.addString("[DisparityModule] Calibration failed after 5 trials.. Please show a non planar scene.");
1335 
1336  return true;
1337  }
1338 
1339  if (command.get(0).asString()=="save")
1340  {
1341  updateExtrinsics(R0,T0,eyes0,"STEREO_DISPARITY");
1342  reply.addString("ACK");
1343  return true;
1344  }
1345 
1346  if (command.get(0).asString()=="getH")
1347  {
1348  Mat RT0=buildRotTras(R0,T0);
1349  Matrix H0; convert(RT0,H0);
1350 
1351  reply.read(H0);
1352  return true;
1353  }
1354 
1355  if (command.get(0).asString()=="setNumDisp")
1356  {
1357  int dispNum=command.get(1).asInt32();
1358  if(dispNum%32==0)
1359  {
1360  this->stereo_parameters.numberOfDisparities=dispNum;
1361  this->setDispParameters(useBestDisp,
1362  this->stereo_parameters.uniquenessRatio,
1363  this->stereo_parameters.speckleWindowSize,
1364  this->stereo_parameters.speckleRange,
1365  this->stereo_parameters.numberOfDisparities,
1366  this->stereo_parameters.SADWindowSize,
1367  this->stereo_parameters.minDisparity,
1368  this->stereo_parameters.preFilterCap,
1369  this->stereo_parameters.disp12MaxDiff);
1370  reply.addString("ACK");
1371  return true;
1372  }
1373  else
1374  {
1375  reply.addString("Num Disparity must be divisible by 32");
1376  return true;
1377  }
1378  }
1379 
1380  if (command.get(0).asString()=="setMinDisp")
1381  {
1382  int dispNum=command.get(1).asInt32();
1383  this->stereo_parameters.minDisparity=dispNum;
1384  this->setDispParameters(useBestDisp,
1385  this->stereo_parameters.uniquenessRatio,
1386  this->stereo_parameters.speckleWindowSize,
1387  this->stereo_parameters.speckleRange,
1388  this->stereo_parameters.numberOfDisparities,
1389  this->stereo_parameters.SADWindowSize,
1390  this->stereo_parameters.minDisparity,
1391  this->stereo_parameters.preFilterCap,
1392  this->stereo_parameters.disp12MaxDiff);
1393  reply.addString("ACK");
1394  return true;
1395  }
1396 
1397  if (command.get(0).asString()=="set" && command.size()==10)
1398  {
1399  bool useBestDisp=command.get(1).asInt32() ? true : false;
1400  int uniquenessRatio=command.get(2).asInt32();
1401  int speckleWindowSize=command.get(3).asInt32();
1402  int speckleRange=command.get(4).asInt32();
1403  int numberOfDisparities=command.get(5).asInt32();
1404  int SADWindowSize=command.get(6).asInt32();
1405  int minDisparity=command.get(7).asInt32();
1406  int preFilterCap=command.get(8).asInt32();
1407  int disp12MaxDiff=command.get(9).asInt32();
1408 
1409  this->setDispParameters(useBestDisp,
1410  uniquenessRatio,
1411  speckleWindowSize,
1412  speckleRange,
1413  numberOfDisparities,
1414  SADWindowSize,
1415  minDisparity,
1416  preFilterCap,
1417  disp12MaxDiff);
1418 
1419  reply.addString("ACK");
1420  }
1421  else if (command.get(0).asString()=="Point" || command.get(0).asString()=="Left" )
1422  {
1423  int u = command.get(1).asInt32();
1424  int v = command.get(2).asInt32();
1425  Point3f point = this->get3DPoints(u,v);
1426  reply.addFloat64(point.x);
1427  reply.addFloat64(point.y);
1428  reply.addFloat64(point.z);
1429  }
1430  else if (command.get(0).asString()=="Right")
1431  {
1432  int u = command.get(1).asInt32();
1433  int v = command.get(2).asInt32();
1434  Point3f point = this->get3DPoints(u,v,"RIGHT");
1435  reply.addFloat64(point.x);
1436  reply.addFloat64(point.y);
1437  reply.addFloat64(point.z);
1438  }
1439  else if (command.get(0).asString()=="Root")
1440  {
1441  int u = command.get(1).asInt32();
1442  int v = command.get(2).asInt32();
1443  Point3f point = this->get3DPoints(u,v,"ROOT");
1444  reply.addFloat64(point.x);
1445  reply.addFloat64(point.y);
1446  reply.addFloat64(point.z);
1447  }
1448  else if (command.get(0).asString()=="Rect")
1449  {
1450  int tl_u = command.get(1).asInt32();
1451  int tl_v = command.get(2).asInt32();
1452  int br_u = tl_u+command.get(3).asInt32();
1453  int br_v = tl_v+command.get(4).asInt32();
1454 
1455  int step = 1;
1456  if (command.size()>=6)
1457  step=command.get(5).asInt32();
1458 
1459  for (int u=tl_u; u<br_u; u+=step)
1460  {
1461  for (int v=tl_v; v<br_v; v+=step)
1462  {
1463  Point3f point=this->get3DPoints(u,v,"ROOT");
1464  reply.addFloat64(point.x);
1465  reply.addFloat64(point.y);
1466  reply.addFloat64(point.z);
1467  }
1468  }
1469  }
1470  else if (command.get(0).asString()=="Points")
1471  {
1472  for (int cnt=1; cnt<command.size()-1; cnt+=2)
1473  {
1474  int u=command.get(cnt).asInt32();
1475  int v=command.get(cnt+1).asInt32();
1476  Point3f point=this->get3DPoints(u,v,"ROOT");
1477  reply.addFloat64(point.x);
1478  reply.addFloat64(point.y);
1479  reply.addFloat64(point.z);
1480  }
1481  }
1482  else if (command.get(0).asString()=="cart2stereo")
1483  {
1484  double x = command.get(1).asFloat64();
1485  double y = command.get(2).asFloat64();
1486  double z = command.get(3).asFloat64();
1487 
1488  Point2f pointL = this->projectPoint("left",x,y,z);
1489  Point2f pointR = this->projectPoint("right",x,y,z);
1490 
1491  reply.addFloat64(pointL.x);
1492  reply.addFloat64(pointL.y);
1493  reply.addFloat64(pointR.x);
1494  reply.addFloat64(pointR.y);
1495  }
1496  else if (command.get(0).asString()=="bilatfilt" && command.size()==3)
1497  {
1498  if (!this->doBLF){
1499  this->doBLF = true;
1500  reply.addString("Bilateral filter activated.");
1501  }
1502  this->stereo_parameters.sigmaColorBLF = command.get(1).asFloat64();
1503  this->stereo_parameters.sigmaSpaceBLF = command.get(2).asFloat64();
1504  reply.addString("BLF sigmaColor ");
1505  reply.addFloat64(this->stereo_parameters.sigmaColorBLF);
1506  reply.addString("BLF sigmaSpace ");
1507  reply.addFloat64(this->stereo_parameters.sigmaSpaceBLF);
1508  }
1509  else if (command.get(0).asString()=="doBLF")
1510  {
1511  bool onoffBLF = command.get(1).asBool();
1512  if (onoffBLF == false ){ // turn OFF Bilateral Filtering
1513  if (this->doBLF == true){
1514  this->doBLF = false;
1515  reply.addString("Bilateral Filter OFF");
1516  } else {
1517  reply.addString("Bilateral Filter already OFF");
1518  }
1519 
1520  } else { // turn ON Bilateral Filtering
1521  if (this->doBLF == true){
1522  reply.addString("Bilateral Filter Already Running");
1523  } else { // Set any different from 0 to activate bilateral filter.
1524  this->doBLF = true;
1525  reply.addString("Bilateral Filter ON");
1526  }
1527  }
1528  reply.addFloat64(this->stereo_parameters.sigmaColorBLF);
1529  reply.addFloat64(this->stereo_parameters.sigmaSpaceBLF);
1530  }
1531  else
1532  reply.addString("NACK");
1533 
1534  return true;
1535 }
1536 
1537 
1538 Point2f DispModule::projectPoint(const string &camera, double x, double y, double z)
1539 {
1540  Point3f point3D;
1541  point3D.x=(float)x;
1542  point3D.y=(float)y;
1543  point3D.z=(float)z;
1544 
1545  vector<Point3f> points3D;
1546 
1547  points3D.push_back(point3D);
1548 
1549  vector<Point2f> response;
1550 
1551  mutexDisp.lock();
1552 
1553  if(camera=="left")
1554  response=this->stereo->projectPoints3D("left",points3D,HL_root);
1555  else
1556  response=this->stereo->projectPoints3D("right",points3D,HL_root); // this should be HR_root
1557 
1558  mutexDisp.unlock();
1559 
1560  return response[0];
1561 }
1562 
1563 
1564 cv::Mat DispModule::refineDisparity(cv::Mat old_disp, cv::Mat new_disp, int th)
1565 {
1566  cv::Mat mask, result;
1567 
1568  cv::absdiff(old_disp, new_disp, mask);
1569  cv::threshold(mask, mask, th, 1, cv::THRESH_BINARY_INV);
1570 
1571  result = new_disp.mul(mask);
1572 
1573  return result;
1574 }
1575 
1576 
1577 DispModule::~DispModule()
1578 {
1579 
1580 #ifdef USE_GUI
1581  if(this->debugWindow)
1582  this->gui.killGUI();
1583 #endif
1584 
1585 }
1586 
1587 
1588 DispModule::DispModule()
1589 {
1590  this->debugWindow = false;
1591 }
1592 
1593 
1594 int main(int argc, char *argv[])
1595 {
1596  Network yarp;
1597 
1598  if (!yarp.checkNetwork())
1599  return 1;
1600 
1601  // rough quick check of the command line parameters,
1602  // has to be definitely made in a smart way
1603 
1604  ResourceFinder rf;
1605  rf.setDefaultContext("cameraCalibration");
1606  rf.configure(argc, argv);
1607 
1608  if(rf.check("use640"))
1609  rf.setDefaultConfigFile("icubEyes_640x480.ini");
1610  else
1611  rf.setDefaultConfigFile("icubEyes.ini");
1612 
1613  rf.configure(argc, argv);
1614 
1615  DispModule mod;
1616 
1617  return mod.runModule(rf);
1618 }
The base class defining stereo camera.
Definition: stereoCamera.h:92