Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpScale.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 * Median Absolute Deviation (MAD), MPDE, Mean shift kernel density
32 * estimation.
33 */
34
38
39#include <cmath> // std::fabs
40#include <limits> // numeric_limits
41#include <stdlib.h>
42#include <visp3/core/vpColVector.h>
43#include <visp3/core/vpMath.h>
44#include <visp3/core/vpScale.h>
45
46#define DEBUG_LEVEL2 0
47
50vpScale::vpScale() : bandwidth(0.02), dimension(1)
51{
52#if (DEBUG_LEVEL2)
53 std::cout << "vpScale constructor reached" << std::endl;
54#endif
55#if (DEBUG_LEVEL2)
56 std::cout << "vpScale constructor finished" << std::endl;
57#endif
58}
59
61vpScale::vpScale(double kernel_bandwidth, unsigned int dim) : bandwidth(kernel_bandwidth), dimension(dim)
62
63{
64#if (DEBUG_LEVEL2)
65 std::cout << "vpScale constructor reached" << std::endl;
66#endif
67#if (DEBUG_LEVEL2)
68 std::cout << "vpScale constructor finished" << std::endl;
69#endif
70}
71
72// Calculate the modes of the density for the distribution
73// and their associated errors
75{
76
77 unsigned int n = error.getRows() / dimension;
78 vpColVector density(n);
79 vpColVector density_gradient(n);
80 vpColVector mean_shift(n);
81
82 unsigned int increment = 1;
83
84 // choose smallest error as start point
85 unsigned int i = 0;
86 while (error[i] < 0 && error[i] < error[i + 1])
87 i++;
88
89 // Do mean shift until no shift
90 while (increment >= 1 && i < n) {
91 increment = 0;
92 density[i] = KernelDensity(error, i);
93 density_gradient[i] = KernelDensityGradient(error, i);
94 mean_shift[i] = vpMath::sqr(bandwidth) * density_gradient[i] / ((dimension + 2) * density[i]);
95
96 double tmp_shift = mean_shift[i];
97
98 // Do mean shift
99 while (tmp_shift > 0 && tmp_shift > error[i] - error[i + 1]) {
100 i++;
101 increment++;
102 tmp_shift -= (error[i] - error[i - 1]);
103 }
104 }
105
106 return error[i];
107}
108
109// Calculate the density of each point in the error vector
110// Requires ordered set of errors
111double vpScale::KernelDensity(vpColVector &error, unsigned int position)
112{
113
114 unsigned int n = error.getRows() / dimension;
115 double density = 0;
116 double Ke = 1;
117 unsigned int j = position;
118
119 vpColVector X(dimension);
120
121 // Use each error in the bandwidth to calculate
122 // the local density of error i
123 // First treat larger errors
124 // while(Ke !=0 && j<=n)
125 while (std::fabs(Ke) > std::numeric_limits<double>::epsilon() && j <= n) {
126 // Create vector of errors corresponding to each dimension of a feature
127 for (unsigned int i = 0; i < dimension; i++) {
128 X[i] = (error[position] - error[j]) / bandwidth;
129 position++;
130 j++;
131 }
132 position -= dimension; // reset position
133
135 density += Ke;
136 }
137
138 Ke = 1;
139 j = position;
140 // Then treat smaller errors
141 // while(Ke !=0 && j>=dimension)
142 while (std::fabs(Ke) > std::numeric_limits<double>::epsilon() && j >= dimension) {
143 // Create vector of errors corresponding to each dimension of a feature
144 for (unsigned int i = 0; i < dimension; i++) {
145 X[i] = (error[position] - error[j]) / bandwidth;
146 position++;
147 j--;
148 }
149 position -= dimension; // reset position
150
152 density += Ke;
153 }
154
155 density *= 1 / (n * bandwidth);
156
157 return density;
158}
159
160double vpScale::KernelDensityGradient(vpColVector &error, unsigned int position)
161{
162
163 unsigned int n = error.getRows() / dimension;
164 double density_gradient = 0;
165 double sum_delta = 0;
166 double delta = 0;
167
168 double inside_kernel = 1;
169 unsigned int j = position;
170 // Use each error in the bandwidth to calculate
171 // the local density gradient
172 // First treat larger errors than current
173 // while(inside_kernel !=0 && j<=n)
174 while (std::fabs(inside_kernel) > std::numeric_limits<double>::epsilon() && j <= n) {
175 delta = error[position] - error[j];
176 if (vpMath::sqr(delta / bandwidth) < 1) {
177 inside_kernel = 1;
178 sum_delta += error[j] - error[position];
179 j++;
180 }
181 else {
182 inside_kernel = 0;
183 }
184 }
185
186 inside_kernel = 1;
187 j = position;
188 // Then treat smaller errors than current
189 // while(inside_kernel !=0 && j>=dimension)
190 while (std::fabs(inside_kernel) > std::numeric_limits<double>::epsilon() && j >= dimension) {
191 delta = error[position] - error[j];
192 if (vpMath::sqr(delta / bandwidth) < 1) {
193 inside_kernel = 1;
194 sum_delta += error[j] - error[position];
195 j--;
196 }
197 else {
198 inside_kernel = 0;
199 }
200 }
201
202 density_gradient = KernelDensityGradient_EPANECHNIKOV(sum_delta, n);
203
204 return density_gradient;
205}
206
207// Epanechnikov_kernel for an d dimensional Euclidean space R^d
209{
210
211 double XtX = X * X;
212 double c; // Volume of an n dimensional unit sphere
213
214 switch (dimension) {
215 case 1:
216 c = 2;
217 break;
218 case 2:
219 c = M_PI;
220 break;
221 case 3:
222 c = 4 * M_PI / 3;
223 break;
224 default:
225 throw(
226 vpException(vpException::fatalError, "Error in vpScale::KernelDensityGradient_EPANECHNIKOV: wrong dimension"));
227 }
228
229 if (XtX < 1)
230 return 1 / (2 * c) * (dimension + 2) * (1 - XtX);
231 else
232 return 0;
233}
234
235// Epanechnikov_kernel for an d dimensional Euclidean space R^d
236double vpScale::KernelDensityGradient_EPANECHNIKOV(double sumX, unsigned int n)
237{
238
239 double c; // Volume of an n dimensional unit sphere
240
241 switch (dimension) {
242 case 1:
243 c = 2;
244 break;
245 case 2:
246 c = M_PI;
247 break;
248 case 3:
249 c = 4 * M_PI / 3;
250 break;
251 default:
252 throw(
253 vpException(vpException::fatalError, "Error in vpScale::KernelDensityGradient_EPANECHNIKOV: wrong dimension"));
254 }
255
256 return sumX * (dimension + 2) / (n * bandwidth * c * vpMath::sqr(bandwidth));
257}
258END_VISP_NAMESPACE
Implementation of column vector and the associated operations.
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ fatalError
Fatal error.
Definition vpException.h:72
static double sqr(double x)
Definition vpMath.h:203
double KernelDensity(vpColVector &error, unsigned int position)
Definition vpScale.cpp:111
double KernelDensityGradient_EPANECHNIKOV(double X, unsigned int n)
Definition vpScale.cpp:236
double KernelDensityGradient(vpColVector &error, unsigned int position)
Definition vpScale.cpp:160
double MeanShift(vpColVector &error)
Definition vpScale.cpp:74
vpScale()
Constructor.
Definition vpScale.cpp:50
double KernelDensity_EPANECHNIKOV(vpColVector &X)
Definition vpScale.cpp:208