Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpTemplateTrackerMIInverseCompositional.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
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 https://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 */
37#include <visp3/core/vpTrackingException.h>
38#include <visp3/tt_mi/vpTemplateTrackerMIInverseCompositional.h>
39
40#include <memory>
41
44 : vpTemplateTrackerMI(_warp), minimizationMethod(USE_LMA), CompoInitialised(false), useTemplateSelect(false),
45 p_prec(), G_prec(), KQuasiNewton()
46{
47 useInverse = true;
48}
49
50void vpTemplateTrackerMIInverseCompositional::initTemplateRefBspline(unsigned int ptIndex, double &et) // AY : Optim
51{
52 ptTemplateSupp[ptIndex].BtInit = new double[(1 + nbParam + nbParam * nbParam) * static_cast<unsigned int>(bspline)];
53
54 unsigned int index = 0;
55 int endIndex = 1;
56
57 double (*ptBspFct)(double);
58 double (*ptdBspFct)(double);
59 double (*ptd2BspFct)(double);
60 if (bspline == 3) {
61 if (et > 0.5) {
62 et = et - 1;
63 }
64 ptBspFct = &vpTemplateTrackerMIBSpline::Bspline3;
65 ptdBspFct = &vpTemplateTrackerMIBSpline::dBspline3;
66 ptd2BspFct = &vpTemplateTrackerMIBSpline::d2Bspline3;
67 }
68 else {
69 ptBspFct = &vpTemplateTrackerBSpline::Bspline4;
70 ptdBspFct = &vpTemplateTrackerMIBSpline::dBspline4;
71 ptd2BspFct = &vpTemplateTrackerMIBSpline::d2Bspline4;
72 endIndex = 2;
73 }
74
75 for (int it = -1; it <= endIndex; it++) {
76 ptTemplateSupp[ptIndex].BtInit[index++] = (*ptBspFct)(static_cast<double>(-it) + et);
77
78 for (unsigned int ip = 0; ip < nbParam; ++ip) {
79 ptTemplateSupp[ptIndex].BtInit[index++] =
80 (*ptdBspFct)(static_cast<double>(-it) + et) * ptTemplate[ptIndex].dW[ip] * (-1.0);
81 for (unsigned int ip2 = 0; ip2 < nbParam; ++ip2) {
82 ptTemplateSupp[ptIndex].BtInit[index++] =
83 (*ptd2BspFct)(static_cast<double>(-it) + et) * ptTemplate[ptIndex].dW[ip] * ptTemplate[ptIndex].dW[ip2];
84 }
85 }
86 }
87}
88
90{
91 ptTemplateSupp = new vpTemplateTrackerPointSuppMIInv[templateSize];
92
95
101 }
102 double Nc_255_ = (Nc - 1) / 255.;
103 Warp->computeCoeff(p);
104 for (unsigned int point = 0; point < templateSize; point++) {
105 int i = ptTemplate[point].y;
106 int j = ptTemplate[point].x;
107
108 ptTemplate[point].dW = new double[nbParam];
109
110 double dx = ptTemplate[point].dx * Nc_255_;
111 double dy = ptTemplate[point].dy * Nc_255_;
112
113 Warp->getdW0(i, j, dy, dx, ptTemplate[point].dW);
114 double Tij = ptTemplate[point].val;
115 int ct = static_cast<int>(Tij * Nc_255_);
116 double et = (Tij * Nc_255_) - ct;
117 ptTemplateSupp[point].et = et;
118 ptTemplateSupp[point].ct = ct;
119 }
120 CompoInitialised = true;
121}
122
124{
126
127 int Nbpoint = 0;
128
129 double IW;
130 int cr, ct;
131 double er, et;
132
133 Nbpoint = 0;
134
135 if (blur)
137
139 Warp->computeCoeff(p);
140
141 for (unsigned int point = 0; point < templateSize; point++) {
142 int i = ptTemplate[point].y;
143 int j = ptTemplate[point].x;
144 X1[0] = j;
145 X1[1] = i;
146
147 Warp->computeDenom(X1, p);
148 Warp->warpX(X1, X2, p);
149
150 double j2 = X2[0];
151 double i2 = X2[1];
152
153 if ((i2 >= 0) && (j2 >= 0) && (i2 < I.getHeight() - 1) && (j2 < I.getWidth() - 1)) {
154 Nbpoint++;
155
156 if (blur)
157 IW = BI.getValue(i2, j2);
158 else
159 IW = I.getValue(i2, j2);
160
161 ct = ptTemplateSupp[point].ct;
162 et = ptTemplateSupp[point].et;
163 cr = static_cast<int>((IW * (Nc - 1)) / 255.);
164 er = (IW * (Nc - 1)) / 255. - cr;
165
166 if (ApproxHessian == HESSIAN_NONSECOND && (ptTemplateSelect[point] || !useTemplateSelect)) {
167 vpTemplateTrackerMIBSpline::PutTotPVBsplineNoSecond(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam,
168 bspline);
169 }
170 else if ((ApproxHessian == HESSIAN_0 || ApproxHessian == HESSIAN_NEW) &&
171 (ptTemplateSelect[point] || !useTemplateSelect)) {
172 if (bspline == 3) {
173 vpTemplateTrackerMIBSpline::PutTotPVBspline3(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam);
174 }
175 else {
176 vpTemplateTrackerMIBSpline::PutTotPVBspline4(PrtTout, cr, er, ct, et, Nc, ptTemplate[point].dW, nbParam);
177 }
178 }
179 else if (ptTemplateSelect[point] || !useTemplateSelect)
180 vpTemplateTrackerMIBSpline::PutTotPVBsplinePrt(PrtTout, cr, er, ct, et, Nc, nbParam, bspline);
181 }
182 }
183
184 double MI;
185 computeProba(Nbpoint);
186 computeMI(MI);
188
190
192
193 HLMdesireInverse = HLMdesire.inverseByLU();
194 KQuasiNewton = HLMdesireInverse;
195}
196
198{
199 if (!CompoInitialised) {
200 std::cout << "Compositionnal tracking not initialised.\nUse initCompInverse() function." << std::endl;
201 }
202
203 dW = 0;
204
205 if (blur)
207
209 double MI = 0, MIprec = -1000;
210
211 vpColVector p_avant_estimation;
212 p_avant_estimation = p;
215
217
218 vpColVector dpinv(nbParam);
219 double alpha = 2.;
220
221 unsigned int iteration = 0;
222
223 vpMatrix Hnorm(nbParam, nbParam);
224 double evolRMS_init = 0;
225 double evolRMS_prec = 0;
226 double evolRMS_delta;
227
228 vpColVector dp_test_LMA(nbParam);
229 vpColVector dpinv_test_LMA(nbParam);
230 vpColVector p_test_LMA(nbParam);
231
232 do {
233 int Nbpoint = 0;
234 MIprec = MI;
235 MI = 0;
236
238
239 Warp->computeCoeff(p);
240
241 for (int point = 0; point < static_cast<int>(templateSize); point++) {
242 X1[0] = static_cast<double>(ptTemplate[point].x);
243 X1[1] = static_cast<double>(ptTemplate[point].y);
244
245 Warp->computeDenom(X1, p);
246 Warp->warpX(X1, X2, p);
247
248 double j2 = X2[0];
249 double i2 = X2[1];
250
251 if ((i2 >= 0) && (j2 >= 0) && (i2 < I.getHeight() - 1) && (j2 < I.getWidth() - 1)) {
252
253 Nbpoint++;
254 double IW;
255 if (!blur)
256 IW = static_cast<double>(I.getValue(i2, j2));
257 else
258 IW = BI.getValue(i2, j2);
259
260 int ct = ptTemplateSupp[point].ct;
261 double et = ptTemplateSupp[point].et;
262 double tmp = IW * (static_cast<double>(Nc) - 1.) / 255.;
263 int cr = static_cast<int>(tmp);
264 double er = tmp - static_cast<double>(cr);
265
267 (ptTemplateSelect[point] || !useTemplateSelect)) {
268 vpTemplateTrackerMIBSpline::PutTotPVBsplineNoSecond(Prt, dPrt, cr, er, ct, et, Ncb, ptTemplate[point].dW,
270 }
271 else if (ptTemplateSelect[point] || !useTemplateSelect) {
272 if (bspline == 3) {
273 vpTemplateTrackerMIBSpline::PutTotPVBspline3(Prt, dPrt, d2Prt, cr, er, ct, et, Ncb, ptTemplate[point].dW,
274 nbParam);
275 }
276 else {
277 vpTemplateTrackerMIBSpline::PutTotPVBspline4(Prt, dPrt, d2Prt, cr, er, ct, et, Ncb, ptTemplate[point].dW,
278 nbParam);
279 }
280 }
281 else {
282 vpTemplateTrackerMIBSpline::PutTotPVBsplinePrt(Prt, cr, er, ct, et, Ncb, nbParam, bspline);
283 }
284 }
285 }
286
287 if (Nbpoint == 0) {
288 diverge = true;
289 MI = 0;
290 throw(vpTrackingException(vpTrackingException::notEnoughPointError, "No points in the template"));
291
292 }
293 else {
294 unsigned int indd, indd2;
295 indd = indd2 = 0;
296 unsigned int Ncb_ = static_cast<unsigned int>(Ncb);
297 for (unsigned int i = 0; i < Ncb_ * Ncb_; i++) {
298 Prt[i] /= Nbpoint;
299 for (unsigned int j = 0; j < nbParam; j++) {
300 dPrt[indd] /= Nbpoint;
301 indd++;
302 for (unsigned int k = 0; k < nbParam; k++) {
303 d2Prt[indd2] /= Nbpoint;
304 indd2++;
305 }
306 }
307 }
308
309 computeMI(MI);
310
314 }
317
318 try {
319 switch (hessianComputation) {
322 break;
324 if (HLM.cond() > HLMdesire.cond())
326 else
327 dp = gain * 0.2 * HLM.inverseByLU() * G;
328 break;
329 default:
330 dp = gain * 0.2 * HLM.inverseByLU() * G;
331 break;
332 }
333 }
334 catch (const vpException &e) {
335 throw(e);
336 }
337 }
338
339 switch (minimizationMethod) {
342 dp_test_LMA = -100000.1 * dp;
343 else
344 dp_test_LMA = dp;
345 Warp->getParamInverse(dp_test_LMA, dpinv_test_LMA);
346 Warp->pRondp(p, dpinv_test_LMA, p_test_LMA);
347
348 MI = -getCost(I, p);
349 double MI_LMA = -getCost(I, p_test_LMA);
350 if (MI_LMA > MI) {
351 dp = dp_test_LMA;
352 lambda = (lambda / 10. < 1e-6) ? lambda / 10. : 1e-6;
353 }
354 else {
355 dp = 0;
356 lambda = (lambda * 10. < 1e6) ? 1e6 : lambda * 10.;
357 }
358 } break;
360 dp = -gain * 0.3 * G * 20;
361 break;
362
364 if (iterationGlobale != 0) {
365 vpColVector s_quasi = p - p_prec;
366 vpColVector y_quasi = G - G_prec;
367 double s_scal_y = s_quasi.t() * y_quasi;
368 if (std::fabs(s_scal_y) > std::numeric_limits<double>::epsilon()) {
369 KQuasiNewton = KQuasiNewton + 0.0001 * (s_quasi * s_quasi.t() / s_scal_y -
370 KQuasiNewton * y_quasi * y_quasi.t() * KQuasiNewton /
371 (y_quasi.t() * KQuasiNewton * y_quasi));
372 }
373 }
374 dp = gain * KQuasiNewton * G;
375 p_prec = p;
376 G_prec = G;
377 } break;
378
379 default: {
380 if (useBrent) {
381 alpha = 2.;
382 computeOptimalBrentGain(I, p, -MI, dp, alpha);
383 dp = alpha * dp;
384 }
386 dp = -dp;
387
388 break;
389 }
390 }
391
392 Warp->getParamInverse(dp, dpinv);
393 Warp->pRondp(p, dpinv, p);
395
396 if (iteration == 0) {
397 evolRMS_init = evolRMS;
398 }
399 iteration++;
401
402 evolRMS_delta = std::fabs(evolRMS - evolRMS_prec);
403 evolRMS_prec = evolRMS;
404
405 } while ((!diverge) && (std::fabs(MI - MIprec) > std::fabs(MI) * std::numeric_limits<double>::epsilon()) &&
406 (iteration < iterationMax) && (evolRMS_delta > std::fabs(evolRMS_init) * evolRMS_eps));
407
408 nbIteration = iteration;
409
410 if (diverge) {
411 if (computeCovariance) {
412 covarianceMatrix = vpMatrix(Warp->getNbParam(), Warp->getNbParam());
413 covarianceMatrix = -1;
416 }
417 }
418 else {
421
423 p = p_avant_estimation;
426 covarianceMatrix = vpMatrix(Warp->getNbParam(), Warp->getNbParam());
427 covarianceMatrix = -1;
428 }
429
430 if (computeCovariance) {
431 try {
432 covarianceMatrix = (-H).inverseByLU();
433 }
434 catch (...) {
435 covarianceMatrix = vpMatrix(Warp->getNbParam(), Warp->getNbParam());
436 covarianceMatrix = -1;
439 }
440 }
441 }
442}
443END_VISP_NAMESPACE
Implementation of column vector and the associated operations.
vpRowVector t() const
error that can be emitted by ViSP classes.
Definition vpException.h:60
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)
Definition of the vpImage class member functions.
Definition vpImage.h:131
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
static void computeHLM(const vpMatrix &H, const double &alpha, vpMatrix &HLM)
vpHessienApproximationType ApproxHessian
vpImage< double > d2Ix
void computeHessienNormalized(vpMatrix &H)
vpHessienType hessianComputation
double getCost(const vpImage< unsigned char > &I, const vpColVector &tp) VP_OVERRIDE
void computeProba(int &nbpoint)
void computeHessien(vpMatrix &H)
vpImage< double > d2Ixy
double getNormalizedCost(const vpImage< unsigned char > &I, const vpColVector &tp)
vpTemplateTrackerMI(const vpTemplateTrackerMI &)=delete
vpImage< double > d2Iy
vpImage< double > dIx
vpImage< double > dIy
void computeEvalRMS(const vpColVector &p)
void computeOptimalBrentGain(const vpImage< unsigned char > &I, vpColVector &tp, double tMI, vpColVector &direction, double &alpha)
unsigned int iterationMax
void initPosEvalRMS(const vpColVector &p)
vpTemplateTrackerPoint * ptTemplate
vpTemplateTrackerWarp * Warp
unsigned int iterationGlobale
vpImage< double > BI
unsigned int templateSize
Error that can be emitted by the vpTracker class and its derivatives.
@ notEnoughPointError
Not enough point to track.