UsTK : Ultrasound ToolKit  version 2.0.1 under development (2024-05-16)
usTissueTranslationEstimatorUKF.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 
33 #include <visp3/ustk_needle_modeling/usTissueTranslationEstimatorUKF.h>
34 
35 #include <visp3/ustk_core/usGeometryTools.h>
36 
37 
40  m_var_measure_p(1e-3),
41  m_var_measure_d(1e-3),
42  m_var_measure_f(1e-3),
43  m_var_measure_t(1e-6),
44  m_var_process_p(1e-3),
45  m_var_process_v(0),
46  m_stateDynamicsType(usTissueTranslationEstimatorUKF::CONSTANT_POSITION),
47  m_tissueTranslationType(usTissueTranslationEstimatorUKF::LATERAL_TRANSLATIONS_ONLY),
48  m_measureType(usTissueTranslationEstimatorUKF::NEEDLE_BODY_POINTS),
49  m_propagationTime(0),
50  m_needle()
51 {
52  this->setStateDimension(3);
55 }
56 
58 {
59 
60 }
61 
63 {
64  return m_var_measure_p;
65 }
66 
68 {
69  if (sigma >= 0) m_var_measure_p = sigma;
70 }
71 
73 {
74  return m_var_measure_d;
75 }
76 
78 {
79  if (sigma >= 0) m_var_measure_d = sigma;
80 }
81 
83 {
84  return m_var_measure_f;
85 }
86 
88 {
89  if (sigma >= 0) m_var_measure_f = sigma;
90 }
91 
93 {
94  return m_var_measure_t;
95 }
96 
98 {
99  if (sigma >= 0) m_var_measure_t = sigma;
100 }
101 
103 {
104  return m_var_process_p;
105 }
106 
108 {
109  if (sigma >= 0) m_var_process_p = sigma;
110 }
111 
113 {
114  return m_var_process_v;
115 }
116 
118 {
119  if (sigma >= 0) m_var_process_v = sigma;
120 }
121 
123 {
124  return m_stateDynamicsType;
125 }
126 
128 {
129  m_stateDynamicsType = type;
130 
131  switch (type) {
133  {
134  this->setStateDimension(3);
135  break;
136  }
138  {
139  this->setStateDimension(6);
140  break;
141  }
142  }
143 }
144 
146 {
148 }
149 
151 {
153 }
154 
156 {
157  return m_measureType;
158 }
159 
161 {
162  m_measureType = type;
163 
165 }
166 
168 {
169  m_propagationTime = time;
170 }
171 
173 {
174  m_needle = needle;
175  m_state.insert(0, vpColVector(vpColVector(m_needle.accessTissue().getPose()), 0, 3));
176 }
177 
179 {
180  vpPoseVector p(needle.accessTissue().accessSurface().getPose());
181  for (int i = 0; i < 3; i++) p[i] = m_state[i];
182  needle.accessTissue().setPose(p);
183 }
184 
186 {
187  if (!m_needle.IsNeedleInserted()) return false;
188  if ((vpColVector(m_state, 0, 3) - vpColVector(vpColVector(m_needle.accessTissue().getPose()), 0, 3)).frobeniusNorm() > std::numeric_limits<double>::epsilon()) std::cout << "usTissueTranslationEstimatorUKF::checkConsistency: the state does not correspond to the needle model, make sure you used the method 'setCurrentNeedle' to initialize the state" << std::endl;
189 
191  if (measure.size() % 3 != 0) throw vpException(vpException::notInitialized, "usTissueTranslationEstimatorUKF::checkConsistency: measure is set as needle body points, but the mesure dimension is not a multiple of 3");
192  this->setMeasureDimension(measure.size());
193  this->setMeasureNoiseDimension(measure.size());
194  }
195 
196  return this->usUnscentedKalmanFilter::checkConsistency(measure);
197 }
198 
200 {
201  vpMatrix normalizedCovarianceMatrix;
202  normalizedCovarianceMatrix.eye(3);
203 
205  vpColVector d_ins = m_needle.accessTissue().accessSurface().getDirection().normalize();
206  normalizedCovarianceMatrix = normalizedCovarianceMatrix - d_ins * d_ins.t();
207  }
208 
209  switch (m_stateDynamicsType) {
211  {
212  m_processNoiseCovarianceMatrix.resize(3, 3);
213  m_processNoiseCovarianceMatrix = m_var_process_p * normalizedCovarianceMatrix;
214  break;
215  }
217  {
218  m_processNoiseCovarianceMatrix.resize(6, 6);
219  m_processNoiseCovarianceMatrix.insert(m_var_process_p * normalizedCovarianceMatrix, 0, 0);
220  m_processNoiseCovarianceMatrix.insert(m_var_process_v * normalizedCovarianceMatrix, 3, 3);
221  break;
222  }
223  }
224 }
225 
227 {
228  switch (m_measureType) {
230  {
233  break;
234  }
236  {
237  m_measureNoiseCovarianceMatrix.resize(6, 6);
238  for (int i = 0; i < 3; i++) {
241  }
242  break;
243  }
245  {
246  m_measureNoiseCovarianceMatrix.resize(6, 6);
247  for (int i = 0; i < 3; i++) {
250  }
251  break;
252  }
253  }
254 }
255 
256 vpColVector usTissueTranslationEstimatorUKF::propagateSigmaPoint(const vpColVector &sigmaPoint)
257 {
258  switch (m_stateDynamicsType) {
260  {
261  return sigmaPoint;
262  }
264  {
265  vpColVector propagatedSigmaPoint(sigmaPoint);
266  for (int i = 0; i < 3; i++) propagatedSigmaPoint[i] += m_propagationTime * propagatedSigmaPoint[i + 3];
267  return propagatedSigmaPoint;
268  }
269  default:
270  {
271  return sigmaPoint;
272  }
273  }
274 }
275 
276 vpColVector usTissueTranslationEstimatorUKF::computeMeasureFromSigmaPoint(const vpColVector &sigmaPoint)
277 {
278  switch (m_measureType) {
280  {
281  int nbPoints = m_measure.size() / 3;
282 
284 
285  std::vector<int> index(nbPoints);
286  std::vector<double> l(nbPoints);
287  for (int i = 0; i < nbPoints; i++) {
288  usGeometryTools::projectPointOnCurve(vpColVector(m_measure, 3 * i, 3), testNeedle.accessNeedle(), -1, &(index.at(i)), &(l.at(i)));
289  }
290 
291  vpPoseVector p(testNeedle.accessTissue().getPose());
292  testNeedle.accessTissue().setPose(vpPoseVector(sigmaPoint[0], sigmaPoint[1], sigmaPoint[2], p[3], p[4], p[5]));
293  testNeedle.updateState();
294 
295  vpColVector measure(m_measure.size());
296  for (int i = 0; i < nbPoints; i++) measure.insert(3 * i, testNeedle.accessNeedle().accessSegment(index.at(i)).getPoint(l.at(i)));
297 
298  return measure;
299  }
301  {
303 
304  vpPoseVector p(testNeedle.accessTissue().getPose());
305  testNeedle.accessTissue().setPose(vpPoseVector(sigmaPoint[0], sigmaPoint[1], sigmaPoint[2], p[3], p[4], p[5]));
306  testNeedle.updateState();
307 
308  vpColVector measure(6);
309  measure.insert(0, testNeedle.accessNeedle().getTipPosition());
310  measure.insert(3, testNeedle.accessNeedle().getTipDirection());
311 
312  return measure;
313  }
315  {
317 
318  vpPoseVector p(testNeedle.accessTissue().getPose());
319  testNeedle.accessTissue().setPose(vpPoseVector(sigmaPoint[0], sigmaPoint[1], sigmaPoint[2], p[3], p[4], p[5]));
320  testNeedle.updateState();
321 
322  vpColVector measure(testNeedle.accessNeedle().getBaseStaticTorsor());
323 
324  return measure;
325  }
326  default:
327  {
328  throw vpException(vpException::notImplementedError, "usTissueTranslationEstimatorUKF::computeMeasureFromSigmaPoint: measure type not implemented");
329  }
330  }
331 }
332 
333 double usTissueTranslationEstimatorUKF::stateNorm(const vpColVector &state) const
334 {
335  switch (m_stateDynamicsType) {
337  {
338  return vpColVector(state, 0, 3).frobeniusNorm();
339  }
341  {
342  return vpColVector(state, 0, 3).frobeniusNorm() + m_propagationTime * vpColVector(state, 3, 3).frobeniusNorm();
343  }
344  default:
345  {
346  return state.frobeniusNorm();
347  }
348  }
349 }
350 
351 vpColVector usTissueTranslationEstimatorUKF::measureLog(const vpColVector &measure, const vpColVector &measureCenter) const
352 {
353  switch (m_measureType) {
355  {
356  return measure;
357  }
359  {
360  vpColVector measureL(6);
361  for (int i = 0; i < 3; i++) measureL[i] = measure[i];
362 
363  vpColVector d_init(measureCenter, 3, 3);
364  vpColVector d(measure, 3, 3);
365  double angle = fabs(atan2(vpColVector::crossProd(d_init, d).frobeniusNorm(), vpColVector::dotProd(d_init, d)));
366  measureL.insert(3, angle * vpColVector::crossProd(d_init, d).normalize());
367 
368  return measureL;
369  }
371  {
372  return measure;
373  }
374  default:
375  {
376  return measure;
377  }
378  }
379 }
const usPolynomialCurve3D & accessSegment(int i) const
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 getDirection() const
vpPoseVector getPose() const
vpColVector getPoint(double parameter) const
bool setPose(const vpPoseVector &p)
vpPoseVector getPose() const
const usOrientedPlane3D & accessSurface() const
Parameters setters and getters.
vpColVector propagateSigmaPoint(const vpColVector &sigmaPoint)
vpColVector measureLog(const vpColVector &measure, const vpColVector &measureCenter) const
usNeedleInsertionModelRayleighRitzSpline m_needle
vpColVector computeMeasureFromSigmaPoint(const vpColVector &sigmaPoint)
void setCurrentNeedle(const usNeedleInsertionModelRayleighRitzSpline &needle)
void applyStateToNeedle(usNeedleInsertionModelRayleighRitzSpline &needle) const
bool checkConsistency(const vpColVector &measure)
void setTissueTranslationType(TissueTranslationType type)
double stateNorm(const vpColVector &state) const
TissueTranslationType getTissueTranslationType() const
virtual bool checkConsistency(const vpColVector &measure)
VISP_EXPORT vpColVector projectPointOnCurve(const vpColVector &point, const usPolynomialCurve3D &poly, double threshold=-1, double *t=nullptr)