Visual Servoing Platform  version 3.0.0
vpTemplateTrackerMIInverseCompositional.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2015 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 ViSP 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  * See http://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Example of template tracking.
32  *
33  * Authors:
34  * Amaury Dame
35  * Aurelien Yol
36  * Fabien Spindler
37  *
38  *****************************************************************************/
39 #include <visp3/tt_mi/vpTemplateTrackerMIInverseCompositional.h>
40 #include <visp3/core/vpTrackingException.h>
41 
42 #include <memory>
43 
45  : vpTemplateTrackerMI(_warp), minimizationMethod(USE_LMA), CompoInitialised(false), useTemplateSelect(false),
46  evolRMS(0), x_pos(NULL), y_pos(NULL), threshold_RMS(1e-20), p_prec(), G_prec(), KQuasiNewton() //, useAYOptim(false)
47 {
48  useInverse=true;
49 }
50 
51 void vpTemplateTrackerMIInverseCompositional::initTemplateRefBspline(unsigned int ptIndex, double &et) //AY : Optim
52 {
53  ptTemplateSupp[ptIndex].BtInit=new double[(1 + nbParam + nbParam*nbParam)*(unsigned int)bspline];
54 
55  unsigned int index = 0;
56  int endIndex = 1;
57 
58  double (*ptBspFct)(double);
59  double (*ptdBspFct)(double);
60  double (*ptd2BspFct)(double);
61  if(bspline == 3){
62  if(et>0.5){et=et-1;}
63  ptBspFct = &vpTemplateTrackerMIBSpline::Bspline3;
64  ptdBspFct = &vpTemplateTrackerMIBSpline::dBspline3;
65  ptd2BspFct = &vpTemplateTrackerMIBSpline::d2Bspline3;
66  }
67  else{
68  ptBspFct = &vpTemplateTrackerBSpline::Bspline4;
69  ptdBspFct = &vpTemplateTrackerMIBSpline::dBspline4;
70  ptd2BspFct = &vpTemplateTrackerMIBSpline::d2Bspline4;
71  endIndex = 2;
72  }
73 
74  for(int it=-1; it<=endIndex; it++)
75  {
76  ptTemplateSupp[ptIndex].BtInit[index++] = (*ptBspFct)((double)(-it)+et);
77 
78  for(unsigned int ip=0;ip<nbParam;++ip)
79  {
80  ptTemplateSupp[ptIndex].BtInit[index++] = (*ptdBspFct)((double)(-it)+et) * ptTemplate[ptIndex].dW[ip] * (-1.0);
81  for(unsigned int ip2=0;ip2<nbParam;++ip2)
82  {
83  ptTemplateSupp[ptIndex].BtInit[index++] = (*ptd2BspFct)((double)(-it)+et) * ptTemplate[ptIndex].dW[ip] * ptTemplate[ptIndex].dW[ip2];
84  }
85  }
86  }
87 }
88 
90 {
91  ptTemplateSupp=new vpTemplateTrackerPointSuppMIInv[templateSize];
92  int i,j;
93  double et;
94  int ct;
95  double Tij;
96 
99 
101  {
105  }
106 
107  Warp->computeCoeff(p);
108  for(unsigned int point=0;point<templateSize;point++)
109  {
110  i=ptTemplate[point].y;
111  j=ptTemplate[point].x;
112 
113  X1[0]=j;X1[1]=i;
114 
115  Warp->computeDenom(X1,p);
116  ptTemplate[point].dW=new double[nbParam];
117 
118  double dx=ptTemplate[point].dx*(Nc-1)/255.;
119  double dy=ptTemplate[point].dy*(Nc-1)/255.;
120 
121  Warp->getdW0(i,j,dy,dx,ptTemplate[point].dW);
122  Tij=ptTemplate[point].val;
123  ct=(int)((Tij*(Nc-1))/255.);
124  et=(Tij*(Nc-1))/255.-ct;
125 
126  ptTemplateSupp[point].et=et;
127  ptTemplateSupp[point].ct=ct;
128 
129  // ###### AY Optim
130  // if(useAYOptim)
131  // if(ApproxHessian != HESSIAN_NONSECOND /*&& hessianComputation != vpTemplateTrackerMI::USE_HESSIEN_DESIRE*/)
132  // initTemplateRefBspline(point, et);
133  // ###################
134  }
135  CompoInitialised=true;
136 
137 }
139 {
140  initCompInverse(I);
141 
142  double erreur=0;
143  int Nbpoint=0;
144 
145  double i2,j2;
146  double Tij;
147  double IW;
148  int cr,ct;
149  double er,et;
150 
151  int i,j;
152 
153  Nbpoint=0;
154  erreur=0;
155 
156  if(blur)
158 
160  Warp->computeCoeff(p);
161 
162  // AY : Optim
163  // unsigned int totParam = (bspline * bspline)*(1+nbParam+nbParam*nbParam);
164  // unsigned int size = (1 + nbParam + nbParam*nbParam)*bspline;
165  // double *ptb;
166 
167  for(unsigned int point=0;point<templateSize;point++)
168  {
169  i=ptTemplate[point].y;
170  j=ptTemplate[point].x;
171  X1[0]=j;X1[1]=i;
172 
173  Warp->computeDenom(X1,p);
174  Warp->warpX(X1,X2,p);
175 
176  j2=X2[0];i2=X2[1];
177 
178  if((i2>=0)&&(j2>=0)&&(i2<I.getHeight()-1)&&(j2<I.getWidth()-1))
179  {
180  Nbpoint++;
181  Tij=ptTemplate[point].val;
182 
183  if(blur)
184  IW=BI.getValue(i2,j2);
185  else
186  IW=I.getValue(i2,j2);
187 
188  ct=ptTemplateSupp[point].ct;
189  et=ptTemplateSupp[point].et;
190  cr=(int)((IW*(Nc-1))/255.);
191  er=((double)IW*(Nc-1))/255.-cr;
192 
193  //calcul de l'erreur
194  erreur+=(Tij-IW)*(Tij-IW);
195 
196  if( ApproxHessian==HESSIAN_NONSECOND && (ptTemplateSelect[point] || !useTemplateSelect) )
197  {
198  vpTemplateTrackerMIBSpline::PutTotPVBsplineNoSecond(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam, bspline);
199  }
200  else if ((ApproxHessian==HESSIAN_0||ApproxHessian==HESSIAN_NEW) && (ptTemplateSelect[point] || !useTemplateSelect))
201  {
202  if(bspline==3){
203  vpTemplateTrackerMIBSpline::PutTotPVBspline3(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam);
204  // {
205  // if(et>0.5){ct++;}
206  // if(er>0.5){cr++;}
207  // int index = (cr*Nc+ct)*totParam;
208  // double *ptb = &PrtTout[index];
209  // vpTemplateTrackerMIBSpline::PutTotPVBspline3(ptb, er, ptTemplateSupp[point].BtInit, size);
210  // }
211  }
212  else{
213  vpTemplateTrackerMIBSpline::PutTotPVBspline4(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam);
214 
215  // {
216  // // ################### AY : Optim
217  // unsigned int index = (cr*Nc+ct)*totParam;
218  // ptb = &PrtTout[index];
219  // vpTemplateTrackerMIBSpline::PutTotPVBspline4(ptb, er, ptTemplateSupp[point].BtInit, size);
220  // // ###################
221  // }
222  }
223  }
224  else if (ptTemplateSelect[point] || !useTemplateSelect)
225  vpTemplateTrackerMIBSpline::PutTotPVBsplinePrt(PrtTout, cr, er, ct, et, Nc,nbParam, bspline);
226  }
227  }
228 
229  double MI;
230  computeProba(Nbpoint);
231  computeMI(MI);
233 
235 
237 
239  KQuasiNewton=HLMdesireInverse;
240 }
241 
243 {
244  if(!CompoInitialised)
245  std::cout<<"Compositionnal tracking no initialised\nUse InitCompInverse(vpImage<unsigned char> &I) function"<<std::endl;
246  dW=0;
247 
248  if(blur)
250 
251  int Nbpoint=0;
252 
254  double MI=0,MIprec=-1000;
255 
256  vpColVector p_avant_estimation;p_avant_estimation=p;
259 
260  // std::cout << "MI avant: " << MI_preEstimation << std::endl;
261  // std::cout << "NMI avant: " << NMI_preEstimation << std::endl;
262 
263  initPosEvalRMS(p);
264 
265  vpColVector dpinv(nbParam);
266  double alpha=2.;
267 
268  unsigned int iteration=0;
269 
270  //unsigned int bspline_ = (unsigned int) bspline;
271  //unsigned int totParam = (bspline_ * bspline_)*(1+nbParam+nbParam*nbParam);
272 
273  vpMatrix Hnorm(nbParam,nbParam);
274 
275  do
276  {
277  Nbpoint=0;
278  MIprec=MI;
279  MI=0;
280 
282 
283  Warp->computeCoeff(p);
284 
285  {
286  for(int point=0;point<(int)templateSize;point++)
287  {
288  vpColVector x1(2),x2(2);
289  double i2,j2;
290  double IW;
291  int cr,ct;
292  double er,et;
293 
294  x1[0]=(double)ptTemplate[point].x;
295  x1[1]=(double)ptTemplate[point].y;
296 
297  Warp->computeDenom(x1,p); // A modif pour parallelisation mais ne pose pas de pb avec warp utilises dans DECSA
298  Warp->warpX(x1,x2,p);
299 
300  j2=x2[0];
301  i2=x2[1];
302 
303  if((i2>=0)&&(j2>=0)&&(i2<I.getHeight()-1)&&(j2<I.getWidth()-1))
304  {
305 
306  //if(m_ptCurrentMask == NULL ||(m_ptCurrentMask->getWidth() == I.getWidth() && m_ptCurrentMask->getHeight() == I.getHeight() && (*m_ptCurrentMask)[(unsigned int)i2][(unsigned int)j2] > 128))
307  {
308  Nbpoint++;
309  if(!blur)
310  IW=(double)I.getValue(i2,j2);
311  else
312  IW=BI.getValue(i2,j2);
313 
314  ct=ptTemplateSupp[point].ct;
315  et=ptTemplateSupp[point].et;
316  double tmp = IW*(((double)Nc)-1.f)/255.f;
317  cr=(int)tmp;
318  er=tmp-(double)cr;
319 
321  {
322  vpTemplateTrackerMIBSpline::PutTotPVBsplineNoSecond(Prt, dPrt, cr, er, ct, et, Ncb, ptTemplate[point].dW, nbParam, bspline);
323  }
324  else if (ptTemplateSelect[point] || !useTemplateSelect)
325  {
326  if(bspline==3){
327  vpTemplateTrackerMIBSpline::PutTotPVBspline3(Prt, dPrt, d2Prt, cr, er, ct, et, Ncb, ptTemplate[point].dW, nbParam);
328  }
329  else{
330  vpTemplateTrackerMIBSpline::PutTotPVBspline4(Prt, dPrt, d2Prt, cr, er, ct, et, Ncb, ptTemplate[point].dW, nbParam);
331  }
332  }
333  else{
334  vpTemplateTrackerMIBSpline::PutTotPVBsplinePrt(Prt, cr, er, ct, et, Ncb,nbParam, bspline);
335  }
336  }
337 
338  }
339  }
340  }
341 
342  if(Nbpoint==0)
343  {
344  diverge=true;
345  MI=0;
347  throw(vpTrackingException(vpTrackingException::notEnoughPointError, "No points in the template"));
348 
349  }
350  else
351  {
352  // computeProba(Nbpoint);
353 
354  unsigned int indd, indd2;
355  indd = indd2 = 0;
356  unsigned int Ncb_ = (unsigned int)Ncb;
357  for(unsigned int i=0;i<Ncb_*Ncb_;i++){
358  Prt[i]=Prt[i]/Nbpoint;
359  for(unsigned int j=0;j<nbParam;j++){
360  dPrt[indd]=dPrt[indd]/Nbpoint;
361  indd++;
362  for(unsigned int k=0;k<nbParam;k++){
363  d2Prt[indd2]=d2Prt[indd2]/Nbpoint;
364  indd2++;
365  }
366  }
367  }
368 
369  computeMI(MI);
370 
373  computeHessien(H);
374  }
375  computeGradient();
376 
378 
379  try
380  {
381  switch(hessianComputation)
382  {
385  break;
387  if(HLM.cond()>HLMdesire.cond())
389  else
390  dp=gain*0.2*HLM.inverseByLU()*G;
391  break;
392  default:
393  dp=gain*0.2*HLM.inverseByLU()*G;
394  break;
395  }
396  }
397  catch(vpException &e)
398  {
399  //std::cerr<<"probleme inversion"<<std::endl;
400  throw(e);
401  }
402  }
403 
404  switch(minimizationMethod)
405  {
407  {
408  vpColVector dp_test_LMA(nbParam);
409  vpColVector dpinv_test_LMA(nbParam);
410  vpColVector p_test_LMA(nbParam);
412  dp_test_LMA=-100000.1*dp;
413  else
414  dp_test_LMA=1.*dp;
415  Warp->getParamInverse(dp_test_LMA,dpinv_test_LMA);
416  Warp->pRondp(p,dpinv_test_LMA,p_test_LMA);
417 
418  MI=-getCost(I,p);
419  double MI_LMA=-getCost(I,p_test_LMA);
420  if(MI_LMA>MI)
421  {
422  dp=dp_test_LMA;
423  lambda=(lambda/10.<1e-6)?lambda/10.:1e-6;
424  }
425  else
426  {
427  dp=0;
428  lambda=(lambda*10.<1e6)?1e6:lambda*10.;
429  }
430  }
431  break;
433  dp=-gain*0.3*G*20;
434  break;
435 
437  {
438  double s_scal_y;
439  if(iterationGlobale!=0)
440  {
441  vpColVector s_quasi=p-p_prec;
442  vpColVector y_quasi=G-G_prec;
443  s_scal_y=s_quasi.t()*y_quasi;
444  //std::cout<<"mise a jour K"<<std::endl;
445  /*if(s_scal_y!=0)//BFGS
446  KQuasiNewton=KQuasiNewton+0.01*(-(s_quasi*y_quasi.t()*KQuasiNewton+KQuasiNewton*y_quasi*s_quasi.t())/s_scal_y+(1.+y_quasi.t()*(KQuasiNewton*y_quasi)/s_scal_y)*s_quasi*s_quasi.t()/s_scal_y);*/
447  //if(s_scal_y!=0)//DFP
448  if(std::fabs(s_scal_y) > std::numeric_limits<double>::epsilon())//DFP
449  {
450  KQuasiNewton=KQuasiNewton+0.0001*(s_quasi*s_quasi.t()/s_scal_y-KQuasiNewton*y_quasi*y_quasi.t()*KQuasiNewton/(y_quasi.t()*KQuasiNewton*y_quasi));
451  //std::cout<<"mise a jour K"<<std::endl;
452  }
453  }
454  dp=gain*KQuasiNewton*G;
455  //std::cout<<KQuasiNewton<<std::endl<<std::endl;
456  p_prec=p;
457  G_prec=G;
458  //p-=1.01*dp;
459  }
460  break;
461 
462  default:
463  {
464  if(useBrent)
465  {
466  alpha=2.;
467  computeOptimalBrentGain(I,p,-MI,dp,alpha);
468  dp=alpha*dp;
469  }
471  dp=-1.*dp;
472 
473  break;
474  }
475  }
476 
477  Warp->getParamInverse(dp,dpinv);
478  Warp->pRondp(p,dpinv,p);
479 
480  iteration++;
482 
483  computeEvalRMS(p);
484 
485  // std::cout << p.t() << std::endl;
486  }
487  while( (!diverge) && (std::fabs(MI-MIprec) > std::fabs(MI)*std::numeric_limits<double>::epsilon()) &&(iteration< iterationMax)&&(evolRMS>threshold_RMS) );
488  //while( (!diverge) && (MI!=MIprec) &&(iteration< iterationMax)&&(evolRMS>threshold_RMS) );
489 
490  nbIteration=iteration;
491 
492  if(diverge)
493  {
494  if(computeCovariance){
496  covarianceMatrix = -1;
497  MI_postEstimation = -1;
498  NMI_postEstimation = -1;
499  }
501 
502  // throw(vpTrackingException(vpTrackingException::badValue, "Tracking failed")) ;
503  }
504  else
505  {
508  // std::cout << "MI apres: " << MI_postEstimation << std::endl;
509  // std::cout << "NMI apres: " << NMI_postEstimation << std::endl;
511  {
512  p=p_avant_estimation;
516  covarianceMatrix = -1;
517  }
518 
520 
521  if(computeCovariance){
522  try{
523  covarianceMatrix = (-H).inverseByLU();
524  // covarianceMatrix = (-Hnorm).inverseByLU();
525  }
526  catch(...){
528  covarianceMatrix = -1;
529  MI_postEstimation = -1;
530  NMI_postEstimation = -1;
532  }
533  }
534  }
535 }
536 
538 {
539  unsigned int nb_corners = zoneTracked->getNbTriangle() * 3;
540  x_pos=new double[nb_corners];
541  y_pos=new double[nb_corners];
542 
543  Warp->computeCoeff(pw);
544  vpTemplateTrackerTriangle triangle;
545 
546  for(unsigned int i=0;i<zoneTracked->getNbTriangle();i++)
547  {
548  zoneTracked->getTriangle(i, triangle);
549  for (unsigned int j=0; j<3; j++) {
550  triangle.getCorner(j, X1[0], X1[1]);
551 
552  Warp->computeDenom(X1,pw);
553  Warp->warpX(X1,X2,p);
554  x_pos[i*3+j]=X2[0];
555  y_pos[i*3+j]=X2[1];
556  }
557  }
558 }
559 
561 {
562  unsigned int nb_corners = zoneTracked->getNbTriangle() * 3;
563 
564  Warp->computeCoeff(pw);
565  evolRMS=0;
566  vpTemplateTrackerTriangle triangle;
567 
568  for(unsigned int i=0;i<zoneTracked->getNbTriangle();i++)
569  {
570  zoneTracked->getTriangle(i, triangle);
571  for (unsigned int j=0; j<3; j++) {
572  triangle.getCorner(j, X1[0], X1[1]);
573 
574  Warp->computeDenom(X1,pw);
575  Warp->warpX(X1,X2,pw);
576  evolRMS+=(x_pos[i*3+j]-X2[0])*(x_pos[i*3+j]-X2[0])+(y_pos[i*3+j]-X2[1])*(y_pos[i*3+j]-X2[1]);
577  x_pos[i*3+j]=X2[0];
578  y_pos[i*3+j]=X2[1];
579  }
580  }
581  evolRMS=evolRMS/nb_corners;
582 }
583 
585 {
586  delete[] x_pos;
587  delete[] y_pos;
588 }
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:92
void initTemplateRefBspline(unsigned int ptIndex, double &et)
void computeHessien(vpMatrix &H)
void getTriangle(unsigned int i, vpTemplateTrackerTriangle &T) const
unsigned int getWidth() const
Definition: vpImage.h:161
static void getGradX(const vpImage< unsigned char > &I, vpImage< double > &dIx)
vpTemplateTrackerPoint * ptTemplate
static void getGradY(const vpImage< unsigned char > &I, vpImage< double > &dIy)
virtual void warpX(const int &i, const int &j, double &i2, double &j2, const vpColVector &ParamM)=0
void computeOptimalBrentGain(const vpImage< unsigned char > &I, vpColVector &tp, double tMI, vpColVector &direction, double &alpha)
error that can be emited by ViSP classes.
Definition: vpException.h:73
Type getValue(double i, double j) const
Definition: vpImage.h:1148
vpColVector getCorner(unsigned int i) const
static void getGradYGauss2D(const vpImage< unsigned char > &I, vpImage< double > &dIy, const double *gaussianKernel, const double *gaussianDerivativeKernel, unsigned int size)
static void getGradXGauss2D(const vpImage< unsigned char > &I, vpImage< double > &dIx, const double *gaussianKernel, const double *gaussianDerivativeKernel, unsigned int size)
vpImage< double > d2Ix
vpImage< double > BI
vpHessienApproximationType ApproxHessian
virtual void getParamInverse(const vpColVector &ParamM, vpColVector &ParamMinv) const =0
double cond() const
Definition: vpMatrix.cpp:3445
unsigned int templateSize
unsigned int iterationMax
virtual void pRondp(const vpColVector &p1, const vpColVector &p2, vpColVector &pres) const =0
Error that can be emited by the vpTracker class and its derivates.
double getCost(const vpImage< unsigned char > &I, const vpColVector &tp)
unsigned int getNbTriangle() const
static void filter(const vpImage< double > &I, vpImage< double > &Iu, vpImage< double > &Iv, const vpMatrix &M)
vpImage< double > dIx
void computeMI(double &MI)
vpRowVector t() const
vpImage< double > dIy
vpImage< double > d2Iy
unsigned int iterationGlobale
unsigned int getNbParam() const
virtual void getdW0(const int &i, const int &j, const double &dy, const double &dx, double *dIdW)=0
double getNormalizedCost(const vpImage< unsigned char > &I, const vpColVector &tp)
unsigned int nbIteration
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
vpImage< double > d2Ixy
vpMatrix inverseByLU() const
vpTemplateTrackerZone * zoneTracked
unsigned int getHeight() const
Definition: vpImage.h:152
void computeHessienNormalized(vpMatrix &H)
vpTemplateTrackerWarp * Warp
static void computeHLM(const vpMatrix &H, const double &alpha, vpMatrix &HLM)
Definition: vpMatrix.cpp:3470
void computeProba(int &nbpoint)
vpHessienType hessianComputation