Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
vpTemplateTrackerMIESM.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Example of template tracking.
33  *
34  * Authors:
35  * Amaury Dame
36  * Aurelien Yol
37  *
38 *****************************************************************************/
39 
40 #include <visp3/tt_mi/vpTemplateTrackerMIESM.h>
41 
42 #ifdef VISP_HAVE_OPENMP
43 #include <omp.h>
44 #endif
45 
46 BEGIN_VISP_NAMESPACE
48  : vpTemplateTrackerMI(_warp), minimizationMethod(USE_NEWTON), CompoInitialised(false), HDirect(), HInverse(),
49  HdesireDirect(), HdesireInverse(), GDirect(), GInverse()
50 {
51  useCompositionnal = false;
52  useInverse = false;
53  if (!Warp->isESMcompatible()) {
54  throw(vpException(vpException::badValue, "The selected warp function is not appropriate for the ESM algorithm..."));
55  }
56 }
57 
59 {
61 
62  dW = 0;
63 
64  int Nbpoint = 0;
65 
66  double i2, j2;
67  double IW, dx, dy;
68  int i, j;
69  int cr, ct;
70  double er, et;
71 
72  Nbpoint = 0;
73 
74  if (blur)
76 
78 
79  vpColVector tptemp(nbParam);
80 
81  Warp->computeCoeff(p);
82  for (unsigned int point = 0; point < templateSize; point++) {
83  i = ptTemplate[point].y;
84  j = ptTemplate[point].x;
85  X1[0] = j;
86  X1[1] = i;
87 
88  Warp->computeDenom(X1, p);
89  Warp->warpX(X1, X2, p);
90 
91  j2 = X2[0];
92  i2 = X2[1];
93 
94  if ((i2 >= 0) && (j2 >= 0) && (i2 < I.getHeight() - 1) && (j2 < I.getWidth() - 1)) {
95  Nbpoint++;
96 
97  if (blur)
98  IW = BI.getValue(i2, j2);
99  else
100  IW = I.getValue(i2, j2);
101 
102  ct = ptTemplateSupp[point].ct;
103  et = ptTemplateSupp[point].et;
104  cr = static_cast<int>((IW * (Nc - 1)) / 255.);
105  er = (IW * (Nc - 1)) / 255. - cr;
106 
107  vpTemplateTrackerMIBSpline::computeProbabilities(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam,
108  bspline, ApproxHessian, false);
109  }
110  }
111 
112  double MI;
113  computeProba(Nbpoint);
114  computeMI(MI);
116 
124  }
125 
126  Nbpoint = 0;
128 
129  Warp->computeCoeff(p);
130  for (unsigned int point = 0; point < templateSize; point++) {
131  i = ptTemplate[point].y;
132  j = ptTemplate[point].x;
133  X1[0] = j;
134  X1[1] = i;
135 
136  Warp->computeDenom(X1, p);
137  Warp->warpX(X1, X2, p);
138 
139  j2 = X2[0];
140  i2 = X2[1];
141 
142  if ((i2 >= 0) && (j2 >= 0) && (i2 < I.getHeight()) && (j2 < I.getWidth())) {
143  Nbpoint++;
144 
145  if (!blur)
146  IW = I.getValue(i2, j2);
147  else
148  IW = BI.getValue(i2, j2);
149 
150  dx = dIx.getValue(i2, j2) * (Nc - 1) / 255.;
151  dy = dIy.getValue(i2, j2) * (Nc - 1) / 255.;
152 
153  cr = ptTemplateSupp[point].ct;
154  er = ptTemplateSupp[point].et;
155  ct = static_cast<int>((IW * (Nc - 1)) / 255.);
156  et = (IW * (Nc - 1)) / 255. - ct;
157 
158  Warp->dWarpCompo(X1, X2, p, ptTemplateCompo[point].dW, dW);
159 
160  for (unsigned int it = 0; it < nbParam; it++)
161  tptemp[it] = dW[0][it] * dx + dW[1][it] * dy;
162 
163  vpTemplateTrackerMIBSpline::computeProbabilities(PrtTout, cr, er, ct, et, Nc, tptemp.data, nbParam, bspline,
164  ApproxHessian, false);
165  }
166  }
167 
168  computeProba(Nbpoint);
169  computeMI(MI);
171 
172  lambda = lambdaDep;
173 
175 
177 
179 }
180 
182 {
189 
190  ptTemplateSupp = new vpTemplateTrackerPointSuppMIInv[templateSize];
192  for (unsigned int point = 0; point < templateSize; point++) {
193  int i = ptTemplate[point].y;
194  int j = ptTemplate[point].x;
195  X1[0] = j;
196  X1[1] = i;
197  Warp->computeDenom(X1, p);
198 
199  ptTemplateCompo[point].dW = new double[2 * nbParam];
200  Warp->getdWdp0(i, j, ptTemplateCompo[point].dW);
201 
202  ptTemplate[point].dW = new double[nbParam];
203  double dx = ptTemplate[point].dx * (Nc - 1) / 255.;
204  double dy = ptTemplate[point].dy * (Nc - 1) / 255.;
205  Warp->getdW0(i, j, dy, dx, ptTemplate[point].dW);
206 
207  double Tij = ptTemplate[point].val;
208  int ct = static_cast<int>((Tij * (Nc - 1)) / 255.);
209  double et = (Tij * (Nc - 1)) / 255. - ct;
210  ptTemplateSupp[point].et = et;
211  ptTemplateSupp[point].ct = ct;
212  ptTemplateSupp[point].Bt = new double[4];
213  ptTemplateSupp[point].dBt = new double[4];
214  for (char it = -1; it <= 2; it++) {
215  ptTemplateSupp[point].Bt[it + 1] = vpTemplateTrackerBSpline::Bspline4(-it + et);
216  ptTemplateSupp[point].dBt[it + 1] = vpTemplateTrackerMIBSpline::dBspline4(-it + et);
217  }
218  }
219  CompoInitialised = true;
220 }
221 
223 {
224  if (!CompoInitialised) {
225  std::cout << "Compositionnal tracking not initialised.\nUse initCompInverse() function." << std::endl;
226  }
227  dW = 0;
228 
229  if (blur)
233 
234  int point;
235 
236  MI_preEstimation = -getCost(I, p);
237 
238  lambda = lambdaDep;
239 
240  double i2, j2;
241  double IW;
242  int cr, ct;
243  double er, et;
244 
245  vpColVector dpinv(nbParam);
246 
247  double alpha = 2.;
248 
249  int i, j;
250  unsigned int iteration = 0;
251  vpColVector tptemp(nbParam);
252 
253  do {
254  int Nbpoint = 0;
255  double MI = 0;
256 
258 
260  // Inverse
261  Warp->computeCoeff(p);
262  for (point = 0; point < static_cast<int>(templateSize); point++) {
263  i = ptTemplate[point].y;
264  j = ptTemplate[point].x;
265  X1[0] = j;
266  X1[1] = i;
267 
268  Warp->computeDenom(X1, p);
269  Warp->warpX(X1, X2, p);
270 
271  j2 = X2[0];
272  i2 = X2[1];
273 
274  if ((i2 >= 0) && (j2 >= 0) && (i2 < I.getHeight() - 1) && (j2 < I.getWidth() - 1)) {
275  Nbpoint++;
276 
277  if (!blur)
278  IW = I.getValue(i2, j2);
279  else
280  IW = BI.getValue(i2, j2);
281 
282  ct = ptTemplateSupp[point].ct;
283  et = ptTemplateSupp[point].et;
284  cr = static_cast<int>((IW * (Nc - 1)) / 255.);
285  er = (IW * (Nc - 1)) / 255. - cr;
286 
287  vpTemplateTrackerMIBSpline::computeProbabilities(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam,
290  }
291  }
292 
293  if (Nbpoint == 0) {
294  diverge = true;
295  MI = 0;
296  throw(vpTrackingException(vpTrackingException::notEnoughPointError, "No points in the template"));
297  }
298  else {
299  computeProba(Nbpoint);
300  computeMI(MI);
303  }
304  computeGradient();
305  GInverse = G;
306 
308  // DIRECT
309 
310  Nbpoint = 0;
311  MI = 0;
312 
314 
315  Warp->computeCoeff(p);
316 #ifdef VISP_HAVE_OPENMP
317  int nthreads = omp_get_num_procs();
318  // std::cout << "file: " __FILE__ << " line: " << __LINE__ << "
319  // function: " << __FUNCTION__ << " nthread: " << nthreads << std::endl;
320  omp_set_num_threads(nthreads);
321 #pragma omp parallel for private(i, j, i2, j2) default(shared)
322 #endif
323  for (point = 0; point < static_cast<int>(templateSize); point++) {
324  i = ptTemplate[point].y;
325  j = ptTemplate[point].x;
326  X1[0] = j;
327  X1[1] = i;
328  Warp->computeDenom(X1, p);
329  Warp->warpX(i, j, i2, j2, p);
330  X2[0] = j2;
331  X2[1] = i2;
332 
333  if ((i2 >= 0) && (j2 >= 0) && (i2 < I.getHeight() - 1) && (j2 < I.getWidth() - 1)) {
334  Nbpoint++;
335 
336  if (!blur)
337  IW = I.getValue(i2, j2);
338  else
339  IW = BI.getValue(i2, j2);
340 
341  double dx = dIx.getValue(i2, j2) * (Nc - 1) / 255.;
342  double dy = dIy.getValue(i2, j2) * (Nc - 1) / 255.;
343 
344  ct = static_cast<int>((IW * (Nc - 1)) / 255.);
345  et = (IW * (Nc - 1)) / 255. - ct;
346  cr = ptTemplateSupp[point].ct;
347  er = ptTemplateSupp[point].et;
348  Warp->dWarpCompo(X1, X2, p, ptTemplateCompo[point].dW, dW);
349 
350  for (unsigned int it = 0; it < nbParam; it++)
351  tptemp[it] = dW[0][it] * dx + dW[1][it] * dy;
352 
353  vpTemplateTrackerMIBSpline::computeProbabilities(PrtTout, cr, er, ct, et, Nc, tptemp.data, nbParam, bspline,
355  }
356  }
357 
358  computeProba(Nbpoint);
359  computeMI(MI);
362  computeGradient();
363  GDirect = G;
364 
366  H = HDirect + HInverse;
368  }
369  G = GDirect - GInverse;
370 
371  try {
373  dp = -gain * 0.3 * G;
374  else {
375  switch (hessianComputation) {
377  dp = gain * HLMdesireInverse * G;
378  break;
380  if (HLM.cond() > HLMdesire.cond()) {
381  dp = gain * HLMdesireInverse * G;
382  }
383  else {
384  dp = gain * 0.3 * HLM.inverseByLU() * G;
385  }
386  break;
387  default:
388  dp = gain * 0.3 * HLM.inverseByLU() * G;
389  break;
390  }
391  }
392  }
393  catch (const vpException &e) {
394  throw(e);
395  }
396 
398  dp = -dp;
399 
400  if (useBrent) {
401  alpha = 2.;
402  computeOptimalBrentGain(I, p, -MI, dp, alpha);
403  dp = alpha * dp;
404  }
405  p += dp;
406 
407  iteration++;
408  }
409  } while ((iteration < iterationMax));
410 
411  MI_postEstimation = -getCost(I, p);
413  MI_postEstimation = -1;
414  }
415 
416  nbIteration = iteration;
417 }
418 END_VISP_NAMESPACE
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:148
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:362
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
void resize(unsigned int i, bool flagNullify=true)
Definition: vpColVector.h:1143
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:73
static void getGradX(const vpImage< unsigned char > &I, vpImage< FilterType > &dIx, const vpImage< bool > *p_mask=nullptr)
static void getGradXGauss2D(const vpImage< ImageType > &I, vpImage< FilterType > &dIx, const FilterType *gaussianKernel, const FilterType *gaussianDerivativeKernel, unsigned int size, const vpImage< bool > *p_mask=nullptr)
static void filter(const vpImage< ImageType > &I, vpImage< FilterType > &If, const vpArray2D< FilterType > &M, bool convolve=false, const vpImage< bool > *p_mask=nullptr)
static void getGradYGauss2D(const vpImage< ImageType > &I, vpImage< FilterType > &dIy, const FilterType *gaussianKernel, const FilterType *gaussianDerivativeKernel, unsigned int size, const vpImage< bool > *p_mask=nullptr)
static void getGradY(const vpImage< unsigned char > &I, vpImage< FilterType > &dIy, const vpImage< bool > *p_mask=nullptr)
unsigned int getWidth() const
Definition: vpImage.h:242
Type getValue(unsigned int i, unsigned int j) const
unsigned int getHeight() const
Definition: vpImage.h:181
double cond(double svThreshold=1e-6) const
Definition: vpMatrix.cpp:1810
vpMatrix inverseByLU() const
static void computeHLM(const vpMatrix &H, const double &alpha, vpMatrix &HLM)
Definition: vpMatrix.cpp:1873
void trackNoPyr(const vpImage< unsigned char > &I)
void initHessienDesired(const vpImage< unsigned char > &I)
vpMinimizationTypeMIESM minimizationMethod
vpTemplateTrackerMIESM()
Default constructor.
vpHessienApproximationType ApproxHessian
vpImage< double > d2Ix
vpHessienType hessianComputation
double getCost(const vpImage< unsigned char > &I, const vpColVector &tp) VP_OVERRIDE
void computeMI(double &MI)
void computeProba(int &nbpoint)
void computeHessien(vpMatrix &H)
vpImage< double > d2Ixy
vpImage< double > d2Iy
virtual void dWarpCompo(const vpColVector &X1, const vpColVector &X2, const vpColVector &p, const double *dwdp0, vpMatrix &dM)=0
virtual bool isESMcompatible() const =0
virtual void getdW0(const int &v, const int &u, const double &dv, const double &du, double *dIdW)=0
virtual void getdWdp0(const int &v, const int &u, double *dIdW)=0
virtual void warpX(const int &v1, const int &u1, double &v2, double &u2, const vpColVector &p)=0
vpImage< double > dIx
vpImage< double > dIy
void computeOptimalBrentGain(const vpImage< unsigned char > &I, vpColVector &tp, double tMI, vpColVector &direction, double &alpha)
unsigned int iterationMax
unsigned int nbIteration
vpTemplateTrackerPoint * ptTemplate
vpTemplateTrackerWarp * Warp
vpImage< double > BI
unsigned int templateSize
vpTemplateTrackerPointCompo * ptTemplateCompo
Error that can be emitted by the vpTracker class and its derivatives.
@ notEnoughPointError
Not enough point to track.