UsTK : Ultrasound ToolKit  version 2.0.1 under development (2024-12-17)
testUsTissueTranslationEstimatorUKF.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ustk software.
4  * Copyright (C) 2016 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ustk with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * This software was developed at:
17  * Inria Rennes - Bretagne Atlantique
18  * Campus Universitaire de Beaulieu
19  * 35042 Rennes Cedex
20  * France
21  *
22  * If you have questions regarding the use of this file, please contact
23  * Inria at ustk@inria.fr
24  *
25  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27  *
28  * Author:
29  * Jason Chevrie
30  *
31  *****************************************************************************/
32 
41 #include <visp3/core/vpConfig.h>
42 
43 #include <iostream>
44 #include <stdlib.h>
45 #include <string>
46 #include <vector>
47 
48 #include <visp3/gui/vpDisplayD3D.h>
49 #include <visp3/gui/vpDisplayGDI.h>
50 #include <visp3/gui/vpDisplayGTK.h>
51 #include <visp3/gui/vpDisplayOpenCV.h>
52 #include <visp3/gui/vpDisplayX.h>
53 
54 #include <visp3/io/vpParseArgv.h>
55 
56 #include <visp3/core/vpColVector.h>
57 #include <visp3/core/vpHomogeneousMatrix.h>
58 #include <visp3/core/vpImage.h>
59 #include <visp3/core/vpMatrix.h>
60 #if defined(VISP_HAVE_DISPLAY)
61 #include <visp3/gui/vpPlot.h>
62 #endif
63 #include <visp3/core/vpRGBa.h>
64 
65 #include <visp3/ustk_needle_modeling/usNeedleModelingDisplayTools.h>
66 #include <visp3/ustk_needle_modeling/usNeedleInsertionModelRayleighRitzSpline.h>
67 #include <visp3/ustk_needle_modeling/usTissueTranslationEstimatorUKF.h>
68 
69 // List of allowed command line options
70 #define GETOPTARGS "hlt:cd"
71 
72 typedef enum { vpX11, vpGTK, vpGDI, vpD3D, vpCV } vpDisplayType;
73 
74 void usage(const char *name, const char *badparam, vpDisplayType &dtype);
75 bool getOptions(int argc, const char **argv, vpDisplayType &dtype, bool &list, bool &display);
76 
87 void usage(const char *name, const char *badparam, vpDisplayType &dtype)
88 {
89  fprintf(stdout, "\n\
90 Tests the class usTissueTranslationEstimatorUKF.\n\
91 \n\
92 SYNOPSIS\n\
93  %s [-t <type of video device>] [-l] [-d] [-h]\n\
94 ", name);
95 
96  std::string display;
97  switch (dtype) {
98  case vpX11:
99  display = "X11";
100  break;
101  case vpGTK:
102  display = "GTK";
103  break;
104  case vpGDI:
105  display = "GDI";
106  break;
107  case vpD3D:
108  display = "D3D";
109  break;
110  case vpCV:
111  display = "CV";
112  break;
113  }
114 
115  fprintf(stdout, "\n\
116 OPTIONS: Default\n\
117 \n\
118  -t <type of video device> \"%s\"\n\
119  String specifying the video device to use.\n\
120  Possible values:\n\
121  \"X11\": only on UNIX platforms,\n\
122  \"GTK\": on all plaforms,\n\
123  \"GDI\": only on Windows platform (Graphics Device Interface),\n\
124  \"D3D\": only on Windows platform (Direct3D).\n\
125  \"CV\" : (OpenCV).\n\
126 \n\
127  -l\n\
128  Print the list of video-devices available and exit.\n\
129 \n\
130  -d \n\
131  Turn off the display.\n\
132 \n\
133  -h\n\
134  Print the help.\n\n", display.c_str());
135 
136  if (badparam)
137  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
138 }
139 
156 bool getOptions(int argc, const char **argv, vpDisplayType &dtype, bool &list, bool &display)
157 {
158  const char *optarg_;
159  int c;
160  std::string sDisplayType;
161  while((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1)
162  {
163 
164  switch (c)
165  {
166  case 'l':
167  list = true;
168  break;
169  case 't':
170  sDisplayType = optarg_;
171  // Parse the display type option
172  if(sDisplayType.compare("X11") == 0) dtype = vpX11;
173  else if (sDisplayType.compare("GTK") == 0) dtype = vpGTK;
174  else if (sDisplayType.compare("GDI") == 0) dtype = vpGDI;
175  else if (sDisplayType.compare("D3D") == 0) dtype = vpD3D;
176  else if (sDisplayType.compare("CV") == 0) dtype = vpCV;
177 
178  break;
179  case 'h':
180  usage(argv[0], NULL, dtype);
181  return false;
182  break;
183  case 'c':
184  break;
185  case 'd':
186  display = false;
187  break;
188 
189 
190  default:
191  usage(argv[0], optarg_, dtype);
192  return false;
193  break;
194  }
195  }
196 
197  if((c == 1) || (c == -1))
198  {
199  // standalone param or error
200  usage(argv[0], NULL, dtype);
201  std::cerr << "ERROR: " << std::endl;
202  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
203  return false;
204  }
205 
206  return true;
207 }
208 
209 
210 
211 int main(int argc, const char **argv)
212 {
213  bool opt_list = false; // To print the list of video devices
214  vpDisplayType opt_dtype; // Type of display to use
215  bool opt_display = true;
216 
217 // Default display is one available
218 #if defined VISP_HAVE_GTK
219  opt_dtype = vpGTK;
220 #elif defined VISP_HAVE_X11
221  opt_dtype = vpX11;
222 #elif defined VISP_HAVE_GDI
223  opt_dtype = vpGDI;
224 #elif defined VISP_HAVE_D3D9
225  opt_dtype = vpD3D;
226 #elif defined VISP_HAVE_OPENCV
227  opt_dtype = vpCV;
228 #endif
229 
230  // Read the command line options
231  if(!getOptions(argc, argv, opt_dtype, opt_list, opt_display)) exit(-1);
232 
233  // Print the list of video-devices available
234  if (opt_list) {
235  unsigned nbDevices = 0;
236  std::cout << "List of video-devices available: \n";
237 #if defined VISP_HAVE_GTK
238  std::cout << " GTK (use \"-t GTK\" option to use it)\n";
239  nbDevices++;
240 #endif
241 #if defined VISP_HAVE_X11
242  std::cout << " X11 (use \"-t X11\" option to use it)\n";
243  nbDevices++;
244 #endif
245 #if defined VISP_HAVE_GDI
246  std::cout << " GDI (use \"-t GDI\" option to use it)\n";
247  nbDevices++;
248 #endif
249 #if defined VISP_HAVE_D3D9
250  std::cout << " D3D (use \"-t D3D\" option to use it)\n";
251  nbDevices++;
252 #endif
253 #if defined VISP_HAVE_OPENCV
254  std::cout << " CV (use \"-t CV\" option to use it)\n";
255  nbDevices++;
256 #endif
257  if (!nbDevices) {
258  std::cout << " No display is available\n";
259  }
260  return (0);
261  }
262 
263  vpImage<unsigned char> I1(700, 500, 255);
264  vpImage<vpRGBa> I2(700, 500, vpRGBa(255,255,255,255));
265 
266  vpDisplay *display1 = nullptr;
267  vpDisplay *display2 = nullptr;
268 #if defined(VISP_HAVE_DISPLAY)
269  vpPlot *statePlot = NULL;
270 #endif
271 
272  if(opt_display)
273  {
274  switch (opt_dtype)
275  {
276  case vpX11:
277  std::cout << "Requested X11 display functionnalities..." << std::endl;
278 #if defined VISP_HAVE_X11
279  display1 = new vpDisplayX;
280  display2 = new vpDisplayX;
281 #else
282  std::cout << " Sorry, X11 video device is not available.\n";
283  std::cout << "Use \"" << argv[0] << " -l\" to print the list of available devices.\n";
284  return 0;
285 #endif
286  break;
287  case vpGTK:
288  std::cout << "Requested GTK display functionnalities..." << std::endl;
289 #if defined VISP_HAVE_GTK
290  display1 = new vpDisplayGTK;
291  display2 = new vpDisplayGTK;
292 #else
293  std::cout << " Sorry, GTK video device is not available.\n";
294  std::cout << "Use \"" << argv[0] << " -l\" to print the list of available devices.\n";
295  return 0;
296 #endif
297  break;
298  case vpGDI:
299  std::cout << "Requested GDI display functionnalities..." << std::endl;
300 #if defined VISP_HAVE_GDI
301  display1 = new vpDisplayGDI;
302  display2 = new vpDisplayGDI;
303 #else
304  std::cout << " Sorry, GDI video device is not available.\n";
305  std::cout << "Use \"" << argv[0] << " -l\" to print the list of available devices.\n";
306  return 0;
307 #endif
308  break;
309  case vpD3D:
310  std::cout << "Requested D3D display functionnalities..." << std::endl;
311 #if defined VISP_HAVE_D3D9
312  display1 = new vpDisplayD3D;
313  display2 = new vpDisplayD3D;
314 #else
315  std::cout << " Sorry, D3D video device is not available.\n";
316  std::cout << "Use \"" << argv[0] << " -l\" to print the list of available devices.\n";
317  return 0;
318 #endif
319  break;
320  case vpCV:
321  std::cout << "Requested OpenCV display functionnalities..." << std::endl;
322 #if defined(VISP_HAVE_OPENCV)
323  display1 = new vpDisplayOpenCV;
324  display2 = new vpDisplayOpenCV;
325 #else
326  std::cout << " Sorry, OpenCV video device is not available.\n";
327  std::cout << "Use \"" << argv[0] << " -l\" to print the list of available devices.\n";
328  return 0;
329 #endif
330  break;
331  }
332  }
333 
334  std::cout << "Start test testUsTissueTranslationEstimatorUKF" << std::endl;
335 
336  const int nbNeedles = 6;
337 
338  if(opt_display)
339  {
340  display1->init(I1, 0,0, "XZ");
341  display2->init(I2, display1->getWindowXPosition()+display1->getWidth(), display1->getWindowYPosition(), "YZ");
342 
343 #if defined(VISP_HAVE_DISPLAY)
344  statePlot = new vpPlot;
345  statePlot->init(4);
346  for(int i=0 ; i<4 ; i++) statePlot->initGraph(i,1+nbNeedles);
347  statePlot->setTitle(0, "Tissue position X");
348  statePlot->setTitle(1, "Tissue position Y");
349  statePlot->setTitle(2, "Tissue velocity X");
350  statePlot->setTitle(3, "Tissue velocity Y");
351  statePlot->setLegend(0,0, "Ref");
352  for(int i=0 ; i<nbNeedles ; i++) statePlot->setLegend(0,i+1,[i](){std::ostringstream t;t<<i;return t.str();}());
353 #endif
354  }
355 
358 
360  for(int i = 0 ; i<nbNeedles ; i++) needle[i].loadPreset(usNeedleInsertionModelRayleighRitzSpline::ModelPreset::BiopsyNeedle);
361 
363  for(int i = 0 ; i<nbNeedles ; i++) needle[i].setPathUpdateType(usNeedleInsertionModelRayleighRitzSpline::PathUpdateType::WithTipPosition);
364 
365  needleRef.setStiffnessPerUnitLength(10000);
366  for(int i = 0 ; i<nbNeedles ; i++) needle[i].setStiffnessPerUnitLength(10000);
367 
368  vpPoseVector needleInitialBasePose(0,0,-0.08, 0, 0, 0);
369  needleRef.setBasePose(needleInitialBasePose);
370  for(int i = 0 ; i<nbNeedles ; i++) needle[i].setBasePose(needleInitialBasePose);
371 
372  needleRef.setSurfaceAtTip();
373  for(int i = 0 ; i<nbNeedles ; i++) needle[i].setSurfaceAtTip();
374 
375  double std_measure_position = 1e-3;
376  double std_measure_tip_direction = 1e-3;
377  double std_measure_force = 1e-3;
378  double std_measure_torque = 1e-3;
379  double std_process_position_only = 1e-3;
380  double std_process_position = 1e-6;
381  double std_process_velocity = 1e-4;
382 
383  usTissueTranslationEstimatorUKF Kalman[nbNeedles];
384  for(int i=0 ; i<nbNeedles ; i++)
385  {
386  Kalman[i].setPositionMeasureNoiseVariance(std_measure_position*std_measure_position);
387  Kalman[i].setTipDirectionMeasureNoiseVariance(std_measure_tip_direction*std_measure_tip_direction);
388  Kalman[i].setForceMeasureNoiseVariance(std_measure_force*std_measure_force);
389  Kalman[i].setTorqueMeasureNoiseVariance(std_measure_torque*std_measure_torque);
390 
393 
395  Kalman[i].setSigmaPointScalingFactor(1e-2);
396  Kalman[i].setSigmaPointSpreadThreshold(0.0001);
397 
399  }
400 
401  for(int i=0 ; i<nbNeedles/2 ; i++)
402  {
404  vpMatrix P(6,6,0);
405  P[0][0] = std_process_position*std_process_position;
406  P[1][1] = std_process_position*std_process_position;
407  P[3][3] = std_process_velocity*std_process_velocity;
408  P[4][4] = std_process_velocity*std_process_velocity;
409  Kalman[i].setStateCovarianceMatrix(P);
410  Kalman[i].setTissuePositionProcessNoiseVariance(std_process_position*std_process_position);
411  Kalman[i].setTissueVelocityProcessNoiseVariance(std_process_velocity*std_process_velocity);
412 
414  P.resize(3,3);
415  P[0][0] = std_process_position_only*std_process_position_only;
416  P[1][1] = std_process_position_only*std_process_position_only;
417  Kalman[nbNeedles/2+i].setStateCovarianceMatrix(P);
418  Kalman[nbNeedles/2+i].setTissuePositionProcessNoiseVariance(std_process_position_only*std_process_position_only);
419  }
420 
421  for(int i=0 ; i<nbNeedles ; i+=3)
422  {
426  }
427 
428  double time = 0;
429  for(int i=0; i<50 ;i++)
430  {
431  for(int i=0 ; i<nbNeedles ; i++) Kalman[i].setCurrentNeedle(needle[i]);
432 
433  if(i<10)
434  {
435  vpColVector baseControl(6,0);
436  baseControl[2] = 0.005;
437  baseControl[1] = 0.0005;
438  needleRef.moveBase(baseControl, 1);
439  for(int i=0 ; i<nbNeedles ; i++) needle[i].moveBase(baseControl, 1);
440  }
441 
442  if(i<10)
443  {
444  needleRef.accessTissue().move(0.001,0,0,0,0,0);
445  needleRef.updateState();
446 #if defined(VISP_HAVE_DISPLAY)
447  if(opt_display)
448  {
449  statePlot->plot(2,0, time, 0.001);
450  statePlot->plot(3,0, time, 0);
451  }
452 #endif
453  }
454  else if(i<20)
455  {
456  needleRef.accessTissue().move(0,0.001,0,0,0,0);
457  needleRef.updateState();
458 #if defined(VISP_HAVE_DISPLAY)
459  if(opt_display)
460  {
461  statePlot->plot(2,0, time, 0);
462  statePlot->plot(3,0, time, 0.001);
463  }
464 #endif
465  }
466  else if(i<30)
467  {
468  needleRef.accessTissue().move(-0.002,0,0,0,0,0);
469  needleRef.updateState();
470 #if defined(VISP_HAVE_DISPLAY)
471  if(opt_display)
472  {
473  statePlot->plot(2,0, time, -0.002);
474  statePlot->plot(3,0, time, 0);
475  }
476 #endif
477  }
478  else if(i<40)
479  {
480  needleRef.accessTissue().move(0,-0.002,0,0,0,0);
481  needleRef.updateState();
482 #if defined(VISP_HAVE_DISPLAY)
483  if(opt_display)
484  {
485  statePlot->plot(2,0, time, 0);
486  statePlot->plot(3,0, time, -0.002);
487  }
488 #endif
489  }
490  else
491  {
492  needleRef.accessTissue().move(0.001,0.001,0,0,0,0);
493  needleRef.updateState();
494 #if defined(VISP_HAVE_DISPLAY)
495  if(opt_display)
496  {
497  statePlot->plot(2,0, time, 0.001);
498  statePlot->plot(3,0, time, 0.001);
499  }
500 #endif
501  }
502 
503 #if defined(VISP_HAVE_DISPLAY)
504  if(opt_display)
505  {
506  statePlot->plot(0,0, time, needleRef.accessTissue().getPose()[0]);
507  statePlot->plot(1,0, time, needleRef.accessTissue().getPose()[1]);
508  }
509 #endif
510 
511  int nbObs = floor(needleRef.getInsertionDepth()/0.005) + 2;
512  double step = needleRef.getInsertionDepth()/(nbObs-1);
513  vpColVector CP(3*nbObs);
514 
515  for(int j=0 ; j<nbObs ; j++)
516  {
517  vpColVector p = needleRef.accessNeedle().getNeedlePoint(needleRef.accessNeedle().getParametricLength()-j*step);
518  CP.insert(3*j, p);
519  }
520 
521  vpColVector tipMeasures(6);
522  tipMeasures.insert(0, needleRef.accessNeedle().getTipPosition());
523  tipMeasures.insert(3, needleRef.accessNeedle().getTipDirection());
524 
525  vpColVector baseForceMeasures(needleRef.accessNeedle().getBaseStaticTorsor());
526 
527  for(int i=0 ; i<nbNeedles ; i++) Kalman[i].setPropagationTime(1.);
528 
529  for(int i=0 ; i<nbNeedles ; i+=3)
530  {
531  Kalman[i].filter(CP);
532  Kalman[i+1].filter(tipMeasures);
533  Kalman[i+2].filter(baseForceMeasures);
534  }
535 
536  for(int i=0 ; i<nbNeedles ; i++)
537  {
538  Kalman[i].applyStateToNeedle(needle[i]);
539  needle[i].updateState();
540  }
541 
542  if(opt_display)
543  {
544  vpDisplay::display(I1);
545  vpDisplay::display(I2);
546  usNeedleModelingDisplayTools::display(needleRef, I1, vpHomogeneousMatrix(0.08, 0.1, 0.2, -M_PI / 2, 0, 0), 3000, 3000);
547  usNeedleModelingDisplayTools::display(needleRef, I2, vpHomogeneousMatrix(0.08, 0.1, 0.2, -2*M_PI / (3*sqrt(3)), 2*M_PI / (3*sqrt(3)), 2*M_PI / (3*sqrt(3))), 3000, 3000);
548  for(int i=0 ; i<nbNeedles ; i++)
549  {
550  usNeedleModelingDisplayTools::display(needle[i], I1, vpHomogeneousMatrix(0.08, 0.1, 0.2, -M_PI / 2, 0, 0), 3000, 3000);
551  usNeedleModelingDisplayTools::display(needle[i], I2, vpHomogeneousMatrix(0.08, 0.1, 0.2, -2*M_PI / (3*sqrt(3)), 2*M_PI / (3*sqrt(3)), 2*M_PI / (3*sqrt(3))), 3000, 3000);
552 #if defined(VISP_HAVE_DISPLAY)
553  statePlot->plot(0,1+i, time, needle[i].accessTissue().getPose()[0]);
554  statePlot->plot(1,1+i, time, needle[i].accessTissue().getPose()[1]);
555 #endif
556  }
557 #if defined(VISP_HAVE_DISPLAY)
558  for(int i=0 ; i<nbNeedles/2 ; i++)
559  {
560  statePlot->plot(2,1+i, time, Kalman[i].getState()[3]);
561  statePlot->plot(3,1+i, time, Kalman[i].getState()[4]);
562  }
563 #endif
564  vpDisplay::flush(I1);
565  vpDisplay::flush(I2);
566  }
567  time += 1;
568  }
569 
570  if (display1) delete display1;
571  if (display2) delete display2;
572 #if defined(VISP_HAVE_DISPLAY)
573  if (statePlot) delete statePlot;
574 #endif
575 
576  return 0;
577 }
double getParametricLength() const
Definition: usBSpline3D.cpp:61
bool moveBase(const vpColVector &v, double time)
void loadPreset(const ModelPreset preset)
Parameters saving and loading.
bool setBasePose(const vpPoseVector &p)
The following methods should be redefined in the derived classes.
const usTissueModelSpline & accessTissue() const
Tissue parameters.
const usNeedleModelSpline & accessNeedle() const
Parameters setters and getters.
vpColVector getTipDirection() const
vpColVector getTipPosition() const
vpColVector getBaseStaticTorsor() const
Force at base.
vpColVector getNeedlePoint(double l) const
Measure model information.
vpPoseVector getPose() const
bool move(const vpHomogeneousMatrix &H)
void applyStateToNeedle(usNeedleInsertionModelRayleighRitzSpline &needle) const
void setTissueTranslationType(TissueTranslationType type)
void setSigmaPointSpreadThreshold(double threshold)
void setProcessNoiseType(NoiseType type)
void setStateCovarianceMatrix(const vpMatrix &mat)
void setMeasureNoiseType(NoiseType type)
bool filter(const vpColVector &measure)
void setSigmaPointScalingFactor(double factor)
void setSigmaPointGenerationType(SigmaPointGenerationType type)
VISP_EXPORT void display(const usOrientedPlane3D &plane, const vpImage< ImageDataType > &I, const vpHomogeneousMatrix &imageMworld, double Xscale=3000, double Yscale=3000, const vpColor &color=vpColor::green)
Display usOrientedPlane3D.
VISP_EXPORT void display(const usNeedleModelBaseTip &needleModel, vpImage< unsigned char > &I, const vpHomogeneousMatrix &imageMworld, double Xscale=3000, double Yscale=3000)