ViSP  2.8.0
vpScale.cpp
1 /****************************************************************************
2  *
3  * $Id: vpScale.cpp 4312 2013-07-16 15:12:42Z ayol $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Median Absolute Deviation (MAD), MPDE, Mean shift kernel density estimation.
36  *
37  * Authors:
38  * Andrew Comport
39  *
40  *****************************************************************************/
41 
49 #include <visp/vpColVector.h>
50 #include <visp/vpMath.h>
51 #include <visp/vpScale.h>
52 #include <stdlib.h>
53 #include <cmath> // std::fabs
54 #include <limits> // numeric_limits
55 
56 #define DEBUG_LEVEL2 0
57 
58 
59 
60 
63 {
64 #if (DEBUG_LEVEL2)
65  std::cout << "vpScale constructor reached" << std::endl;
66 #endif
67  bandwidth = 0.02;
68  dimension = 1;
69  kernel_type = EPANECHNIKOV;
70 
71 #if (DEBUG_LEVEL2)
72  std::cout << "vpScale constructor finished" << std::endl;
73 #endif
74 
75 }
76 
78 vpScale::vpScale(double kernel_bandwidth,
79  int dimension=1, int kernel_type=EPANECHNIKOV)
80 {
81 #if (DEBUG_LEVEL2)
82  std::cout << "vpScale constructor reached" << std::endl;
83 #endif
84 
85  bandwidth = kernel_bandwidth;
86  this->dimension = (unsigned)dimension;
87  this->kernel_type = kernel_type;
88 
89 #if (DEBUG_LEVEL2)
90  std::cout << "vpScale constructor finished" << std::endl;
91 #endif
92 
93 }
94 
97 {
98 
99 }
100 
101 
102 
103 // Calculate the modes of the density for the distribution
104 // and their associated errors
105 double
107 {
108 
109  unsigned int n = error.getRows()/dimension;
110  vpColVector density(n);
111  vpColVector density_gradient(n);
112  vpColVector mean_shift(n);
113 
114  unsigned int increment=1;
115 
116  // choose smallest error as start point
117  unsigned int i=0;
118  while(error[i]<0 && error[i]<error[i+1])
119  i++;
120 
121  // Do mean shift until no shift
122  while(increment >= 1 && i<n)
123  {
124  increment=0;
125  density[i] = KernelDensity(error, i);
126  density_gradient[i] = KernelDensityGradient(error, i);
127  mean_shift[i]=vpMath::sqr(bandwidth)*density_gradient[i]/((dimension+2)*density[i]);
128 
129  double tmp_shift = mean_shift[i];
130 
131  // Do mean shift
132  while(tmp_shift>0 && tmp_shift>error[i]-error[i+1])
133  {
134  i++;
135  increment++;
136  tmp_shift-=(error[i]-error[i-1]);
137  }
138  }
139 
140  return error[i];
141 
142 }
143 
144 // Calculate the density of each point in the error vector
145 // Requires ordered set of errors
146 double
147 vpScale::KernelDensity(vpColVector &error, unsigned int position)
148 {
149 
150  unsigned int n = error.getRows()/dimension;
151  double density=0;
152  double Ke = 1;
153  unsigned int j=position;
154 
155  vpColVector X(dimension);
156 
157 
158  // Use each error in the bandwidth to calculate
159  // the local density of error i
160  // First treat larger errors
161  //while(Ke !=0 && j<=n)
162  while(std::fabs(Ke) > std::numeric_limits<double>::epsilon() && j<=n)
163  {
164  //Create vector of errors corresponding to each dimension of a feature
165  for(unsigned int i=0; i<dimension; i++)
166  {
167  X[i]=(error[position]-error[j])/bandwidth;
168  position++;
169  j++;
170  }
171  position-=dimension; // reset position
172 
174  density+=Ke;
175  }
176 
177  Ke = 1;
178  j=position;
179  // Then treat smaller errors
180  //while(Ke !=0 && j>=dimension)
181  while(std::fabs(Ke) > std::numeric_limits<double>::epsilon() && j>=dimension)
182  {
183  //Create vector of errors corresponding to each dimension of a feature
184  for(unsigned int i=0; i<dimension; i++)
185  {
186  X[i]=(error[position]-error[j])/bandwidth;
187  position++;
188  j--;
189  }
190  position-=dimension; // reset position
191 
193  density+=Ke;
194  }
195 
196  density*=1/(n*bandwidth);
197 
198  return density;
199 
200 }
201 
202 double
203 vpScale::KernelDensityGradient(vpColVector &error, unsigned int position)
204 {
205 
206  unsigned int n = error.getRows()/dimension;
207  double density_gradient=0;
208  double sum_delta=0;
209  double delta=0;
210  int nx=0;
211 
212  double inside_kernel = 1;
213  unsigned int j=position;
214  // Use each error in the bandwidth to calculate
215  // the local density gradient
216  // First treat larger errors than current
217  //while(inside_kernel !=0 && j<=n)
218  while(std::fabs(inside_kernel) > std::numeric_limits<double>::epsilon() && j<=n)
219  {
220  delta = error[position]-error[j];
221  if(vpMath::sqr(delta/bandwidth)<1)
222  {
223  inside_kernel = 1;
224  sum_delta+=error[j]-error[position];
225  j++;
226  nx++;
227  }
228  else
229  inside_kernel = 0;
230  }
231 
232  inside_kernel = 1;
233  j=position;
234  // Then treat smaller errors than current
235  //while(inside_kernel !=0 && j>=dimension)
236  while(std::fabs(inside_kernel) > std::numeric_limits<double>::epsilon() && j>=dimension)
237  {
238  delta = error[position]-error[j];
239  if(vpMath::sqr(delta/bandwidth)<1)
240  {
241  inside_kernel = 1;
242  sum_delta+=error[j]-error[position];
243  j--;
244  nx++;
245  }
246  else
247  inside_kernel = 0;
248  }
249 
250  density_gradient = KernelDensityGradient_EPANECHNIKOV(sum_delta, n);
251 
252 
253  return density_gradient;
254 
255 }
256 
257 
258 //Epanechnikov_kernel for an d dimensional Euclidian space R^d
259 double
261 {
262 
263  double XtX= X*X;
264  double c; // Volume of an n dimensional unit sphere
265 
266  switch (dimension)
267  {
268  case 1:
269  c = 2;
270  break;
271  case 2:
272  c = M_PI;
273  break;
274  case 3:
275  c = 4*M_PI/3;
276  break;
277  default:
278  std::cout << "ERROR in vpScale::Kernel_EPANECHNIKOV : wrong dimension" << std::endl;
279  exit(1);
280  }
281 
282  if(XtX < 1)
283  return 1/(2*c)*(dimension+2)*(1-XtX);
284  else
285  return 0;
286 
287 }
288 
289 
290 //Epanechnikov_kernel for an d dimensional Euclidian space R^d
291 double
293 {
294 
295  double c; // Volume of an n dimensional unit sphere
296 
297  switch (dimension)
298  {
299  case 1:
300  c = 2;
301  break;
302  case 2:
303  c = M_PI;
304  break;
305  case 3:
306  c = 4*M_PI/3;
307  break;
308  default:
309  std::cout << "ERROR in vpScale::Kernel_EPANECHNIKOV : wrong dimension" << std::endl;
310  exit(1);
311  }
312 
313  //return sumX*(dimension+2)/(n*pow(bandwidth, (double)dimension)*c*vpMath::sqr(bandwidth));
314  return sumX*(dimension+2)/(n*bandwidth*c*vpMath::sqr(bandwidth));
315 
316 }
317 
double KernelDensityGradient_EPANECHNIKOV(double X, unsigned int n)
Definition: vpScale.cpp:292
double KernelDensityGradient(vpColVector &error, unsigned int position)
Definition: vpScale.cpp:203
static double sqr(double x)
Definition: vpMath.h:106
virtual ~vpScale(void)
Destructor.
Definition: vpScale.cpp:96
Class that provides a data structure for the column vectors as well as a set of operations on these v...
Definition: vpColVector.h:72
double MeanShift(vpColVector &error)
Definition: vpScale.cpp:106
double KernelDensity(vpColVector &error, unsigned int position)
Definition: vpScale.cpp:147
unsigned int getRows() const
Return the number of rows of the matrix.
Definition: vpMatrix.h:157
vpScale()
Constructor.
Definition: vpScale.cpp:62
double KernelDensity_EPANECHNIKOV(vpColVector &X)
Definition: vpScale.cpp:260