Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
vpTemplateTrackerMIInverseCompositional.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 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 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 
95 
97  {
101  }
102 
103  Warp->computeCoeff(p);
104  for(unsigned int point=0;point<templateSize;point++)
105  {
106  int i=ptTemplate[point].y;
107  int j=ptTemplate[point].x;
108 
109  X1[0]=j;X1[1]=i;
110 
111  Warp->computeDenom(X1,p);
112  ptTemplate[point].dW=new double[nbParam];
113 
114  double dx=ptTemplate[point].dx*(Nc-1)/255.;
115  double dy=ptTemplate[point].dy*(Nc-1)/255.;
116 
117  Warp->getdW0(i,j,dy,dx,ptTemplate[point].dW);
118  double Tij=ptTemplate[point].val;
119  int ct=(int)((Tij*(Nc-1))/255.);
120  double et=(Tij*(Nc-1))/255.-ct;
121 
122  ptTemplateSupp[point].et=et;
123  ptTemplateSupp[point].ct=ct;
124 
125  // ###### AY Optim
126  // if(useAYOptim)
127  // if(ApproxHessian != HESSIAN_NONSECOND /*&& hessianComputation != vpTemplateTrackerMI::USE_HESSIEN_DESIRE*/)
128  // initTemplateRefBspline(point, et);
129  // ###################
130  }
131  CompoInitialised=true;
132 
133 }
135 {
136  initCompInverse(I);
137 
138  //double erreur=0;
139  int Nbpoint=0;
140 
141  //double Tij;
142  double IW;
143  int cr,ct;
144  double er,et;
145 
146  Nbpoint=0;
147  //erreur=0;
148 
149  if(blur)
151 
153  Warp->computeCoeff(p);
154 
155  // AY : Optim
156  // unsigned int totParam = (bspline * bspline)*(1+nbParam+nbParam*nbParam);
157  // unsigned int size = (1 + nbParam + nbParam*nbParam)*bspline;
158  // double *ptb;
159 
160  for(unsigned int point=0;point<templateSize;point++)
161  {
162  int i=ptTemplate[point].y;
163  int j=ptTemplate[point].x;
164  X1[0]=j;
165  X1[1]=i;
166 
167  Warp->computeDenom(X1,p);
168  Warp->warpX(X1,X2,p);
169 
170  double j2=X2[0];
171  double i2=X2[1];
172 
173  if((i2>=0)&&(j2>=0)&&(i2<I.getHeight()-1)&&(j2<I.getWidth()-1))
174  {
175  Nbpoint++;
176  //Tij=ptTemplate[point].val;
177 
178  if(blur)
179  IW=BI.getValue(i2,j2);
180  else
181  IW=I.getValue(i2,j2);
182 
183  ct=ptTemplateSupp[point].ct;
184  et=ptTemplateSupp[point].et;
185  cr=(int)((IW*(Nc-1))/255.);
186  er=((double)IW*(Nc-1))/255.-cr;
187 
188  //calcul de l'erreur
189  //erreur+=(Tij-IW)*(Tij-IW);
190 
191  if( ApproxHessian==HESSIAN_NONSECOND && (ptTemplateSelect[point] || !useTemplateSelect) )
192  {
193  vpTemplateTrackerMIBSpline::PutTotPVBsplineNoSecond(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam, bspline);
194  }
195  else if ((ApproxHessian==HESSIAN_0||ApproxHessian==HESSIAN_NEW) && (ptTemplateSelect[point] || !useTemplateSelect))
196  {
197  if(bspline==3){
198  vpTemplateTrackerMIBSpline::PutTotPVBspline3(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam);
199  // {
200  // if(et>0.5){ct++;}
201  // if(er>0.5){cr++;}
202  // int index = (cr*Nc+ct)*totParam;
203  // double *ptb = &PrtTout[index];
204  // vpTemplateTrackerMIBSpline::PutTotPVBspline3(ptb, er, ptTemplateSupp[point].BtInit, size);
205  // }
206  }
207  else{
208  vpTemplateTrackerMIBSpline::PutTotPVBspline4(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam);
209 
210  // {
211  // // ################### AY : Optim
212  // unsigned int index = (cr*Nc+ct)*totParam;
213  // ptb = &PrtTout[index];
214  // vpTemplateTrackerMIBSpline::PutTotPVBspline4(ptb, er, ptTemplateSupp[point].BtInit, size);
215  // // ###################
216  // }
217  }
218  }
219  else if (ptTemplateSelect[point] || !useTemplateSelect)
220  vpTemplateTrackerMIBSpline::PutTotPVBsplinePrt(PrtTout, cr, er, ct, et, Nc,nbParam, bspline);
221  }
222  }
223 
224  double MI;
225  computeProba(Nbpoint);
226  computeMI(MI);
228 
230 
232 
234  KQuasiNewton=HLMdesireInverse;
235 }
236 
238 {
239  if(!CompoInitialised)
240  std::cout<<"Compositionnal tracking no initialised\nUse InitCompInverse(vpImage<unsigned char> &I) function"<<std::endl;
241  dW=0;
242 
243  if(blur)
245 
247  double MI=0,MIprec=-1000;
248 
249  vpColVector p_avant_estimation;p_avant_estimation=p;
252 
253  // std::cout << "MI avant: " << MI_preEstimation << std::endl;
254  // std::cout << "NMI avant: " << NMI_preEstimation << std::endl;
255 
256  initPosEvalRMS(p);
257 
258  vpColVector dpinv(nbParam);
259  double alpha=2.;
260 
261  unsigned int iteration=0;
262 
263  //unsigned int bspline_ = (unsigned int) bspline;
264  //unsigned int totParam = (bspline_ * bspline_)*(1+nbParam+nbParam*nbParam);
265 
266  vpMatrix Hnorm(nbParam,nbParam);
267 
268  do
269  {
270  int Nbpoint=0;
271  MIprec=MI;
272  MI=0;
273 
275 
276  Warp->computeCoeff(p);
277 
278  {
279  for(int point=0;point<(int)templateSize;point++)
280  {
281  vpColVector x1(2),x2(2);
282  double i2,j2;
283 
284  x1[0]=(double)ptTemplate[point].x;
285  x1[1]=(double)ptTemplate[point].y;
286 
287  Warp->computeDenom(x1,p); // A modif pour parallelisation mais ne pose pas de pb avec warp utilises dans DECSA
288  Warp->warpX(x1,x2,p);
289 
290  j2=x2[0];
291  i2=x2[1];
292 
293  if((i2>=0)&&(j2>=0)&&(i2<I.getHeight()-1)&&(j2<I.getWidth()-1))
294  {
295  //if(m_ptCurrentMask == NULL ||(m_ptCurrentMask->getWidth() == I.getWidth() && m_ptCurrentMask->getHeight() == I.getHeight() && (*m_ptCurrentMask)[(unsigned int)i2][(unsigned int)j2] > 128))
296  {
297  Nbpoint++;
298  double IW;
299  if(!blur)
300  IW=(double)I.getValue(i2,j2);
301  else
302  IW=BI.getValue(i2,j2);
303 
304  int ct=ptTemplateSupp[point].ct;
305  double et=ptTemplateSupp[point].et;
306  double tmp = IW*(((double)Nc)-1.f)/255.f;
307  int cr=(int)tmp;
308  double er=tmp-(double)cr;
309 
311  {
312  vpTemplateTrackerMIBSpline::PutTotPVBsplineNoSecond(Prt, dPrt, cr, er, ct, et, Ncb, ptTemplate[point].dW, nbParam, bspline);
313  }
314  else if (ptTemplateSelect[point] || !useTemplateSelect)
315  {
316  if(bspline==3){
317  vpTemplateTrackerMIBSpline::PutTotPVBspline3(Prt, dPrt, d2Prt, cr, er, ct, et, Ncb, ptTemplate[point].dW, nbParam);
318  }
319  else{
320  vpTemplateTrackerMIBSpline::PutTotPVBspline4(Prt, dPrt, d2Prt, cr, er, ct, et, Ncb, ptTemplate[point].dW, nbParam);
321  }
322  }
323  else{
324  vpTemplateTrackerMIBSpline::PutTotPVBsplinePrt(Prt, cr, er, ct, et, Ncb,nbParam, bspline);
325  }
326  }
327 
328  }
329  }
330  }
331 
332  if(Nbpoint==0)
333  {
334  diverge=true;
335  MI=0;
337  throw(vpTrackingException(vpTrackingException::notEnoughPointError, "No points in the template"));
338 
339  }
340  else
341  {
342  // computeProba(Nbpoint);
343 
344  unsigned int indd, indd2;
345  indd = indd2 = 0;
346  unsigned int Ncb_ = (unsigned int)Ncb;
347  for(unsigned int i=0;i<Ncb_*Ncb_;i++){
348  Prt[i]=Prt[i]/Nbpoint;
349  for(unsigned int j=0;j<nbParam;j++){
350  dPrt[indd]=dPrt[indd]/Nbpoint;
351  indd++;
352  for(unsigned int k=0;k<nbParam;k++){
353  d2Prt[indd2]=d2Prt[indd2]/Nbpoint;
354  indd2++;
355  }
356  }
357  }
358 
359  computeMI(MI);
360 
363  computeHessien(H);
364  }
365  computeGradient();
366 
368 
369  try
370  {
371  switch(hessianComputation)
372  {
375  break;
377  if(HLM.cond()>HLMdesire.cond())
379  else
380  dp=gain*0.2*HLM.inverseByLU()*G;
381  break;
382  default:
383  dp=gain*0.2*HLM.inverseByLU()*G;
384  break;
385  }
386  }
387  catch(vpException &e)
388  {
389  //std::cerr<<"probleme inversion"<<std::endl;
390  throw(e);
391  }
392  }
393 
394  switch(minimizationMethod)
395  {
397  {
398  vpColVector dp_test_LMA(nbParam);
399  vpColVector dpinv_test_LMA(nbParam);
400  vpColVector p_test_LMA(nbParam);
402  dp_test_LMA=-100000.1*dp;
403  else
404  dp_test_LMA=1.*dp;
405  Warp->getParamInverse(dp_test_LMA,dpinv_test_LMA);
406  Warp->pRondp(p,dpinv_test_LMA,p_test_LMA);
407 
408  MI=-getCost(I,p);
409  double MI_LMA=-getCost(I,p_test_LMA);
410  if(MI_LMA>MI)
411  {
412  dp=dp_test_LMA;
413  lambda=(lambda/10.<1e-6)?lambda/10.:1e-6;
414  }
415  else
416  {
417  dp=0;
418  lambda=(lambda*10.<1e6)?1e6:lambda*10.;
419  }
420  }
421  break;
423  dp=-gain*0.3*G*20;
424  break;
425 
427  {
428  if(iterationGlobale!=0)
429  {
430  vpColVector s_quasi=p-p_prec;
431  vpColVector y_quasi=G-G_prec;
432  double s_scal_y=s_quasi.t()*y_quasi;
433  //std::cout<<"mise a jour K"<<std::endl;
434  /*if(s_scal_y!=0)//BFGS
435  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);*/
436  //if(s_scal_y!=0)//DFP
437  if(std::fabs(s_scal_y) > std::numeric_limits<double>::epsilon())//DFP
438  {
439  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));
440  //std::cout<<"mise a jour K"<<std::endl;
441  }
442  }
443  dp=gain*KQuasiNewton*G;
444  //std::cout<<KQuasiNewton<<std::endl<<std::endl;
445  p_prec=p;
446  G_prec=G;
447  //p-=1.01*dp;
448  }
449  break;
450 
451  default:
452  {
453  if(useBrent)
454  {
455  alpha=2.;
456  computeOptimalBrentGain(I,p,-MI,dp,alpha);
457  dp=alpha*dp;
458  }
460  dp=-1.*dp;
461 
462  break;
463  }
464  }
465 
466  Warp->getParamInverse(dp,dpinv);
467  Warp->pRondp(p,dpinv,p);
468 
469  iteration++;
471 
472  computeEvalRMS(p);
473 
474  // std::cout << p.t() << std::endl;
475  }
476  while( (!diverge) && (std::fabs(MI-MIprec) > std::fabs(MI)*std::numeric_limits<double>::epsilon()) &&(iteration< iterationMax)&&(evolRMS>threshold_RMS) );
477  //while( (!diverge) && (MI!=MIprec) &&(iteration< iterationMax)&&(evolRMS>threshold_RMS) );
478 
479  nbIteration=iteration;
480 
481  if(diverge)
482  {
483  if(computeCovariance){
485  covarianceMatrix = -1;
486  MI_postEstimation = -1;
487  NMI_postEstimation = -1;
488  }
490 
491  // throw(vpTrackingException(vpTrackingException::badValue, "Tracking failed")) ;
492  }
493  else
494  {
497  // std::cout << "MI apres: " << MI_postEstimation << std::endl;
498  // std::cout << "NMI apres: " << NMI_postEstimation << std::endl;
500  {
501  p=p_avant_estimation;
505  covarianceMatrix = -1;
506  }
507 
509 
510  if(computeCovariance){
511  try{
512  covarianceMatrix = (-H).inverseByLU();
513  // covarianceMatrix = (-Hnorm).inverseByLU();
514  }
515  catch(...){
517  covarianceMatrix = -1;
518  MI_postEstimation = -1;
519  NMI_postEstimation = -1;
521  }
522  }
523  }
524 }
525 
527 {
528  unsigned int nb_corners = zoneTracked->getNbTriangle() * 3;
529  x_pos=new double[nb_corners];
530  y_pos=new double[nb_corners];
531 
532  Warp->computeCoeff(pw);
533  vpTemplateTrackerTriangle triangle;
534 
535  for(unsigned int i=0;i<zoneTracked->getNbTriangle();i++)
536  {
537  zoneTracked->getTriangle(i, triangle);
538  for (unsigned int j=0; j<3; j++) {
539  triangle.getCorner(j, X1[0], X1[1]);
540 
541  Warp->computeDenom(X1,pw);
542  Warp->warpX(X1,X2,p);
543  x_pos[i*3+j]=X2[0];
544  y_pos[i*3+j]=X2[1];
545  }
546  }
547 }
548 
550 {
551  unsigned int nb_corners = zoneTracked->getNbTriangle() * 3;
552 
553  Warp->computeCoeff(pw);
554  evolRMS=0;
555  vpTemplateTrackerTriangle triangle;
556 
557  for(unsigned int i=0;i<zoneTracked->getNbTriangle();i++)
558  {
559  zoneTracked->getTriangle(i, triangle);
560  for (unsigned int j=0; j<3; j++) {
561  triangle.getCorner(j, X1[0], X1[1]);
562 
563  Warp->computeDenom(X1,pw);
564  Warp->warpX(X1,X2,pw);
565  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]);
566  x_pos[i*3+j]=X2[0];
567  y_pos[i*3+j]=X2[1];
568  }
569  }
570  evolRMS=evolRMS/nb_corners;
571 }
572 
574 {
575  delete[] x_pos;
576  delete[] y_pos;
577 }
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:97
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:226
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:1477
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:3500
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
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:175
static void filter(const vpImage< double > &I, vpImage< double > &Iu, vpImage< double > &Iv, const vpMatrix &M, const bool convolve=false)
void computeHessienNormalized(vpMatrix &H)
vpTemplateTrackerWarp * Warp
static void computeHLM(const vpMatrix &H, const double &alpha, vpMatrix &HLM)
Definition: vpMatrix.cpp:3525
void computeProba(int &nbpoint)
vpHessienType hessianComputation