Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpRBSilhouetteCCDTracker.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
31#include <visp3/core/vpConfig.h>
32#include <visp3/rbt/vpRBSilhouetteCCDTracker.h>
33
34#ifdef VISP_HAVE_OPENMP
35#include <omp.h>
36#endif
37
38#define VISP_DEBUG_CCD_TRACKER 0
39
41
42
43template <class T> class FastMat33
44{
45public:
46 std::array<T, 9> data;
47
49
50 inline T operator[](const size_t i) const { return data[i]; }
51
52 inline T &operator[](const size_t i) { return data[i]; }
53
54 void inverse(FastMat33<T> &minv) const
55 {
56 // determinant
57 T det = data[0] * (data[4] * data[8] - data[7] * data[5]) - data[1] * (data[3] * data[8] - data[5] * data[6]) +
58 data[2] * (data[3] * data[7] - data[4] * data[6]);
59 T invdet = 1 / det;
60
61 minv[0] = (data[4] * data[8] - data[7] * data[5]) * invdet;
62 minv[1] = (data[2] * data[7] - data[1] * data[8]) * invdet;
63 minv[2] = (data[1] * data[5] - data[2] * data[4]) * invdet;
64 minv[3] = (data[5] * data[6] - data[3] * data[8]) * invdet;
65 minv[4] = (data[0] * data[8] - data[2] * data[6]) * invdet;
66 minv[5] = (data[3] * data[2] - data[0] * data[5]) * invdet;
67 minv[6] = (data[3] * data[7] - data[6] * data[4]) * invdet;
68 minv[7] = (data[6] * data[1] - data[0] * data[7]) * invdet;
69 minv[8] = (data[0] * data[4] - data[3] * data[1]) * invdet;
70 }
71
72 static void multiply(const vpMatrix &A, const FastMat33<double> &B, vpMatrix &C)
73 {
74 C.resize(A.getRows(), 3, false, false);
75 for (unsigned int i = 0; i < A.getRows(); ++i) {
76 C[i][0] = A[i][0] * B.data[0] + A[i][1] * B.data[3] + A[i][2] * B.data[6];
77 C[i][1] = A[i][0] * B.data[1] + A[i][1] * B.data[4] + A[i][2] * B.data[7];
78 C[i][2] = A[i][0] * B.data[2] + A[i][1] * B.data[5] + A[i][2] * B.data[8];
79 }
80 }
81};
82
83template <class T> class FastMat63
84{
85public:
86 std::array<T, 18> data;
87
89
90 inline T operator[](const size_t i) const { return data[i]; }
91
92 inline T &operator[](const size_t i) { return data[i]; }
93
94 static void multiply(const FastMat63<T> &A, const FastMat33<T> &B, FastMat63 &C)
95 {
96 for (unsigned int i = 0; i < 6; ++i) {
97 const T *d = &A.data[i * 3];
98 T *c = &C.data[i * 3];
99 c[0] = d[0] * B.data[0] + d[1] * B.data[3] + d[2] * B.data[6];
100 c[1] = d[0] * B.data[1] + d[1] * B.data[4] + d[2] * B.data[7];
101 c[2] = d[0] * B.data[2] + d[1] * B.data[5] + d[2] * B.data[8];
102 }
103 }
104
106 {
107 for (unsigned int i = 0; i < 6; ++i) {
108 const double *a = &A.data[i * 3];
109 double *c = C[i];
110
111 c[0] = a[0] * B[0] + a[1] * B[1] + a[2] * B[2];
112 c[1] = a[0] * B[3] + a[1] * B[4] + a[2] * B[5];
113 c[2] = a[0] * B[6] + a[1] * B[7] + a[2] * B[8];
114
115 c[3] = a[0] * B[9] + a[1] * B[10] + a[2] * B[11];
116 c[4] = a[0] * B[12] + a[1] * B[13] + a[2] * B[14];
117 c[5] = a[0] * B[15] + a[1] * B[16] + a[2] * B[17];
118 }
119 }
120};
121
122template <class T> class FastVec3
123{
124public:
125 std::array<T, 3> data;
126
127 inline T operator[](const size_t i) const { return data[i]; }
128 inline T &operator[](const size_t i) { return data[i]; }
129
130 static void multiply(const FastMat63<double> &A, const FastVec3<double> &B, vpColVector &C)
131 {
132 C[0] = A[0] * B[0] + A[1] * B[1] + A[2] * B[2];
133 C[1] = A[3] * B[0] + A[4] * B[1] + A[5] * B[2];
134 C[2] = A[6] * B[0] + A[7] * B[1] + A[8] * B[2];
135 C[3] = A[9] * B[0] + A[10] * B[1] + A[11] * B[2];
136 C[4] = A[12] * B[0] + A[13] * B[1] + A[14] * B[2];
137 C[5] = A[15] * B[0] + A[16] * B[1] + A[17] * B[2];
138 }
139};
140
141const unsigned int vpRBSilhouetteCCDTracker::BASE_SEED = 421;
142
146
148{
150 m_ccdParameters.delta_h = m_ccdParameters.start_delta_h;
151 m_ccdParameters.iters_since_scale_change = 0;
152 m_controlPoints.clear();
153}
154
156{
157
158 const vpHomogeneousMatrix cMo = frame.renders.cMo;
159 const vpHomogeneousMatrix oMc = cMo.inverse();
160
161 std::vector<std::vector<vpRBSilhouetteControlPoint>> pointsPerThread;
162#ifdef VISP_HAVE_OPENMP
163#pragma omp parallel
164#endif
165 {
166#ifdef VISP_HAVE_OPENMP
167#pragma omp single
168 {
169 unsigned int numThreads = omp_get_num_threads();
170 pointsPerThread.resize(numThreads);
171 }
172#else
173 {
174 pointsPerThread.resize(1);
175 }
176#endif
177#ifdef VISP_HAVE_OPENMP
178 unsigned int threadIdx = omp_get_thread_num();
179#else
180 unsigned int threadIdx = 0;
181#endif
182 std::vector<vpRBSilhouetteControlPoint> localControlPoints;
183#ifdef VISP_HAVE_OPENMP
184#pragma omp for
185#endif
186 for (int i = 0; i < static_cast<int>(frame.silhouettePoints.size()); ++i) {
187 const vpRBSilhouettePoint sp = frame.silhouettePoints[i];
188 int ii = sp.i, jj = sp.j;
189
190 // We only care about outer object contours, not depth disparity that still lie in the object
191 if (!sp.isSilhouette) {
192 continue;
193 }
194
195 // Filter points for which the normal vector may go outside the image
196 if (ii <= m_ccdParameters.h || jj <= m_ccdParameters.h ||
197 static_cast<unsigned int>(ii) >= frame.I.getHeight() - m_ccdParameters.h ||
198 static_cast<unsigned int>(jj) >= frame.I.getWidth() - m_ccdParameters.h) {
199 continue;
200 }
202
203 pccd.buildSilhouettePoint(ii, jj, sp.Z, sp.orientation, sp.normal, cMo, oMc, frame.cam);
204
205 if (std::isnan(sp.orientation) || !pccd.isValid()) {
206 continue;
207 }
208 // Check whether we should add point according to the mask
209 if (frame.hasMask() && m_useMask) {
210 double maskGradValue = pccd.getMaxMaskGradientAlongLine(frame.mask, m_ccdParameters.h);
211 if (maskGradValue < m_minMaskConfidence) {
212 continue;
213 }
214 }
215 localControlPoints.push_back(std::move(pccd));
216 }
217
218 {
219 pointsPerThread[threadIdx] = std::move(localControlPoints);
220 }
221 }
222 unsigned int numElements = 0;
223 for (const std::vector<vpRBSilhouetteControlPoint> &points: pointsPerThread) {
224 numElements += static_cast<unsigned int>(points.size());
225 }
226
227 m_controlPoints.reserve(numElements);
228 for (const std::vector<vpRBSilhouetteControlPoint> &points: pointsPerThread) {
229 m_controlPoints.insert(m_controlPoints.end(), std::make_move_iterator(points.begin()), std::make_move_iterator(points.end()));
230 }
231 // Resample if maximum number of points is specified
232 if (m_maxPoints > 0 && m_controlPoints.size() > m_maxPoints) {
233 std::vector<size_t> keptIndices = m_random.sampleWithoutReplacement(m_maxPoints, m_controlPoints.size());
234
235 std::vector<vpRBSilhouetteControlPoint> finalPoints;
236 finalPoints.reserve(m_maxPoints);
237 for (size_t index : keptIndices) {
238 finalPoints.emplace_back(std::move(m_controlPoints[index]));
239 }
240 m_controlPoints = std::move(finalPoints);
241 }
242}
243
244void vpRBSilhouetteCCDTracker::buildGradientAndHessianStorageViews(unsigned int normalsPerPoint, bool clear)
245{
246 unsigned int numPoints = m_controlPoints.size();
247 unsigned int numNormalPoints = numPoints * 2 * normalsPerPoint;
248 if (m_gradients.size() != numNormalPoints) {
249 // Resize only if we need additional data
250 if (m_gradientData.size() < numNormalPoints * 6) {
251 m_gradientData.resize(numNormalPoints * 6);
252 m_hessianData.resize(numNormalPoints * 6 * 6);
253 }
254 if (clear) {
255 m_gradients.clear();
256 m_hessians.clear();
257 }
258 m_gradients.resize(numNormalPoints);
259 m_hessians.resize(numNormalPoints);
260
261#if defined(VISP_HAVE_OPENMP)
262#pragma omp parallel for
263#endif
264 for (int i = 0; i < static_cast<int>(m_gradients.size()); ++i) {
265 vpColVector::view(m_gradients[i], m_gradientData.data() + i * 6, 6);
266 vpMatrix::view(m_hessians[i], m_hessianData.data() + i * 6 * 6, 6, 6);
267 }
268 }
269
270}
271
273{
274 // Reinit all variables
275 m_sigma = vpMatrix(m_ccdParameters.phi_dim, m_ccdParameters.phi_dim, 0.0);
276 m_cov.resize(6, 6);
277
278 m_vvsConverged = false;
279
280 unsigned int resolution = static_cast<unsigned int>(m_controlPoints.size());
281 int normal_points_number = static_cast<int>(floor(m_ccdParameters.h / m_ccdParameters.delta_h));
282 m_numFeatures = 2 * normal_points_number * 3 * resolution;
283
284 m_stats.reinit(resolution, normal_points_number);
285 m_prevStats.reinit(resolution, normal_points_number);
286 m_gradient = vpMatrix(m_ccdParameters.phi_dim, 1, 0.0);
287 m_hessian = vpMatrix(m_ccdParameters.phi_dim, m_ccdParameters.phi_dim, 0.0);
288 buildGradientAndHessianStorageViews(normal_points_number, true);
289
290 m_weights.resize(m_numFeatures, false);
291 if (m_temporalSmoothingFac > 0.0) {
293 }
294 m_previousFrame = &previousFrame;
295}
296
298{
299 m_sigma = vpMatrix(m_ccdParameters.phi_dim, m_ccdParameters.phi_dim, 0.0);
300 m_cov.resize(6, 6);
301 unsigned int resolution = static_cast<unsigned int>(m_controlPoints.size());
302 int normal_points_number = static_cast<int>(floor(m_ccdParameters.h / m_ccdParameters.delta_h));
303 m_numFeatures = 2 * normal_points_number * 3 * resolution;
304
305 m_prevStats.reinit(resolution, normal_points_number);
306 m_stats.reinit(resolution, normal_points_number);
307 buildGradientAndHessianStorageViews(normal_points_number, false);
308 m_weights.resize(m_numFeatures, false);
309 if (m_temporalSmoothingFac > 0.0) {
311 }
312 else {
314 }
315}
316
318{
319 if (m_numFeatures == 0) {
320 m_vvsConverged = false;
321 return;
322 }
323
324 vpColVector oldPoints(static_cast<unsigned int>(m_controlPoints.size()) * 2);
325 for (unsigned int i = 0; i < m_controlPoints.size(); ++i) {
326 oldPoints[i * 2] = m_controlPoints[i].icpoint.get_u();
327 oldPoints[i * 2 + 1] = m_controlPoints[i].icpoint.get_v();
328 }
329
330 updateCCDPoints(cMo);
331
332 // Compute motion between current and previous frames, in pixels
333 tol = 0.0;
334 for (unsigned int i = 0; i < m_controlPoints.size(); ++i) {
335 tol += abs(oldPoints[i * 2] - m_controlPoints[i].icpoint.get_u());
336 tol += abs(oldPoints[i * 2 + 1] - m_controlPoints[i].icpoint.get_v());
337 }
338 tol /= m_controlPoints.size();
339
340 // If enabled and if motion between consecutive frame is small enough, halve contour size
341 if (m_ccdParameters.iters_since_scale_change > m_ccdParameters.min_iters_before_scale_change && tol < sqrt(static_cast<double>(m_ccdParameters.h) / 8.0)) {
342 int previousH = m_ccdParameters.h;
343 m_ccdParameters.h = std::max(m_ccdParameters.min_h, previousH / 2);
344 if (m_ccdParameters.h != previousH) {
345 m_ccdParameters.delta_h = static_cast<int>(std::max(1, m_ccdParameters.delta_h / 2));
346 changeScale();
347 }
348 m_ccdParameters.iters_since_scale_change = 0;
349 }
350 else {
351 ++m_ccdParameters.iters_since_scale_change;
352 }
353
354 //Update local statistics
356
357 // Update interaction matrix, and gauss newton left and right side terms
358 if (m_temporalSmoothingFac > 0.0) {
360 }
361 else {
363 }
364
365 m_vvsConverged = false;
366 if (iteration > 0 && tol < m_vvsConvergenceThreshold) {
367 m_vvsConverged = true;
368 }
369}
370
372 const vpImage<vpRGBa> &IRGB, const vpImage<unsigned char> &/*depth*/) const
373{
374 unsigned normal_points_number = static_cast<unsigned int>(floor(m_ccdParameters.h / m_ccdParameters.delta_h));
375 unsigned nerror_per_point = 2 * normal_points_number * 3;
376 if (m_displayType == DT_SIMPLE) {
377
378 for (unsigned int i = 0; i < m_controlPoints.size(); ++i) {
380 vpDisplay::displayPoint(IRGB, static_cast<int>(p.icpoint.get_i()), static_cast<int>(p.icpoint.get_j()), vpColor::green, 2);
381 }
382 }
383 else if (m_displayType == DT_ERROR) {
384 vpColVector errorPerPoint(m_controlPoints.size());
385 double maxPointError = 0.0;
386 for (unsigned int i = 0; i < m_controlPoints.size(); ++i) {
387 double sum = 0.0;
388 for (unsigned int j = 0; j < nerror_per_point; ++j) {
389 sum += m_error[i * nerror_per_point + j];
390 }
391 if (sum > maxPointError) {
392 maxPointError = sum;
393 }
394 errorPerPoint[i] = sum;
395 }
396 const vpColor bestColor = vpColor::green;
397 const vpColor worstColor = vpColor::red;
398 const double diffR = static_cast<double>(worstColor.R) - static_cast<double>(bestColor.R);
399 const double diffG = static_cast<double>(worstColor.G) - static_cast<double>(bestColor.G);
400 const double diffB = static_cast<double>(worstColor.B) - static_cast<double>(bestColor.B);
401 unsigned idx = 0;
403 const double weight = errorPerPoint[idx] / maxPointError;
404
405 vpColor c;
406 c.R = static_cast<unsigned char>(static_cast<double>(bestColor.R) + diffR * weight);
407 c.G = static_cast<unsigned char>(static_cast<double>(bestColor.G) + diffG * weight);
408 c.B = static_cast<unsigned char>(static_cast<double>(bestColor.B) + diffB * weight);
409
410 vpDisplay::displayCross(IRGB, static_cast<int>(p.icpoint.get_i()), static_cast<int>(p.icpoint.get_j()), 3, c, 1);
411 ++idx;
412 }
413 }
414 else if (m_displayType == DT_WEIGHT) {
415 vpColVector weightPerPoint(static_cast<unsigned int>(m_controlPoints.size()));
416 for (unsigned int i = 0; i < m_controlPoints.size(); ++i) {
417 double sum = 0.0;
418 for (unsigned int j = 0; j < nerror_per_point; ++j) {
419 sum += m_weights[i * nerror_per_point + j];
420 }
421
422 weightPerPoint[i] = sum / nerror_per_point;
423 }
424 const vpColor bestColor = vpColor::green;
425 unsigned idx = 0;
427 const double weight = weightPerPoint[idx];
428 vpColor c;
429 c.R = 0;
430 c.G = static_cast<unsigned char>(255.f * weight);
431 c.B = 0;
432
433 vpDisplay::displayCross(IRGB, static_cast<int>(p.icpoint.get_i()), static_cast<int>(p.icpoint.get_j()), 3, c, 1);
434 idx++;
435 }
436 }
438 vpColVector weightPerPoint(static_cast<unsigned int>(m_controlPoints.size()));
439 vpColVector errorPerPoint(static_cast<unsigned int>(m_controlPoints.size()));
440 for (unsigned int i = 0; i < m_controlPoints.size(); ++i) {
441 double sum = 0.0;
442 double sumError = 0.0;
443 for (unsigned int j = 0; j < nerror_per_point; ++j) {
444 sum += m_weights[i * nerror_per_point + j];
445 sumError += m_error[i * nerror_per_point + j];
446 }
447 weightPerPoint[i] = sum / nerror_per_point;
448 errorPerPoint[i] = sumError / nerror_per_point;
449
450 }
451 double maxError = errorPerPoint.getMaxValue();
452 unsigned idx = 0;
454 vpColor c;
455 c.R = static_cast<unsigned char>((errorPerPoint[idx] / maxError) * 255.0);
456 c.G = 0;
457 c.B = static_cast<unsigned char>(255.0 * weightPerPoint[idx]);
458 // vpImagePoint diff(m_stats.nv[idx][1] * m_ccdParameters.h, m_stats.nv[idx][0] * m_ccdParameters.h);
459 // vpImagePoint ip1 = p.icpoint - diff;
460 // vpImagePoint ip2 = p.icpoint + diff;
461
462 // vpDisplay::displayLine(IRGB, ip1, ip2, c, 1);
463 vpDisplay::displayCross(IRGB, static_cast<int>(p.icpoint.get_i()), static_cast<int>(p.icpoint.get_j()), 3, c, 1);
464 idx++;
465 }
466 }
467 else {
468 throw vpException(vpException::badValue, "Unknown display type");
469 }
470}
471
473{
474 const vpRotationMatrix cRo = cMo.getRotationMatrix();
476 p.updateSilhouettePoint(cMo, cRo);
477 }
478}
479
480bool extremitiesOutsideOfImage(int h, int w, unsigned int l, const double *nv_ptr, double i, double j)
481{
482 int id, jd;
483
484 jd = static_cast<int>(round(j - l * nv_ptr[0]));
485 id = static_cast<int>(round(i - l * nv_ptr[1]));
486
487 if (id < 0 || jd < 0 || id >= h || jd >= w) {
488 return true;
489 }
490
491 jd = static_cast<int>(round(j + l * nv_ptr[0]));
492 id = static_cast<int>(round(i + l * nv_ptr[1]));
493
494 if (id < 0 || jd < 0 || id >= h || jd >= w) {
495 return true;
496 }
497 return false;
498}
499
501{
502
503 const double minus_exp_gamma2 = exp(-m_ccdParameters.gamma_2);
504
505 const double sigma = m_ccdParameters.h / (m_ccdParameters.alpha * m_ccdParameters.gamma_3);
506 // sigma_hat = gamma_3 * sigma
507
508 // double sigma_hat = max(h/sqrt(2*gamma_2), gamma_4);
509 const double sigma_hat = m_ccdParameters.gamma_3 * sigma + m_ccdParameters.gamma_4;
510 unsigned int resolution = static_cast<unsigned int>(m_controlPoints.size());
511 // to save the normalized parameters of vic[i,8]
512 // dimension: resolution x 2
513 // the first column save the normalized coefficient outside the curve
514 // the second column store the one inside the curve
515 vpMatrix normalized_param = vpMatrix(resolution, 2, 0.0);
516
517#ifdef VISP_HAVE_OPENMP
518#pragma omp parallel for
519#endif
520 for (int kk = 0; kk < static_cast<int>(m_controlPoints.size()); kk++) {
521 // temporary points used to store those points in the
522 // normal direction as well as negative normal direction
523 std::array<double, 2> pt1, pt2;
524
525 // store the distance from a point in normal(negative norml) direction
526 // to the point on the curve
527 std::array<double, 2> dist1, dist2;
528
530
531 double *nv_ptr = stats.nv[kk];
532 nv_ptr[0] = p.nxs;
533 nv_ptr[1] = p.nys;
534
535 int ccdh = m_ccdParameters.h;
536 if (extremitiesOutsideOfImage(static_cast<int>(I.getHeight()), static_cast<int>(I.getWidth()), ccdh, nv_ptr, p.icpoint.get_i(), p.icpoint.get_j())) {
537 p.setValid(false); // invalidate points that are too close to image border
538 }
539
540 if (!p.isValid()) {
541 continue;
542 }
543#if VISP_DEBUG_CCD_TRACKER
544 if (std::isnan(nv_ptr[0]) || std::isnan(nv_ptr[1])) {
545 throw vpException(vpException::fatalError, "x: %f, theta = %f", p.xs, p.getTheta());
546 }
547#endif
548
549 int k = 0;
550 double alpha = 0.5;
551 double *vic_ptr = stats.vic[kk];
552 for (int j = m_ccdParameters.delta_h; j <= m_ccdParameters.h; j += m_ccdParameters.delta_h, k++) {
554 // calculate in the direction +n: (n_x, n_y)
556 // x_{k,l}
557 pt1[0] = round(p.icpoint.get_u() + j * nv_ptr[0]);
558 // y_{k,l}
559 pt1[1] = round(p.icpoint.get_v() + j * nv_ptr[1]);
560 // distance between x_{k,l} and x_{k,0} in the normal direction
561 // appoximately it is l*h, l = {1,2,3,.....}
562 dist1[0] = (pt1[0] - p.icpoint.get_u()) * nv_ptr[0] + (pt1[1] - p.icpoint.get_v()) * nv_ptr[1];
563 // distance between y_{k,l} and y_{k,0} along the curve
564 // it approximates 0
565 dist1[1] = (pt1[0] - p.icpoint.get_u()) * nv_ptr[1] - (pt1[1] - p.icpoint.get_v()) * nv_ptr[0];
566 vic_ptr[10 * k + 0] = pt1[1];
567 vic_ptr[10 * k + 1] = pt1[0];
568 vic_ptr[10 * k + 2] = dist1[0];
569 vic_ptr[10 * k + 3] = dist1[1];
570
571 // fuzzy assignment a(d_{k,l}) = 1/2*(erf(d_{kl})/\sqrt(2)*sigma) + 1/2
572 vic_ptr[10 * k + 4] = 0.5 * (erf((dist1[0]) / (sqrt(2) * sigma)) + 1.0);
573 //vic_ptr[10*k + 4] = logistic(dist1[0]/(sqrt(2)*sigma));
574 //double wp1 = (a_{d,l} - gamm_1) /(1-gamma_1)
575 double wp1 = (vic_ptr[10 * k + 4] - m_ccdParameters.gamma_1) / (1 - m_ccdParameters.gamma_1);
576
577 // wp1^4, why? if a_{d,l} \approx 0.5, do not count the point
578 vic_ptr[10 * k + 5] = wp1 * wp1 * wp1 * wp1;
579
580 // wp1 = (1-a_{d,l} - gamm_1) /(1-gamma_1)
581 // double wp2 = (1-vic_ptr[10*k + 4] - gamma_1)/(1-gamma_1);
582 double wp2 = (1 - vic_ptr[10 * k + 4] - 0.25);
583 vic_ptr[10 * k + 6] = -64 * wp2 * wp2 * wp2 * wp2 + 0.25;
584 // W_p(d_p, simga_p) = c*max[0, exp(-d_p^2/2*sigma_p'^2) - exp(-gamma_2))]
585 vic_ptr[10 * k + 7] = std::max((exp(-0.5 * dist1[0] * dist1[0] / (sigma_hat * sigma_hat)) - minus_exp_gamma2), 0.0);
586 // W' = 0.5*exp(-|d_v= - d_p=|/alpha)/alpha
587 vic_ptr[10 * k + 8] = 0.5 * exp(-abs(dist1[1]) / alpha) / alpha;
588 // the derivative of col_5: 1/(sqrt(2*PI)*sigma)*exp{-d_{k,l}^2/(2*sigma*sigma)}
589 vic_ptr[10 * k + 9] = exp(-dist1[0] * dist1[0] / (2 * sigma * sigma)) / (sqrt(2.0 * M_PI) * sigma);
590
591
592 // calculate the normalization parameter c
593 normalized_param[kk][0] += vic_ptr[10 * k + 7];
594
596 // calculate in the direction -n: (-n_x, -n_y)
598 pt2[0] = round(p.icpoint.get_u() - j * nv_ptr[0]);
599 pt2[1] = round(p.icpoint.get_v() - j * nv_ptr[1]);
600
601 // cv::circle(canvas_tmp, cv::Point2d(pt2[0], pt2[1]), 1, CV_RGB(255,0,0), 1);#ifdef DEBUG
602
603 // start compute the size in the direction of -(n_x, n_y)
604 dist2[0] = (pt2[0] - p.icpoint.get_u()) * nv_ptr[0] + (pt2[1] - p.icpoint.get_v()) * nv_ptr[1];
605 dist2[1] = (pt2[0] - p.icpoint.get_u()) * nv_ptr[1] - (pt2[1] - p.icpoint.get_v()) * nv_ptr[0];
606 int negative_normal = k + static_cast<int>(floor(m_ccdParameters.h / m_ccdParameters.delta_h));
607 vic_ptr[10 * negative_normal + 0] = pt2[1];
608 vic_ptr[10 * negative_normal + 1] = pt2[0];
609 vic_ptr[10 * negative_normal + 2] = dist2[0];
610 vic_ptr[10 * negative_normal + 3] = dist2[1];
611 vic_ptr[10 * negative_normal + 4] = 0.5 * (erf(dist2[0] / (sqrt(2) * sigma)) + 1);
612 //vic_ptr[10*negative_normal + 4] = logistic(dist2[0]/(sqrt(2)*sigma));
613 // vic_ptr[10*negative_normal + 4] = 0.5;
614 wp1 = (vic_ptr[10 * negative_normal + 4] - 0.25);
615 vic_ptr[10 * negative_normal + 5] = -64 * wp1 * wp1 * wp1 * wp1 + 0.25;
616 wp2 = (1 - vic_ptr[10 * negative_normal + 4] - m_ccdParameters.gamma_1) / (1 - m_ccdParameters.gamma_1);
617 vic_ptr[10 * negative_normal + 6] = wp2 * wp2 * wp2 * wp2;
618 vic_ptr[10 * negative_normal + 7] = std::max((exp(-0.5 * dist2[0] * dist2[0] / (sigma_hat * sigma_hat)) - minus_exp_gamma2), 0.0);
619 vic_ptr[10 * negative_normal + 8] = 0.5 * exp(-abs(dist2[0]) / alpha) / alpha;
620 vic_ptr[10 * negative_normal + 9] = exp(-dist2[0] * dist2[0] / (2 * sigma * sigma)) / (sqrt(2 * M_PI) * sigma);
621 normalized_param[kk][1] += vic_ptr[10 * negative_normal + 7];
622 }
623 }
624
625#ifdef VISP_HAVE_OPENMP
626#pragma omp parallel for
627#endif
628 for (int i = 0; i < static_cast<int>(resolution); ++i) {
629 if (!m_controlPoints[i].isValid()) {
630 continue;
631 }
632
633 int k = 0;
634 // w1 = \sum wp_1, w2 = \sum wp_2
635 double w1 = 0.0, w2 = 0.0;
636
637 // store mean value near the curve
638 std::array<double, 3> m1 { 0.0, 0.0, 0.0 }, m2 { 0.0, 0.0, 0.0 };
639
640 // store the second mean value near the curve
641 std::array<double, 9> m1_o2 { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
642 std::array<double, 9> m2_o2 { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
643
644 // compute local statistics
645
646 // start search the points in the +n direction as well as -n direction
647 double wp1 = 0.0, wp2 = 0.0;
648
649 double *vic_ptr = stats.vic[i];
650 double *mean_vic_ptr = stats.mean_vic[i];
651 double *cov_vic_ptr = stats.cov_vic[i];
652 double *pix_ptr = stats.imgPoints[i];
653
654 for (int j = m_ccdParameters.delta_h; j <= m_ccdParameters.h; j += m_ccdParameters.delta_h, k++) {
655 wp1 = 0.0, wp2 = 0.0;
656 int negative_normal = k + static_cast<int>(floor(m_ccdParameters.h / m_ccdParameters.delta_h));
657 const double *vic_k = vic_ptr + 10 * k;
658
659 // wp1 = w(a_{k,l})*w(d_{k,l})*w(d)
660 wp1 = (vic_k[5] * vic_k[7] / normalized_param[i][0]);
661
662 // wp2 = w(a_{k,l})*w(d_{k,l})*w(d)
663 wp2 = (vic_k[6] * vic_k[7] / normalized_param[i][1]);
664 //w1 = \sum{wp1}
665 w1 += wp1;
666
667 //w2 = \sum{wp2}
668 w2 += wp2;
669
670 // compute the mean value in the vicinity of a point
671 // m_{ks} = I{k}^{s} = \sum_{l} w_{kls}{I_{kl}} : s = 1 or 2
672#if VISP_DEBUG_CCD_TRACKER
673 if (vic_k[0] >= I.getHeight() || vic_k[1] >= I.getWidth()) {
674 throw vpException(vpException::badValue, "Reading out of image");
675 }
676#endif
677 const vpRGBa pixelRGBa = I(static_cast<unsigned int>(vic_k[0]), static_cast<unsigned int>(vic_k[1]));
678 double *pixel = pix_ptr + k * 3;
679 pixel[0] = static_cast<double>(pixelRGBa.R);
680 pixel[1] = static_cast<double>(pixelRGBa.G);
681 pixel[2] = static_cast<double>(pixelRGBa.B);
682
683 m1[0] += wp1 * pixel[0];
684 m1[1] += wp1 * pixel[1];
685 m1[2] += wp1 * pixel[2];
686
687 m2[0] += wp2 * pixel[0];
688 m2[1] += wp2 * pixel[1];
689 m2[2] += wp2 * pixel[2];
690
691 // compute second order local statistics
692 // m_{k,s} = \sum_{l} w_{kls} I_{kl}*I_{kl}^T
693 for (unsigned int m = 0; m < 3; ++m) {
694 for (unsigned int n = 0; n < 3; ++n) {
695 m1_o2[m * 3 + n] += wp1 * pixel[m] * pixel[n];
696 m2_o2[m * 3 + n] += wp2 * pixel[m] * pixel[n];
697 }
698 }
699 const double *vic_neg = vic_ptr + 10 * negative_normal;
700 const vpRGBa pixelNegRGBa = I(static_cast<unsigned int>(vic_neg[0]), static_cast<unsigned int>(vic_neg[1]));
701 double *pixelNeg = pix_ptr + negative_normal * 3;
702
703 pixelNeg[0] = static_cast<double>(pixelNegRGBa.R);
704 pixelNeg[1] = static_cast<double>(pixelNegRGBa.G);
705 pixelNeg[2] = static_cast<double>(pixelNegRGBa.B);
706 wp1 = (vic_neg[5] * vic_neg[7] / normalized_param[i][0]);
707 wp2 = (vic_neg[6] * vic_neg[7] / normalized_param[i][1]);
708 w1 += wp1;
709 w2 += wp2;
710
711 m1[0] += wp1 * pixelNeg[0];
712 m1[1] += wp1 * pixelNeg[1];
713 m1[2] += wp1 * pixelNeg[2];
714
715 m2[0] += wp2 * pixelNeg[0];
716 m2[1] += wp2 * pixelNeg[1];
717 m2[2] += wp2 * pixelNeg[2];
718
719 for (unsigned int m = 0; m < 3; ++m) {
720 for (unsigned int n = 0; n < 3; ++n) {
721 m1_o2[m * 3 + n] += wp1 * pixelNeg[m] * pixelNeg[n];
722 m2_o2[m * 3 + n] += wp2 * pixelNeg[m] * pixelNeg[n];
723 }
724 }
725 }
726 mean_vic_ptr[0] = m1[0] / w1;
727 mean_vic_ptr[1] = m1[1] / w1;
728 mean_vic_ptr[2] = m1[2] / w1;
729
730 mean_vic_ptr[3] = m2[0] / w2;
731 mean_vic_ptr[4] = m2[1] / w2;
732 mean_vic_ptr[5] = m2[2] / w2;
733
734 for (unsigned int m = 0; m < 3; ++m) {
735 for (unsigned int n = 0; n < 3; ++n) {
736 cov_vic_ptr[m * 3 + n] = m1_o2[m * 3 + n] / w1 - m1[m] * m1[n] / (w1 * w1);
737 cov_vic_ptr[9 + m * 3 + n] = m2_o2[m * 3 + n] / w2 - m2[m] * m2[n] / (w2 * w2);
738 }
739 cov_vic_ptr[m * 3 + m] += m_ccdParameters.kappa;
740 cov_vic_ptr[9 + m * 3 + m] += m_ccdParameters.kappa;
741 }
742 }
743}
744
745
746
747void sumGradientsAndHessians(const std::vector<vpColVector> &gradients, const std::vector<vpMatrix> &hessians, const vpColVector &weights, vpColVector &gradient, vpMatrix &hessian, vpMatrix &L)
748{
749 std::vector<vpColVector> gradientPerThread;
750 std::vector<vpMatrix> hessianPerThread;
751 gradient = 0.0;
752 hessian = 0.0;
753#ifdef VISP_HAVE_OPENMP
754#pragma omp parallel
755#endif
756 {
757#ifdef VISP_HAVE_OPENMP
758#pragma omp single
759 {
760 unsigned int numThreads = omp_get_num_threads();
761 gradientPerThread.resize(numThreads);
762 hessianPerThread.resize(numThreads);
763 }
764#else
765 {
766 gradientPerThread.resize(1);
767 hessianPerThread.resize(1);
768 }
769#endif
770
771#ifdef VISP_HAVE_OPENMP
772 unsigned int threadIdx = omp_get_thread_num();
773#else
774 unsigned int threadIdx = 0;
775#endif
776 vpColVector localGradient(gradient.getRows(), 0.0);
777 vpMatrix localHessian(hessian.getRows(), hessian.getCols(), 0.0);
778
779#ifdef VISP_HAVE_OPENMP
780#pragma omp for
781#endif
782 for (int ii = 0; ii < static_cast<int>(gradients.size()); ++ii) {
783 const unsigned int i = static_cast<unsigned int>(ii);
784 const double *g = gradients[i].data;
785 const double *h = hessians[i].data;
786 double *Ldata = L[i];
787 double w = weights[i];
788
789 for (unsigned int j = 0; j < 6; ++j) {
790 Ldata[j] *= w;
791 localGradient[j] += g[j] * w;
792 const double *hj = h + j* 6;
793 for (unsigned int k = 0; k < 6; ++k) {
794
795 localHessian[j][k] += hj[k] * w;
796 }
797 }
798
799 }
800 {
801 gradientPerThread[threadIdx] = localGradient;
802 hessianPerThread[threadIdx] = localHessian;
803 }
804 }
805
806 for (unsigned int i = 0; i < gradientPerThread.size(); ++i) {
807 gradient += gradientPerThread[i];
808 hessian += hessianPerThread[i];
809 }
810}
811
812template<bool hasTemporalSmoothing>
814{
815 const unsigned int npointsccd = static_cast<unsigned int>(m_controlPoints.size());
816 const unsigned int normal_points_number = static_cast<unsigned int>(floor(m_ccdParameters.h / m_ccdParameters.delta_h));
817 const unsigned int nerror_ccd = 2 * normal_points_number * 3 * npointsccd;
818 m_error.resize(nerror_ccd, false);
819 m_weighted_error.resize(nerror_ccd, false);
820 vpColVector errorPerPoint(static_cast<unsigned int>(m_controlPoints.size()), 0.0);
821 m_L.resize(nerror_ccd, 6, false, false);
822#ifdef VISP_HAVE_OPENMP
823#pragma omp parallel
824#endif
825 {
826 // vpMatrix tmp_cov(3, 3);
827 // vpMatrix tmp_cov_inv(3, 3);
828 FastMat33<double> tmp_cov, tmp_cov_inv;
829 FastMat63<double> tmp_jacobian;
830 FastMat63<double> tmp_jacobian_x_tmp_cov_inv;
831 FastVec3<double> tmp_pixel_diff;
832 vpMatrix Lnvp(1, 6);
833
834 vpMatrix objectFrameProj(6, 6);
836 vpVelocityTwistMatrix cVo(cMo);
837 objectFrameProj = cVo * m_oJo;
838 }
839
840#ifdef VISP_HAVE_OPENMP
841#pragma omp for
842#endif
843 for (int i = 0; i < static_cast<int>(m_controlPoints.size()); i++) {
844 const unsigned int ui = static_cast<unsigned int>(i);
846 errorPerPoint[ui] = 0.0;
847 if (!p.isValid()) {
848 for (unsigned int j = 0; j < 2 * normal_points_number; ++j) {
849 for (unsigned int m = 0; m < 3; ++m) {
850 m_error[ui * 2 * normal_points_number * 3 + j * 3 + m] = 0.0;
851 }
852 }
853 continue;
854 }
855
856 const double *vic_ptr = m_stats.vic[ui];
857 const double *nv_ptr = m_stats.nv[ui];
858 const double *mean_vic_ptr = m_stats.mean_vic[ui];
859 const double *cov_vic_ptr = m_stats.cov_vic[ui];
860 const double *pix_ptr = m_stats.imgPoints[ui];
861
862 const double *mean_vic_ptr_prev = m_prevStats.mean_vic[ui];
863 const double *cov_vic_ptr_prev = m_prevStats.cov_vic[ui];
864
865 const vpCameraParameters &cam = p.getCameraParameters();
866
867 Lnvp[0][0] = (-nv_ptr[0] / p.Zs);
868 Lnvp[0][1] = (-nv_ptr[1] / p.Zs);
869 Lnvp[0][2] = ((nv_ptr[0] * p.xs + nv_ptr[1] * p.ys) / p.Zs);
870 Lnvp[0][3] = (nv_ptr[0] * p.xs * p.ys + nv_ptr[1] * (1.0 + p.ys * p.ys));
871 Lnvp[0][4] = (-nv_ptr[1] * p.xs * p.ys - nv_ptr[0] * (1.0 + p.xs * p.xs));
872 Lnvp[0][5] = (nv_ptr[0] * p.ys - nv_ptr[1] * p.xs);
874 Lnvp = Lnvp * objectFrameProj;
875 }
876
877 for (unsigned int j = 0; j < 2 * normal_points_number; ++j) {
878 const double *vic_j = vic_ptr + 10 * j;
879 const double *pix_j = pix_ptr + j * 3;
880 const double errf = vic_j[4];
881 const double smooth2 = m_temporalSmoothingFac * m_temporalSmoothingFac;
882 double *error_ccd_j = m_error.data + i * 2 * normal_points_number * 3 + j * 3;
883
884 for (unsigned n = 0; n < 9; ++n) {
885 //double *tmp_cov_ptr = tmp_cov[m];
886 tmp_cov[n] = errf * cov_vic_ptr[n] + (1.0 - errf) * cov_vic_ptr[n + 9];
887 if constexpr (hasTemporalSmoothing) {
888 tmp_cov[n] += smooth2 * (errf * cov_vic_ptr_prev[n] + (1.0 - errf) * cov_vic_ptr_prev[n + 9]);
889 }
890 }
891
892 tmp_cov.inverse(tmp_cov_inv);
893
894 //compute the difference between I_{kl} and \hat{I_{kl}}
895 for (int m = 0; m < 3; ++m) {
896 double err = (pix_j[m] - errf * mean_vic_ptr[m] - (1.0 - errf) * mean_vic_ptr[m + 3]);
897 if constexpr (hasTemporalSmoothing) {
898 err += m_temporalSmoothingFac * (pix_j[m] - errf * mean_vic_ptr_prev[m] - (1.0 - errf) * mean_vic_ptr_prev[m + 3]);
899 }
900 //error_ccd[i*2*normal_points_number*3 + j*3 + m] = img(vic_ptr[10*j+0], vic_ptr[10*j+1])[m]- errf * mean_vic_ptr[m]- (1-errf)* mean_vic_ptr[m+3];
901 tmp_pixel_diff[m] = err;
902 error_ccd_j[m] = err;
903 errorPerPoint[ui] += err;
904 }
905
906 //compute jacobian matrix
907 //memset(tmp_jacobian.data, 0, 3 * m_ccdParameters.phi_dim * sizeof(double));
908 for (unsigned int n = 0; n < 3; ++n) {
909 const double f = -cam.get_px() * (vic_j[9] * (mean_vic_ptr[n] - mean_vic_ptr[n + 3]));
910 const double facPrev = hasTemporalSmoothing ? -cam.get_px() * m_temporalSmoothingFac * (vic_j[9] * (mean_vic_ptr_prev[n] - mean_vic_ptr_prev[n + 3])) : 0.0;
911 for (unsigned int dof = 0; dof < 6; ++dof) {
912 tmp_jacobian.data[dof * 3 + n] = f * Lnvp[0][dof];
913 if constexpr (hasTemporalSmoothing) {
914 tmp_jacobian.data[dof * 3 + n] += facPrev * Lnvp[0][dof];
915 }
916 }
917 }
918
919 FastMat63<double>::multiply(tmp_jacobian, tmp_cov_inv, tmp_jacobian_x_tmp_cov_inv);
920 //vpMatrix::mult2Matrices(tmp_jacobian, tmp_cov_inv, tmp_jacobian_x_tmp_cov_inv);
921
922 FastVec3<double>::multiply(tmp_jacobian_x_tmp_cov_inv, tmp_pixel_diff, m_gradients[ui * 2 * normal_points_number + j]);
923 FastMat63<double>::multiplyBTranspose(tmp_jacobian_x_tmp_cov_inv, tmp_jacobian, m_hessians[ui * 2 * normal_points_number + j]);
924 // vpMatrix::mult2Matrices(tmp_jacobian_x_tmp_cov_inv, tmp_jacobian.t(), m_hessians[i * 2 * normal_points_number + j]);
925 }
926 }
927 }
928
929 //m_robust.setMinMedianAbsoluteDeviation(1.0);
930 vpColVector weightPerPoint(errorPerPoint.getRows());
931 m_robust.MEstimator(vpRobust::vpRobustEstimatorType::TUKEY, errorPerPoint, weightPerPoint);
932 for (unsigned int i = 0; i < m_controlPoints.size(); ++i) {
933 double w = m_controlPoints[i].isValid() ? weightPerPoint[i] : 0.0;
934 for (unsigned int j = 0; j < static_cast<unsigned int>(2 * normal_points_number * 3); ++j) {
935 m_weights[i * 2 * normal_points_number * 3 + j] = w;
936 }
937 }
938 sumGradientsAndHessians(m_gradients, m_hessians, m_weights, m_gradient, m_hessian, m_L);
940 m_LTR = -m_gradient;
941
942 try {
943 vpMatrix hessian_E_inv(6, 6);
944 if (hasIgnoredDofs() || m_hessian.det() < 1e-6) {
945 hessian_E_inv = m_hessian.pseudoInverse();
946 }
947 else {
948 hessian_E_inv = m_hessian.inverseByCholesky();
949 }
950 //m_sigma = /*m_sigma +*/ 2*hessian_E_inv;
951 m_sigma = m_ccdParameters.covarianceIterDecreaseFactor * m_sigma + 2.0 * (1.0 - m_ccdParameters.covarianceIterDecreaseFactor) * hessian_E_inv;
952 }
953 catch (vpException &e) {
954
955 }
956}
957
958
959END_VISP_NAMESPACE
T operator[](const size_t i) const
T & operator[](const size_t i)
std::array< T, 9 > data
void inverse(FastMat33< T > &minv) const
static void multiply(const vpMatrix &A, const FastMat33< double > &B, vpMatrix &C)
std::array< T, 18 > data
static void multiplyBTranspose(const FastMat63< double > &A, const FastMat63< double > &B, vpMatrix &C)
static void multiply(const FastMat63< T > &A, const FastMat33< T > &B, FastMat63 &C)
T operator[](const size_t i) const
T & operator[](const size_t i)
T & operator[](const size_t i)
std::array< T, 3 > data
T operator[](const size_t i) const
static void multiply(const FastMat63< double > &A, const FastVec3< double > &B, vpColVector &C)
unsigned int getCols() const
Definition vpArray2D.h:423
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition vpArray2D.h:448
unsigned int getRows() const
Definition vpArray2D.h:433
Type getMaxValue() const
Definition vpArray2D.h:1237
vpMatrix imgPoints
Normal vector.
vpMatrix mean_vic
Vicinity data.
vpMatrix nv
Covariance.
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
static vpColVector view(double *raw_data, unsigned int rows)
Create a column vector view of a raw data array. The view can modify the contents of the raw data arr...
Class to define RGB colors available for display functionalities.
Definition vpColor.h:157
static const vpColor red
Definition vpColor.h:198
static const vpColor green
Definition vpColor.h:201
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
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
@ fatalError
Fatal error.
Definition vpException.h:72
Implementation of an homogeneous matrix and operations on such kind of matrices.
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:181
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
static vpMatrix view(double *data, unsigned int rows, unsigned int cols)
Create a matrix view of a raw data array. The view can modify the contents of the raw data array,...
Definition vpMatrix.cpp:307
All the data related to a single tracking frame. This contains both the input data (from a real camer...
vpImage< vpRGBa > IRGB
Image luminance.
vpImage< unsigned char > I
std::vector< vpRBSilhouettePoint > silhouettePoints
vpImage< float > mask
depth image, 0 sized if depth is not available
vpRBRenderData renders
camera parameters
vpColVector m_weights
Weighted VS error.
bool m_jacobianInObjectSpace
Matrix representation of the estimated DOFS.
vpMatrix m_LTL
Error jacobian (In VS terms, the interaction matrix).
vpColVector m_LTR
Left side of the Gauss newton minimization.
bool m_vvsConverged
User-defined weight for this specific type of feature.
unsigned m_numFeatures
Error weights.
vpColVector m_weighted_error
Raw VS Error vector.
vpMatrix m_cov
Right side of the Gauss Newton minimization.
const vpRBFeatureTrackerInput * m_previousFrame
void buildGradientAndHessianStorageViews(unsigned int normalsPerPoint, bool clear)
Update the gradient and hessian storage views. Reserve new memory if required and ensure that gradien...
vpRobust m_robust
Silhouette points where to compute CCD statistics.
void extractFeatures(const vpRBFeatureTrackerInput &frame, const vpRBFeatureTrackerInput &previousFrame, const vpHomogeneousMatrix &cMo) VP_OVERRIDE
Extract features from the frame data and the current pose estimate.
void updateCCDPoints(const vpHomogeneousMatrix &cMo)
void computeErrorAndInteractionMatrix(const vpHomogeneousMatrix &cMo)
void computeLocalStatistics(const vpImage< vpRGBa > &I, vpCCDStatistics &stats)
std::vector< double > m_hessianData
std::vector< vpColVector > m_gradients
std::vector< double > m_gradientData
double m_temporalSmoothingFac
Sum of local hessians.
std::vector< vpRBSilhouetteControlPoint > m_controlPoints
void initVVS(const vpRBFeatureTrackerInput &frame, const vpRBFeatureTrackerInput &previousFrame, const vpHomogeneousMatrix &cMo) VP_OVERRIDE
static const unsigned int BASE_SEED
vpMatrix m_hessian
Sum of local gradients.
std::vector< vpMatrix > m_hessians
bool m_useMask
Smoothing factor used to integrate data from the previous frame.
void changeScale()
To be called when the scale of the normal vectors is changed.
void computeVVSIter(const vpRBFeatureTrackerInput &frame, const vpHomogeneousMatrix &cMo, unsigned int iteration) VP_OVERRIDE
void onTrackingIterStart(const vpRBFeatureTrackerInput &, const vpHomogeneousMatrix &) VP_OVERRIDE
Method called when starting a tracking iteration.
void display(const vpCameraParameters &cam, const vpImage< unsigned char > &I, const vpImage< vpRGBa > &IRGB, const vpImage< unsigned char > &depth) const VP_OVERRIDE
Trackable silhouette point representation.
void buildSilhouettePoint(int n, int m, const double &Z, double orient, const vpColVector &normo, const vpHomogeneousMatrix &cMo, const vpHomogeneousMatrix &oMc, const vpCameraParameters &cam)
double getMaxMaskGradientAlongLine(const vpImage< float > &mask, int searchSize) const
Silhouette point simple candidate representation.
double Z
angle of the normal in the image.
vpColVector normal
Pixel coordinates of the silhouette point.
double orientation
Normal to the silhouette at point i,j, in world frame.
bool isSilhouette
Point depth.
unsigned char B
Blue component.
Definition vpRGBa.h:327
unsigned char R
Red component.
Definition vpRGBa.h:325
unsigned char G
Green component.
Definition vpRGBa.h:326
@ TUKEY
Tukey influence function.
Definition vpRobust.h:89
Implementation of a rotation matrix and operations on such kind of matrices.
vpHomogeneousMatrix cMo