segmentation
All Data Structures Namespaces Files Functions Variables Modules Pages
ms.cpp
1 /*******************************************************
2 
3  Mean Shift Analysis Library
4  =============================================
5 
6  The mean shift library is a collection of routines
7  that use the mean shift algorithm. Using this algorithm,
8  the necessary output will be generated needed
9  to analyze a given input set of data.
10 
11  MeanShift Base Class:
12  ====================
13 
14  The mean shift library of routines is realized
15  via the creation of a MeanShift base class. This class
16  provides a mechanism for calculating the mean shift vector
17  at a specified data point, using an arbitrary N-dimensional
18  data set, and a user-defined kernel.
19 
20  For image processing the mean shift base class also allows
21  for the definition of a data set that is on a two-dimensional
22  lattice. The amount of time needed to compute the mean shift
23  vector using such a data set is much less than that of an
24  arbitrary one. Because images usually contain many data points,
25  defining the image input data points as being on a lattice
26  greatly improves computation time and makes algorithms such
27  as image filtering practical.
28 
29  The definition of the MeanShift class is provided below. Its
30  prototype is provided in 'ms.h'.
31 
32 The theory is described in the papers:
33 
34  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
35  space analysis.
36 
37  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
38 
39 and they are is available at:
40  http://www.caip.rutgers.edu/riul/research/papers/
41 
42 Implemented by Chris M. Christoudias, Bogdan Georgescu
43 ********************************************************/
44 
45 
46 //Include Needed Libraries
47 
48 #include "segm/ms.h"
49 #include <string.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <math.h>
53 
54 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
55 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
56 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ PUBLIC METHODS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
57 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
58 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
59 
60  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
61  /*** Constructor/Destructor ***/
62  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
63 
64 /*******************************************************/
65 /*Class Constructor */
66 /*******************************************************/
67 /*Post: */
68 /* The MeanShift class has been properly */
69 /* initialized. */
70 /*******************************************************/
71 
72 MeanShift::MeanShift( void )
73 {
74 
75  //intialize input data set parameters...
76  P = NULL;
77  L = 0;
78  N = 0;
79  kp = 0;
80 
81  //initialize input data set storage structures...
82  data = NULL;
83 
84  //initialize input data set kd-tree
85  root = NULL;
86  forest = NULL;
87  range = NULL;
88 
89  //intialize lattice structure...
90  height = 0;
91  width = 0;
92 
93  //intialize kernel strucuture...
94  h = NULL;
95  kernel = NULL;
96  w = NULL;
97  offset = NULL;
98  increment = NULL;
99  uniformKernel = false;
100 
101  //initialize weight function linked list...
102  head = cur = NULL;
103 
104  //intialize mean shift processing data structures...
105  uv = NULL;
106 
107  //set lattice weight map to null
108  weightMap = NULL;
109 
110  //indicate that the lattice weight map is undefined
111  weightMapDefined = false;
112 
113  //allocate memory for error message buffer...
114  ErrorMessage = new char [256];
115 
116  //initialize error status to OKAY
117  ErrorStatus = EL_OKAY;
118 
119  //Initialize class state...
120  class_state.INPUT_DEFINED = false;
121  class_state.KERNEL_DEFINED = false;
122  class_state.LATTICE_DEFINED = false;
123  class_state.OUTPUT_DEFINED = false;
124 
125 }
126 
127 /*******************************************************/
128 /*Class Destructor */
129 /*******************************************************/
130 /*Post: */
131 /* The MeanShift class has been properly */
132 /* destroyed. */
133 /*******************************************************/
134 
135 MeanShift::~MeanShift( void )
136 {
137  delete [] ErrorMessage;
138  if (weightMap)
139  {
140  delete [] weightMap;
141  }
142 
143  //de-allocate memory used to store
144  //user defined weight functions
145  ClearWeightFunctions();
146 
147  //de-allocate memory used for kernel
148  DestroyKernel();
149 
150  //de-allocate memory used for input
151  ResetInput();
152 
153 }
154 
155  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
156  /*** Creation/Initialization of Mean Shift Kernel ***/
157  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
158 
159 /*******************************************************/
160 /*Define Kernel */
161 /*******************************************************/
162 /*Creats custom user defined Kernel to be used by the */
163 /*mean shift procedure. */
164 /*******************************************************/
165 /*Pre: */
166 /* - kernel is an array of kernelTypes specifying */
167 /* the type of kernel to be used on each sub- */
168 /* space of the input data set x */
169 /* - h is the set of bandwidths used to define the*/
170 /* the search window */
171 /* - P is a one dimensional array of integers of */
172 /* size kp, that specifies the dimension of each*/
173 /* subspace of the input data set x */
174 /* - kp is the total number of subspaces used to */
175 /* the input data set x */
176 /*Post: */
177 /* - the custom kernel has been created for use */
178 /* by the mean shift procedure. */
179 /*******************************************************/
180 
181 void MeanShift::DefineKernel(kernelType *kernel_, float *h_, int *P_, int kp_)
182 {
183 
184  // Declare variables
185  int i, kN;
186 
187  //if a kernel has already been created then destroy it
188  if(kp)
189  DestroyKernel();
190 
191  //Obtain kp...
192  if((kp = kp_) <= 0)
193  {
194  ErrorHandler("MeanShift", "CreateKernel", "Subspace count (kp) is zero or negative.");
195  return;
196  }
197 
198  //Allocate memory for h, P, kernel, offset, and increment
199  if((!(P = new int [kp]))||(!(h = new float [kp]))||(!(kernel = new kernelType [kp]))||
200  (!(offset = new float [kp]))||(!(increment = new double [kp])))
201  {
202  ErrorHandler("MeanShift", "CreateKernel", "Not enough memory available to create kernel.");
203  return;
204  }
205 
206  //Populate h, P and kernel, also use P to calculate
207  //the dimension (N_) of the potential input data set x
208  kN = 0;
209  for(i = 0; i < kp; i++)
210  {
211  if((h[i] = h_[i]) <= 0)
212  {
213  ErrorHandler("MeanShift", "CreateKernel", "Negative or zero valued bandwidths are prohibited.");
214  return;
215  }
216  if((P[i] = P_[i]) <= 0)
217  {
218  ErrorHandler("MeanShift", "CreateKernel", "Negative or zero valued subspace dimensions are prohibited.");
219  return;
220  }
221  kernel[i] = kernel_[i];
222  kN += P[i];
223  }
224 
225  //Allocate memory for range vector and uv using N_
226  if((!(range = new float [2*kN]))||(!(uv = new double [kN])))
227  {
228  ErrorHandler("MeanShift", "CreateKernel", "Not enough memory available to create kernel.");
229  return;
230  }
231 
232  // Generate weight function lookup table
233  // using above information and user
234  // defined weight function list
235  generateLookupTable();
236 
237  //check for errors
238  if(ErrorStatus == EL_ERROR)
239  return;
240 
241  //indicate that the kernel has been defined
242  class_state.KERNEL_DEFINED = true;
243 
244  //done.
245  return;
246 
247 }
248 
249 /*******************************************************/
250 /*Add Weight Function */
251 /*******************************************************/
252 /*Adds a weight function to the Mean Shift class to be */
253 /*used by the mean shift procedure */
254 /*******************************************************/
255 /*Pre: */
256 /* - g(u) is the normalized weight function with */
257 /* respect to u = (norm(x-xi))^2/h^2 */
258 /* - sampleNumber is the number of samples to be */
259 /* taken of g(u) over halfWindow interval */
260 /* - halfWindow is the radius of g(u) such that */
261 /* g(u) is defined for 0 <= u <= halfWindow */
262 /* - subspace is the subspace number for which */
263 /* g(u) is to be applied during the mean shift */
264 /* procedure. */
265 /*Post: */
266 /* - g(u) has been added to the Mean Shift class */
267 /* private data structure to be used by the */
268 /* mean shift procedure. */
269 /* - if a weight function has already been spec- */
270 /* ified for the specified subspace, the weight */
271 /* function for this subspace has been replaced.*/
272 /*******************************************************/
273 
274 void MeanShift::AddWeightFunction(double g(double), float halfWindow, int sampleNumber, int subspace)
275 {
276 
277  // Declare Variables
278  int i;
279  double increment;
280 
281  // Search to see if a weight function has already been
282  // defined for specified subspace, if not then insert
283  // into the head of the weight function list, otherwise
284  // replace entry
285 
286  // Perform Search
287  cur = head;
288  while((cur)&&(cur->subspace != subspace))
289  cur = cur->next;
290 
291  // Entry Exists - Replace It!
292  // Otherwise insert at the head of the the weight functon list
293  if(cur)
294  delete cur->w;
295  else
296  {
297  cur = new userWeightFunct;
298  cur->next = head;
299  head = cur;
300  }
301 
302  // Generate lookup table
303  increment = halfWindow/(double)(sampleNumber);
304 
305  cur->w = new double [sampleNumber+1];
306  for(i = 0; i <= sampleNumber; i++)
307  cur->w[i] = g((double)(i*increment));
308 
309  // Set weight function parameters
310  cur->halfWindow = halfWindow;
311  cur->sampleNumber = sampleNumber;
312  cur->subspace = subspace;
313 
314  //done.
315  return;
316 
317 }
318 
319 /*******************************************************/
320 /*Clear Weight Functions */
321 /*******************************************************/
322 /*Clears user defined weight from the Mean Shift class */
323 /*private data structure. */
324 /*******************************************************/
325 /*Post: */
326 /* - all user defined weight functions ahve been */
327 /* cleared from the private data structure of */
328 /* the mean shift class. */
329 /*******************************************************/
330 
331 void MeanShift::ClearWeightFunctions( void )
332 {
333 
334  while(head)
335  {
336  delete head->w;
337  cur = head;
338  head = head->next;
339  delete cur;
340  }
341 
342 }
343 
344  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
345  /*** Input Data Set Declaration ***/
346  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
347 
348 /*******************************************************/
349 /*Define Input */
350 /*******************************************************/
351 /*Uploads input data set x into the mean shift class. */
352 /*******************************************************/
353 /*Pre: */
354 /* - x is a one dimensional array of L N-dimen- */
355 /* ional data points. */
356 /*Post: */
357 /* - x has been uploaded into the mean shift */
358 /* class. */
359 /* - the height and width of a previous data set */
360 /* has been undefined. */
361 /*******************************************************/
362 
363 void MeanShift::DefineInput(float *x, int L_, int N_)
364 {
365 
366 
367  //if input data is defined de-allocate memory, and
368  //re-initialize the input data structure
369  if((class_state.INPUT_DEFINED)||(class_state.LATTICE_DEFINED))
370  ResetInput();
371 
372  //make sure x is not NULL...
373  if(!x)
374  {
375  ErrorHandler("MeanShift", "UploadInput", "Input data set is NULL.");
376  return;
377  }
378 
379  //Obtain L and N
380  if(((L = L_) <= 0)||((N = N_) <= 0))
381  {
382  ErrorHandler("MeanShift", "UploadInput", "Input data set has negative or zero length or dimension.");
383  return;
384  }
385 
386  //Allocate memory for data
387  if(!(data = new float [L*N]))
388  {
389  ErrorHandler("MeanShift", "UploadInput", "Not enough memory.");
390  return;
391  }
392 
393  //Allocate memory for input data set, and copy
394  //x into the private data members of the mean
395  //shift class
396  InitializeInput(x);
397 
398  //check for errors
399  if(ErrorStatus == EL_ERROR)
400  return;
401 
402  // Load x into the MeanShift object using
403  // using a kd-tree, resulting in better
404  // range searching of the input data points
405  // x - also upload window centers into
406  // msRawData
407  CreateBST();
408 
409  //indicate that the input has been recently defined
410  class_state.INPUT_DEFINED = true;
411  class_state.LATTICE_DEFINED = false;
412  class_state.OUTPUT_DEFINED = false;
413 
414  //done.
415  return;
416 
417 }
418 
419 /*******************************************************/
420 /*Define Lattice */
421 /*******************************************************/
422 /*Defines the height and width of the input lattice. */
423 /*******************************************************/
424 /*Pre: */
425 /* - ht is the height of the lattice */
426 /* - wt is the width of the lattice */
427 /*Post: */
428 /* - the height and width of the lattice has been */
429 /* specified. */
430 /* - if a data set is presently loaded into the */
431 /* mean shift class, an error is flagged if the */
432 /* number of elements in that data set does not */
433 /* equal the product ht*wt. */
434 /*******************************************************/
435 
436 void MeanShift::DefineLInput(float *x, int ht, int wt, int N_)
437 {
438 
439  //if input data is defined de-allocate memory, and
440  //re-initialize the input data structure
441  if((class_state.INPUT_DEFINED)||(class_state.LATTICE_DEFINED))
442  ResetInput();
443 
444  //Obtain lattice height and width
445  if(((height = ht) <= 0)||((width = wt) <= 0))
446  {
447  ErrorHandler("MeanShift", "DefineLInput", "Lattice defined using zero or negative height and/or width.");
448  return;
449  }
450 
451  //Obtain input data dimension
452  if((N = N_) <= 0)
453  {
454  ErrorHandler("MeanShift", "DefineInput", "Input defined using zero or negative dimension.");
455  return;
456  }
457 
458  //compute the data length, L, of input data set
459  //using height and width
460  L = height*width;
461 
462  //Allocate memory for input data set, and copy
463  //x into the private data members of the mean
464  //shift class
465  InitializeInput(x);
466 
467  //check for errors
468  if(ErrorStatus == EL_ERROR)
469  return;
470 
471  //allocate memory for weight map
472  if(!(weightMap = new float [L]))
473  {
474  ErrorHandler("MeanShift", "InitializeInput", "Not enough memory.");
475  return;
476  }
477 
478  //initialize weightMap to an array of zeros
479  memset(weightMap, 0, L*(sizeof(float)));
480 
481  //Indicate that a lattice input has recently been
482  //defined
483  class_state.LATTICE_DEFINED = true;
484  class_state.INPUT_DEFINED = false;
485  class_state.OUTPUT_DEFINED = false;
486 
487  //done.
488  return;
489 
490 }
491 
492 /*******************************************************/
493 /*Set Lattice Weight Map */
494 /*******************************************************/
495 /*Populates the lattice weight map with specified */
496 /*weight values. */
497 /*******************************************************/
498 /*Pre: */
499 /* - wm is a floating point array of size L */
500 /* specifying for each data point a weight */
501 /* value */
502 /*Post: */
503 /* - wm has been used to populate the lattice */
504 /* weight map. */
505 /*******************************************************/
506 
507 void MeanShift::SetLatticeWeightMap(float *wm)
508 {
509  //make sure wm is not NULL
510  if(!wm)
511  {
512  ErrorHandler("MeanShift", "SetWeightMap", "Specified weight map is NULL.");
513  return;
514  }
515 
516  //populate weightMap using wm
517  int i;
518  for(i = 0; i < L; i++)
519  weightMap[i] = wm[i];
520 
521  //indicate that a lattice weight map has been specified
522  weightMapDefined = true;
523 
524  //done.
525  return;
526 
527 }
528 
529 
530 /*******************************************************/
531 /*Remove Lattice Weight Map */
532 /*******************************************************/
533 /*Removes the lattice weight map. */
534 /*******************************************************/
535 /*Post: */
536 /* - the lattice weight map has been removed. */
537 /* - if a weight map did not exist NO error is */
538 /* flagged. */
539 /*******************************************************/
540 
541 void MeanShift::RemoveLatticeWeightMap(void)
542 {
543 
544  //only remove weight map if it exists, otherwise
545  //do nothing...
546  if(weightMapDefined)
547  {
548  //set values of lattice weight map to zero
549  memset(weightMap, 0, L*sizeof(float));
550 
551  //indicate that a lattice weight map is no longer
552  //defined
553  weightMapDefined = false;
554  }
555 
556  //done.
557  return;
558 
559 }
560 
561 
562  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
563  /*** Mean Shift Operations ***/
564  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
565 
566 /*******************************************************/
567 /*Mean Shift Vector */
568 /*******************************************************/
569 /*Calculates the mean shift vector at a specified data */
570 /*point yk. */
571 /*******************************************************/
572 /*Pre: */
573 /* - a kernel has been created */
574 /* - a data set has been uploaded */
575 /* - Mh is an N dimensional mean shift vector */
576 /* - yk is an N dimensional data point */
577 /*Post: */
578 /* - the mean shift vector at yk has been */
579 /* calculated and stored in and returned by Mh. */
580 /*******************************************************/
581 
582 void MeanShift::msVector(double *Mh, double *yk)
583 {
584 
585  //make sure that Mh and/or yk are not NULL...
586  if((!Mh)||(!yk))
587  {
588  ErrorHandler("MeanShift", "msVector", "Invalid argument(s) passed to this method.");
589  return;
590  }
591 
592  //make sure that a kernel has been created, data has
593  //been uploaded, and that they are consistent with one
594  //another...
595  classConsistencyCheck(N, false);
596 
597  //calculate mean shift vector at yk using created kernel
598  //and uploaded data set
599  MSVector(Mh, yk);
600 
601  //done.
602  return;
603 
604 }
605 
606 /*******************************************************/
607 /*Lattice Mean Shift Vector */
608 /*******************************************************/
609 /*Calculates the mean shift vector at a specified data */
610 /*point yk, assuming that the data set exhists on a */
611 /*height x width two dimensional lattice. */
612 /*******************************************************/
613 /*Pre: */
614 /* - a kernel has been created */
615 /* - a data set has been uploaded */
616 /* - the height and width of the lattice has been */
617 /* specified using method DefineLattice() */
618 /* - Mh is an N dimensional mean shift vector */
619 /* - yk is an N dimensional data point */
620 /*Post: */
621 /* - the mean shift vector at yk has been */
622 /* calculated and stored in and returned by Mh. */
623 /* - Mh was calculated using the defined input */
624 /* lattice. */
625 /*******************************************************/
626 
627 void MeanShift::latticeMSVector(double *Mh, double *yk)
628 {
629 
630  //make sure that Mh and/or yk are not NULL...
631  if((!Mh)||(!yk))
632  {
633  ErrorHandler("MeanShift", "lmsVector", "Invalid argument(s) passed to this method.");
634  return;
635  }
636 
637  //make sure that a kernel has been created, data has
638  //been uploaded, and that they are consistent with one
639  //another...
640  classConsistencyCheck(N+2, true);
641 
642  //calculate mean shift vector at yk using created kernel
643  //and uploaded data set
644  LatticeMSVector(Mh, yk);
645 
646  //done.
647  return;
648 
649 }
650 
651 /*******************************************************/
652 /*Find Mode */
653 /*******************************************************/
654 /*Calculates the mode of a specified data point yk. */
655 /*******************************************************/
656 /*Pre: */
657 /* - a kernel has been created */
658 /* - a data set has been uploaded */
659 /* - mode is the N dimensional mode of the N-dim- */
660 /* ensional data point yk */
661 /*Post: */
662 /* - the mode of yk has been calculated and */
663 /* stored in mode. */
664 /*******************************************************/
665 
666 void MeanShift::FindMode(double *mode, double *yk)
667 {
668 
669  //make sure that mode and/or yk are not NULL...
670  if((!mode)||(!yk))
671  {
672  ErrorHandler("MeanShift", "FindMode", "Invalid argument(s) passed to this method.");
673  return;
674  }
675 
676  //make sure that a kernel has been created, data has
677  //been uploaded, and that they are consistent with one
678  //another...
679  classConsistencyCheck(N, false);
680 
681  //allocate memory for Mh
682  double *Mh = new double [N];
683 
684  //copy yk into mode
685  int i;
686  for(i = 0; i < N; i++)
687  mode[i] = yk[i];
688 
689  //calculate mean shift vector at yk
690  MSVector(Mh, yk);
691 
692  //calculate mvAbs = |Mh|^2
693  double mvAbs = 0;
694  for(i = 0; i < N; i++)
695  mvAbs += Mh[i]*Mh[i];
696 
697  //shift mode until convergence (mvAbs = 0)...
698  int iterationCount = 1;
699  while((mvAbs >= EPSILON)&&(iterationCount < LIMIT))
700  {
701  //shift mode...
702  for(i = 0; i < N; i++)
703  mode[i] += Mh[i];
704 
705  //re-calculate mean shift vector at new
706  //window location have center defined by
707  //mode
708  MSVector(Mh, mode);
709 
710  //calculate mvAbs = |Mh|^2
711  mvAbs = 0;
712  for(i = 0; i < N; i++)
713  mvAbs += Mh[i]*Mh[i];
714 
715  //increment interation count...
716  iterationCount++;
717 
718  }
719 
720  //shift mode...
721  for(i = 0; i < N; i++)
722  mode[i] += Mh[i];
723 
724  //de-allocate memory
725  delete [] Mh;
726 
727  //done.
728  return;
729 
730 }
731 
732 /*******************************************************/
733 /*Find Lattice Mode */
734 /*******************************************************/
735 /*Calculates the mode of a specified data point yk, */
736 /*assuming that the data set exhists on a height x */
737 /*width two dimensional lattice. */
738 /*******************************************************/
739 /*Pre: */
740 /* - a kernel has been created */
741 /* - a data set has been uploaded */
742 /* - the height and width of the lattice has been */
743 /* specified using method DefineLattice() */
744 /* - mode is the N dimensional mode of the N-dim- */
745 /* ensional data point yk */
746 /*Post: */
747 /* - the mode of yk has been calculated and */
748 /* stored in mode. */
749 /* - mode was calculated using the defined input */
750 /* lattice. */
751 /*******************************************************/
752 
753 void MeanShift::FindLMode(double *mode, double *yk)
754 {
755 
756  //make sure that mode and/or yk are not NULL...
757  if((!mode)||(!yk))
758  {
759  ErrorHandler("MeanShift", "FindLMode", "Invalid argument(s) passed to this method.");
760  return;
761  }
762 
763  //make sure the lattice height and width have been defined...
764  if(!height)
765  {
766  ErrorHandler("MeanShift", "FindLMode", "Lattice height and width is undefined.");
767  return;
768  }
769 
770  //make sure that a kernel has been created, data has
771  //been uploaded, and that they are consistent with one
772  //another...
773  classConsistencyCheck(N+2, true);
774 
775  //define gridN
776  int gridN = N+2;
777 
778  //allocate memory for Mh
779  double *Mh = new double [gridN];
780 
781  //copy yk into mode
782  int i;
783  for(i = 0; i < gridN; i++)
784  mode[i] = yk[i];
785 
786  //calculate mean shift vector at yk
787  LatticeMSVector(Mh, mode);
788 
789  //calculate mvAbs = |Mh|^2
790  double mvAbs = 0;
791  for(i = 0; i < gridN; i++)
792  mvAbs += Mh[i]*Mh[i];
793 
794  //shift mode until convergence (mvAbs = 0)...
795  int iterationCount = 1;
796  while((mvAbs >= EPSILON)&&(iterationCount < LIMIT))
797  {
798  //shift mode...
799  for(i = 0; i < gridN; i++)
800  mode[i] += Mh[i];
801 
802  //re-calculate mean shift vector at new
803  //window location have center defined by
804  //mode
805  LatticeMSVector(Mh, mode);
806 
807  //calculate mvAbs = |Mh|^2
808  mvAbs = 0;
809  for(i = 0; i < gridN; i++)
810  mvAbs += Mh[i]*Mh[i];
811 
812  //increment interation count...
813  iterationCount++;
814 
815  }
816 
817  //shift mode...
818  for(i = 0; i < gridN; i++)
819  mode[i] += Mh[i];
820 
821  //de-allocate memory
822  delete [] Mh;
823 
824  //done.
825  return;
826 
827 }
828 
829 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
830 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
831 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ PROTECTED METHODS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
832 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
833 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
834 
835  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
836  /* Mean Shift: Using kd-Tree */
837  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
838 
839 /*******************************************************/
840 /*Mean Shift Vector */
841 /*******************************************************/
842 /*Computes the mean shift vector at a window location */
843 /*yk using input data set x using a custom, user defin-*/
844 /*ed kernel. */
845 /*******************************************************/
846 /*Pre: */
847 /* - input data has been uploaded into the private*/
848 /* data members of the MeanShift class */
849 /* - a window center yk has been defined */
850 /* - uniformKernel indicates the which type of */
851 /* kernel to be used by this procedure: uniform */
852 /* or general */
853 /*Post: */
854 /* - the mean shift vector calculated at yk */
855 /* using a either a custom, user defined kernel */
856 /* or a uniform kernel is returned */
857 /*******************************************************/
858 
859 void MeanShift::MSVector(double *Mh_ptr, double *yk_ptr)
860 {
861 
862  // Declare Variables
863  int i,j;
864 
865  // Initialize mean shift vector
866  for(i = 0; i < N; i++)
867  Mh_ptr[i] = 0;
868 
869  // Initialize wsum to zero, the sum of the weights of each
870  // data point found to lie within the search window (sphere)
871  wsum = 0;
872 
873  // Build Range Vector using h[i] and yk
874 
875  int s = 0;
876 
877  // The flag uniformKernel is used to determine which
878  // kernel function is to be used in the calculation
879  // of the mean shift vector
880  if(uniformKernel)
881  {
882  for(i = 0; i < kp; i++)
883  {
884  for(j = 0; j < P[i]; j++)
885  {
886  range[2*(s+j) ] = (float)(yk_ptr[s+j] - h[i]);
887  range[2*(s+j)+1] = (float)(yk_ptr[s+j] + h[i]);
888  }
889  s += P[i];
890  }
891  }
892  else
893  {
894  for(i = 0; i < kp; i++)
895  {
896  for(j = 0; j < P[i]; j++)
897  {
898  range[2*(s+j) ] = (float)(yk_ptr[s+j] - h[i]*float(sqrt(offset[i])));
899  range[2*(s+j)+1] = (float)(yk_ptr[s+j] + h[i]*float(sqrt(offset[i])));
900  }
901  s += P[i];
902  }
903  }
904 
905  // Traverse through the data set x, performing the
906  // weighted sum of each point xi that lies within
907  // the search window (sphere) using a general,
908  // user defined kernel or uniform kernel depending
909  // on the uniformKernel flag
910  if(uniformKernel)
911  uniformSearch(root, 0, Mh_ptr, yk_ptr);
912  else
913  generalSearch(root, 0, Mh_ptr, yk_ptr);
914 
915  // Calculate the mean shift vector using Mh and wsum
916  for(i = 0; i < N; i++)
917  {
918 
919  // Divide Sum by wsum
920  Mh_ptr[i] /= wsum;
921 
922  // Calculate mean shift vector: Mh(yk) = y(k+1) - y(k)
923  Mh_ptr[i] -= yk_ptr[i];
924 
925  }
926 
927  //done.
928  return;
929 
930 }
931 
932  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
933  /* Mean Shift: Using Lattice */
934  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
935 
936 /*******************************************************/
937 /*Lattice Mean Shift Vector */
938 /*******************************************************/
939 /*Computes the mean shift vector at a specfied window */
940 /*yk using the lattice data structure. */
941 /*******************************************************/
942 /*Pre: */
943 /* - Mh_ptr and yh_ptr are arrays of doubles con- */
944 /* aining N+2 elements */
945 /* - Mh_ptr is the mean shift vector calculated */
946 /* at window center yk_ptr */
947 /*Post: */
948 /* - the mean shift vector at the window center */
949 /* pointed to by yk_ptr has been calculated and */
950 /* stored in the memory location pointed to by */
951 /* Mh_ptr */
952 /*******************************************************/
953 
954 void MeanShift::LatticeMSVector(double *Mh_ptr, double *yk_ptr)
955 {
956 
957  // Initialize mean shift vector
958  register int i;
959  for(i = 0; i < N+2; i++)
960  Mh_ptr[i] = 0;
961 
962  // Initialize wsum
963  wsum = 0;
964 
965  // Perform lattice search summing
966  // all the points that lie within the search
967  // window defined using the kernel specified
968  //by uniformKernel
969  if(uniformKernel)
970  uniformLSearch(Mh_ptr, yk_ptr);
971  else
972  generalLSearch(Mh_ptr, yk_ptr);
973 
974  // Compute mean shift vector using sum computed
975  // by lattice search, wsum, and yk_ptr:
976  // Mh = Mh/wsum - yk_ptr
977 
978  if (wsum > 0)
979  {
980  for(i = 0; i < N+2; i++)
981  Mh_ptr[i] = Mh_ptr[i]/wsum - yk_ptr[i];
982  }
983  else
984  {
985  for(i = 0; i < N+2; i++)
986  Mh_ptr[i] = 0;
987  }
988 
989  // done.
990  return;
991 
992 }
993 
994 /*******************************************************/
995 /*Optimized Lattice Mean Shift Vector */
996 /*******************************************************/
997 /*Computes the mean shift vector at a specfied window */
998 /*yk using the lattice data structure. Also the points */
999 /*that lie within the window are stored into the basin */
1000 /*of attraction structure used by the optimized mean */
1001 /*shift algorithms. */
1002 /*******************************************************/
1003 /*Pre: */
1004 /* - Mh_ptr and yh_ptr are arrays of doubles con- */
1005 /* aining N+2 elements */
1006 /* - Mh_ptr is the mean shift vector calculated */
1007 /* at window center yk_ptr */
1008 /*Post: */
1009 /* - the mean shift vector at the window center */
1010 /* pointed to by yk_ptr has been calculated and */
1011 /* stored in the memory location pointed to by */
1012 /* Mh_ptr */
1013 /* - the data points lying within h of of yk_ptr */
1014 /* have been stored into the basin of attract- */
1015 /* ion data structure. */
1016 /*******************************************************/
1017 
1018 void MeanShift::OptLatticeMSVector(double *Mh_ptr, double *yk_ptr)
1019 {
1020 
1021  // Initialize mean shift vector
1022  register int i;
1023  for(i = 0; i < N+2; i++)
1024  Mh_ptr[i] = 0;
1025 
1026  // Initialize wsum
1027  wsum = 0;
1028 
1029  // Perform lattice search summing
1030  // all the points that lie within the search
1031  // window defined using the kernel specified
1032  //by uniformKernel
1033  if(uniformKernel)
1034  optUniformLSearch(Mh_ptr, yk_ptr);
1035  else
1036  optGeneralLSearch(Mh_ptr, yk_ptr);
1037 
1038  // Compute mean shift vector using sum computed
1039  // by lattice search, wsum, and yk_ptr:
1040  // Mh = Mh/wsum - yk_ptr
1041 
1042  if (wsum > 0)
1043  {
1044  for(i = 0; i < N+2; i++)
1045  Mh_ptr[i] = Mh_ptr[i]/wsum - yk_ptr[i];
1046  } else
1047  {
1048  for (i=0; i< N+2; i++)
1049  Mh_ptr[i] = 0;
1050  }
1051 
1052  // done.
1053  return;
1054 
1055 }
1056 
1057  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
1058  /*** Kernel-Input Data Consistency ***/
1059  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
1060 
1061 /*******************************************************/
1062 /*Class Consistency Check */
1063 /*******************************************************/
1064 /*Checks the state of the class prior to the applicat- */
1065 /*ion of mean shift. */
1066 /*******************************************************/
1067 /*Pre: */
1068 /* - iN is the specified dimension of the input, */
1069 /* iN = N for a general input data set, iN = N */
1070 /* + 2 for a input set defined using a lattice */
1071 /*Post: */
1072 /* - if the kernel has not been created, an input */
1073 /* has not been defined and/or the specified */
1074 /* input dimension (iN) does not match that of */
1075 /* the kernel a fatal error is flagged. */
1076 /*******************************************************/
1077 
1078 void MeanShift::classConsistencyCheck(int iN, bool usingLattice)
1079 {
1080 
1081  //make sure that kernel has been created...
1082  if(class_state.KERNEL_DEFINED == false)
1083  {
1084  ErrorHandler("MeanShift", "classConsistencyCheck", "Kernel not created.");
1085  return;
1086  }
1087 
1088  //make sure input data set has been loaded into mean shift object...
1089  if((class_state.INPUT_DEFINED == false)&&(!usingLattice))
1090  {
1091  ErrorHandler("MeanShift", "classConsistencyCheck", "No input data specified.");
1092  return;
1093  }
1094 
1095  //make sure that the lattice is defined if it is being used
1096  if((class_state.LATTICE_DEFINED == false)&&(usingLattice))
1097  {
1098  ErrorHandler("MeanShift", "classConsistencyCheck", "Latice not created.");
1099  return;
1100  }
1101 
1102  //make sure that dimension of the kernel and the input data set
1103  //agree
1104 
1105  //calculate dimension of kernel (kN)
1106  int i, kN = 0;
1107  for(i = 0; i < kp; i++)
1108  kN += P[i];
1109 
1110  //perform comparison...
1111  if(iN != kN)
1112  {
1113  ErrorHandler("MeanShift", "classConsitencyCheck", "Kernel dimension does not match defined input data dimension.");
1114  return;
1115  }
1116 
1117  //done.
1118  return;
1119 
1120 }
1121 
1122  /*/\/\/\/\/\/\/\/\/\/\/\/\/\*/
1123  /*** Class Error Handler ***/
1124  /*\/\/\/\/\/\/\/\/\/\/\/\/\/*/
1125 
1126 /*******************************************************/
1127 /*Error Handler */
1128 /*******************************************************/
1129 /*Class error handler. */
1130 /*******************************************************/
1131 /*Pre: */
1132 /* - className is the name of the class that fl- */
1133 /* agged an error */
1134 /* - methodName is the name of the method that */
1135 /* flagged an error */
1136 /* - errmsg is the error message given by the */
1137 /* calling function */
1138 /*Post: */
1139 /* - the error message errmsg is flagged on beh- */
1140 /* ave of method methodName belonging to class */
1141 /* className: */
1142 /* */
1143 /* (1) ErrorMessage has been updated with the */
1144 /* appropriate error message using the arg- */
1145 /* ments passed to this method. */
1146 /* (2) ErrorStatus is set to ERROR */
1147 /* (ErrorStatus = 1) */
1148 /*******************************************************/
1149 
1150 void MeanShift::ErrorHandler(const char *className, const char *methodName, const char* errmsg)
1151 {
1152 
1153  //store trace into error message
1154  strcpy(ErrorMessage, className);
1155  strcat(ErrorMessage, "::");
1156  strcat(ErrorMessage, methodName);
1157  strcat(ErrorMessage, " Error: ");
1158 
1159  //store message into error message
1160  strcat(ErrorMessage, errmsg);
1161 
1162  //set error status to ERROR
1163  ErrorStatus = EL_ERROR;
1164 
1165 
1166 }
1167 
1168 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
1169 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
1170 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ PRIVATE METHODS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
1171 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
1172 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
1173 
1174  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
1175  /*** Kernel Creation/Manipulation ***/
1176  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
1177 
1178 /*******************************************************/
1179 /*Generate Lookup Table */
1180 /*******************************************************/
1181 /*A weight function look up table is generated. */
1182 /*******************************************************/
1183 /*Pre: */
1184 /* - kernel is an array of kernelTypes specifying */
1185 /* the type of kernel to be used on each sub- */
1186 /* space of the input data set x */
1187 /* - kp is the total number of subspaces used to */
1188 /* the input data set x */
1189 /* - the above information has been pre-loaded */
1190 /* into the MeanShift class private members */
1191 /*Post: */
1192 /* - a lookup table is generated for the weight */
1193 /* function of the resulting kernel */
1194 /* - uniformKernel is set to true if the kernel */
1195 /* to be used is uniform, false is returned */
1196 /* otherwise */
1197 /* - if a user defined weight function is requred */
1198 /* for a given subspace but not defined in the */
1199 /* user defined weight function list, an error */
1200 /* is flagged and the program is halted */
1201 /*******************************************************/
1202 
1203 void MeanShift::generateLookupTable( void )
1204 {
1205 
1206  // Declare Variables
1207  int i,j;
1208 
1209  // Allocate memory for lookup table w
1210  w = new double*[kp];
1211 
1212  // Traverse through kernel generating weight function
1213  // lookup table w
1214 
1215  // Assume kernel is uniform
1216  uniformKernel = true;
1217 
1218  for(i = 0; i < kp; i++)
1219  {
1220  switch(kernel[i])
1221  {
1222  // *Uniform Kernel* has weight funciton w(u) = 1
1223  // therefore, a weight funciton lookup table is
1224  // not needed for this kernel --> w[i] = NULL indicates
1225  // this
1226  case Uniform:
1227 
1228  w [i] = NULL; //weight function not needed for this kernel
1229  offset [i] = 1; //uniform kernel has u < 1.0
1230  increment[i] = 1; //has no meaning
1231  break;
1232 
1233  // *Gaussian Kernel* has weight function w(u) = constant*exp(-u^2/[2h[i]^2])
1234  case Gaussian:
1235 
1236  // Set uniformKernel to false
1237  uniformKernel = false;
1238 
1239  // generate weight function using expression,
1240  // exp(-u/2), where u = norm(xi - x)^2/h^2
1241 
1242  // Allocate memory for weight table
1243  w[i] = new double [GAUSS_NUM_ELS+1];
1244 
1245  for(j = 0; j <= GAUSS_NUM_ELS; j++)
1246  w[i][j] = exp(-j*GAUSS_INCREMENT/2);
1247 
1248  // Set offset = offset^2, and set increment
1249  offset [i] = (float)(GAUSS_LIMIT*GAUSS_LIMIT);
1250  increment[i] = GAUSS_INCREMENT;
1251 
1252  // done
1253  break;
1254 
1255  // *User Define Kernel* uses the weight function wf(u)
1256  case UserDefined:
1257 
1258  // Set uniformKernel to false
1259  uniformKernel = false;
1260 
1261  // Search for user defined weight function
1262  // defined for subspace (i+1)
1263  cur = head;
1264  while((cur)&&(cur->subspace != (i+1)))
1265  cur = cur->next;
1266 
1267  // If a user defined subspace has not been found
1268  // for this subspace, flag an error
1269  if(cur == NULL)
1270  {
1271  fprintf(stderr, "\ngenerateLookupTable Fatal Error: User defined kernel for subspace %d undefined.\n\nAborting Program.\n\n", i+1);
1272  exit(1);
1273  }
1274 
1275  // Otherwise, copy weight function lookup table to w[i]
1276  w[i] = new double [cur->sampleNumber+1];
1277  for(j = 0; j <= cur->sampleNumber; j++)
1278  w[i][j] = cur->w[j];
1279 
1280  // Set offset and increment accordingly
1281  offset [i] = (float)(cur->halfWindow);
1282  increment[i] = cur->halfWindow/(float)(cur->sampleNumber);
1283 
1284  // done
1285  break;
1286 
1287  default:
1288 
1289  ErrorHandler("MeanShift", "generateLookupTable", "Unknown kernel type.");
1290 
1291  }
1292 
1293  }
1294 }
1295 
1296 /*******************************************************/
1297 /*Destroy Kernel */
1298 /*******************************************************/
1299 /*Destroys and initializes kernel. */
1300 /*******************************************************/
1301 /*Post: */
1302 /* - memory for the kernel private data members */
1303 /* have been destroyed and the kernel has been */
1304 /* initialized for re-use. */
1305 /*******************************************************/
1306 
1307 void MeanShift::DestroyKernel( void )
1308 {
1309 
1310  //de-allocate memory...
1311  if(kernel) delete [] kernel;
1312  if (h) delete [] h;
1313  if (P) delete [] P;
1314  if (range) delete [] range;
1315 
1316  if (uv) delete [] uv;
1317  if(increment) delete [] increment;
1318  if (offset) delete [] offset;
1319 
1320  if (kp>0)
1321  {
1322  if (w)
1323  {
1324  int i;
1325  for (i=0; i<kp; i++)
1326  delete [] w[i];
1327  delete [] w;
1328  }
1329  w = NULL;
1330  }
1331 
1332  //intialize kernel for re-use...
1333  kp = 0;
1334  kernel = NULL;
1335  h = NULL;
1336  P = NULL;
1337  range = NULL;
1338 
1339  increment = NULL;
1340  uv = NULL;
1341  offset = NULL;
1342 
1343  //done.
1344  return;
1345 
1346 }
1347 
1348  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
1349  /*** Input Data Initialization/Destruction ***/
1350  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
1351 
1352 /*******************************************************/
1353 /*Create Binary Search Tree */
1354 /*******************************************************/
1355 /*Uploads input data set x into a kd-BST. */
1356 /*******************************************************/
1357 /*Pre: */
1358 /* - x is a one dimensional array of L N-dimensi- */
1359 /* onal data points */
1360 /*Post: */
1361 /* - x has been uploaded into a balanced kd-BST */
1362 /* data structure for use by the mean shift */
1363 /* procedure */
1364 /*******************************************************/
1365 
1366 void MeanShift::CreateBST( void )
1367 {
1368 
1369  // Create BST using data....
1370 
1371  // Allocate memory for tree
1372  forest = new tree[L];
1373 
1374  // Populate 'forest' of tree's with
1375  // the values stored in x
1376  int i;
1377  for(i = 0; i < L; i++)
1378  {
1379  forest[i].x = &data[i*N];
1380  forest[i].right = NULL;
1381  forest[i].left = NULL;
1382  forest[i].parent = NULL;
1383  }
1384 
1385  // Build balanced Nd-tree from the
1386  // forest of trees generated above
1387  // retaining the root of this tree
1388 
1389  root = BuildKDTree(forest, L, 0, NULL);
1390 
1391  //done.
1392  return;
1393 
1394 }
1395 
1396 /*******************************************************/
1397 /*Initialize Input */
1398 /*******************************************************/
1399 /*Allocates memory for and initializes the input data */
1400 /*structure. */
1401 /*******************************************************/
1402 /*Pre: */
1403 /* - x is a floating point array of L, N dimens- */
1404 /* ional input data points */
1405 /*Post: */
1406 /* - memory has been allocated for the input data */
1407 /* structure and x has been stored using into */
1408 /* the mean shift class using the resulting */
1409 /* structure. */
1410 /*******************************************************/
1411 
1412 void MeanShift::InitializeInput(float *x)
1413 {
1414 
1415  //allocate memory for input data set
1416  if(!(data = new float [L*N]))
1417  {
1418  ErrorHandler("MeanShift", "InitializeInput", "Not enough memory.");
1419  return;
1420  }
1421 
1422  //copy x into data
1423  int i;
1424  for(i = 0; i < L*N; i++)
1425  data[i] = x[i];
1426 
1427  //done.
1428  return;
1429 
1430 }
1431 
1432 /*******************************************************/
1433 /*Reset Input */
1434 /*******************************************************/
1435 /*De-allocates memory for and re-intializes input data */
1436 /*structure. */
1437 /*******************************************************/
1438 /*Post: */
1439 /* - the memory of the input data structure has */
1440 /* been de-allocated and this strucuture has */
1441 /* been initialized for re-use. */
1442 /*******************************************************/
1443 
1444 void MeanShift::ResetInput( void )
1445 {
1446 
1447  //de-allocate memory of input data structure (BST)
1448  if(data) delete [] data;
1449  if(forest) delete [] forest;
1450 
1451  //initialize input data structure for re-use
1452  data = NULL;
1453  forest = NULL;
1454  root = NULL;
1455  L = 0;
1456  N = 0;
1457  width = 0;
1458  height = 0;
1459 
1460  //re-set class input to indicate that
1461  //an input is not longer stored by
1462  //the private data members of this class
1463  class_state.INPUT_DEFINED = class_state.LATTICE_DEFINED = false;
1464 
1465 }
1466 
1467  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
1468  /*** k-dimensional Binary Search Tree ***/
1469  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
1470 
1471 /*******************************************************/
1472 /*Build KD Tree (for Tree Structure) */
1473 /*******************************************************/
1474 /*Builds a KD Tree given a forest of tree's. */
1475 /*******************************************************/
1476 /*Pre: */
1477 /* - subset is a subset of L un-ordered tree nodes*/
1478 /* each containing an N-dimensional data point */
1479 /* - d is the depth of the subset, used to specify*/
1480 /* the dimension used to construct the tree at */
1481 /* the given depth */
1482 /* - parent is the parent tree of subset */
1483 /*Post: */
1484 /* - a balanced KD tree has been constructed using*/
1485 /* the forest subset, the root of this tree has */
1486 /* been returned */
1487 /*******************************************************/
1488 
1489 tree *MeanShift::BuildKDTree(tree *subset, int length, int d, tree* parent)
1490 {
1491 
1492  // If the subset is a single tree
1493  // then return this tree otherwise
1494  // partition the subset and place
1495  // these subsets recursively into
1496  // the left and right sub-trees having
1497  // their root specified by the median
1498  // of this subset in dimension d
1499  if(length == 1)
1500  {
1501  subset->parent = parent;
1502  return subset;
1503  }
1504  else if(length > 1)
1505  {
1506 
1507  // Sort Subset
1508  QuickMedian(subset, 0, length-1, d);
1509 
1510  // Get Median of Subset and Partition
1511  // it into two sub-trees - create
1512  // a tree with its root being the median
1513  // of the subset and its left and right
1514  // children being the medians of the subsets
1515  int median = length/2;
1516  subset[median].parent = parent;
1517  subset[median].left = BuildKDTree(subset , median , (d+1)%N, &subset[median]);
1518  subset[median].right = BuildKDTree(&subset[median+1], length-median-1, (d+1)%N, &subset[median]);
1519 
1520  // Output tree structure
1521  return &subset[median];
1522 
1523  }
1524  else
1525  return NULL;
1526 
1527  //done.
1528 
1529 }
1530 
1531 /*******************************************************/
1532 /*Quick Median (for Tree Structure) */
1533 /*******************************************************/
1534 /*Finds the median element in an un-ordered set, re- */
1535 /*structuring the set such that points less than the */
1536 /*median point are located to the left of the median */
1537 /*and points greater than the median point are located */
1538 /*to the right. */
1539 /*******************************************************/
1540 /*Pre: */
1541 /* - arr is a subset of tree nodes whose leftmost */
1542 /* element is specified by left and rightmost */
1543 /* element is specified by left */
1544 /* - d is the dimension of the data set stored by */
1545 /* the tree structure that is used to find */
1546 /* the median */
1547 /*Post: */
1548 /* - the median point is found and the subset */
1549 /* of trees is re-ordered such that all trees */
1550 /* whose data points with d dimensional value */
1551 /* less than that of the median tree node are */
1552 /* located to the left of the median tree node, */
1553 /* otherwise they are located to the right */
1554 /*******************************************************/
1555 
1556 void MeanShift::QuickMedian(tree *arr, int left, int right, int d)
1557 {
1558  unsigned long k;
1559  unsigned long n;
1560  float* a;
1561  float* temp;
1562  n = right-left+1;
1563  k = n/2 + 1;
1564  unsigned long i, ir, j, l, mid;
1565 
1566  l = 1;
1567  ir = n;
1568  for (;;)
1569  {
1570  if (ir <= l+1)
1571  {
1572  if (ir == l+1 && arr[ir-1].x[d] < arr[l-1].x[d])
1573  {
1574  SWAP(arr[l-1].x, arr[ir-1].x)
1575  }
1576  return;
1577  } else
1578  {
1579  mid = (l+ir) >> 1;
1580  SWAP(arr[mid-1].x, arr[l+1-1].x)
1581  if (arr[l-1].x[d] > arr[ir-1].x[d])
1582  {
1583  SWAP(arr[l-1].x, arr[ir-1].x)
1584  }
1585  if (arr[l+1-1].x[d] > arr[ir-1].x[d])
1586  {
1587  SWAP(arr[l+1-1].x, arr[ir-1].x)
1588  }
1589  if (arr[l-1].x[d] > arr[l+1-1].x[d])
1590  {
1591  SWAP(arr[l-1].x, arr[l+1-1].x)
1592  }
1593  i = l+1;
1594  j = ir;
1595  a = arr[l+1-1].x;
1596  for (;;) {
1597  do i++; while (arr[i-1].x[d] < a[d]);
1598  do j--; while (arr[j-1].x[d] > a[d]);
1599  if (j<i) break;
1600  SWAP(arr[i-1].x, arr[j-1].x)
1601  }
1602  arr[l+1-1].x = arr[j-1].x;
1603  arr[j-1].x = a;
1604  if (j>=k) ir = j-1;
1605  if (j<=k) l = i;
1606  }
1607  }
1608 }
1609 
1610  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
1611  /*** Mean Shift: Using kd-Tree ***/
1612  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
1613 
1614 /*******************************************************/
1615 /*Uniform Search */
1616 /*******************************************************/
1617 /*Searches the input data using a kd-tree, performs the*/
1618 /*sum on the data within the Hypercube defined by the */
1619 /*tree using a uniform kernel. */
1620 /*******************************************************/
1621 /*Pre: */
1622 /* - gt is a possibly NULL pointer to a kd tree */
1623 /* - Mh_ptr is a pointer to the mean shift vector */
1624 /* being calculated */
1625 /* - yk_ptr is a pointer to the current window */
1626 /* center location */
1627 /* - gd is the depth of the current subtree */
1628 /*Post: */
1629 /* - the mean of the points within the Hypercube */
1630 /* of the kd tree is computed using a uniform */
1631 /* kernel */
1632 /*******************************************************/
1633 
1634 void MeanShift::uniformSearch(tree *gt, int gd, double *Mh_ptr, double *yk_ptr)
1635 {
1636  tree* c_t;
1637  int c_d;
1638  int i;
1639  int actionType;
1640 
1641  c_t = gt;
1642  c_d = gd;
1643  actionType = 0;
1644 
1645  double el, diff;
1646  int k, j, s;
1647 
1648  while (c_t != NULL)
1649  {
1650  switch(actionType) {
1651  case 0: // forward
1652  if ((c_t->x[c_d] > range[2*c_d]) && ((c_t->left) != NULL))
1653  {
1654  c_t = c_t->left;
1655  c_d = (c_d+1)%N;
1656  } else
1657  {
1658  actionType = 1;
1659  }
1660  break;
1661  case 1: // backleft
1662 
1663  for(i = 0; i < N; i++)
1664  {
1665  if((c_t->x[i] < range[2*i])||(c_t->x[i] > range[2*i+1]))
1666  break;
1667  }
1668 
1669  if(i == N)
1670  {
1671 
1672  // *** Visit Tree ***
1673 
1674  // Check if xi is in the window centered about yk_ptr
1675  // If so - use it to compute y(k+1)
1676  diff = 0;
1677  j = 0;
1678  s = 0;
1679  while((diff < 1.0)&&(j < kp)) // Partial Distortion Search (PDS)
1680  {
1681 
1682  // test each sub-dimension independently
1683  diff = 0;
1684  for(k = 0; k < P[j]; k++)
1685  {
1686  el = (c_t->x[s+k] - yk_ptr[s+k])/h[j];
1687  diff += el*el;
1688  }
1689 
1690  s += P[j]; // next subspace
1691  j++;
1692 
1693  }
1694 
1695  if(diff < 1.0)
1696  {
1697  wsum += 1;
1698  for(j = 0; j < N; j++)
1699  Mh_ptr[j] += c_t->x[j];
1700  }
1701 
1702  }
1703  if ((c_t->x[c_d] < range[2*c_d+1]) && ((c_t->right) != NULL))
1704  {
1705  c_t = c_t->right;
1706  c_d = (c_d+1)%N;
1707  actionType = 0;
1708  } else
1709  {
1710  actionType = 2;
1711  }
1712  break;
1713  case 2: // backright
1714  c_d = (c_d+N-1)%N;
1715 
1716  if (c_t->parent == NULL)
1717  {
1718  c_t = NULL;
1719  break;
1720  }
1721 
1722  if (c_t->parent->left == c_t)
1723  actionType = 1;
1724  else
1725  actionType = 2;
1726  c_t = c_t->parent;
1727  break;
1728  }
1729  }
1730 }
1731 
1732 /*******************************************************/
1733 /*General Search */
1734 /*******************************************************/
1735 /*Searches the input data using a kd tree, performs the*/
1736 /*sum on the data within the Hypercube defined by the */
1737 /*tree using a general kernel. */
1738 /*******************************************************/
1739 /*Pre: */
1740 /* - gt is a possibly NULL pointer to a kd tree */
1741 /* - Mh_ptr is a pointer to the mean shift vector */
1742 /* being calculated */
1743 /* - yk_ptr is a pointer to the current window */
1744 /* center location */
1745 /* - gd is the depth of the current subtree */
1746 /*Post: */
1747 /* - the mean of the points within the Hypercube */
1748 /* of the kd tree is computed using a general */
1749 /* kernel */
1750 /*******************************************************/
1751 
1752 void MeanShift::generalSearch(tree *gt, int gd, double *Mh_ptr, double *yk_ptr)
1753 {
1754  tree* c_t;
1755  int c_d;
1756  int i;
1757  int actionType;
1758 
1759  c_t = gt;
1760  c_d = gd;
1761  actionType = 0;
1762 
1763  double el, diff, u, tw, y0, y1;
1764  int k, j, s, x0, x1;
1765 
1766  while (c_t != NULL)
1767  {
1768  switch(actionType) {
1769  case 0: // forward
1770  if ((c_t->x[c_d] > range[2*c_d]) && ((c_t->left) != NULL))
1771  {
1772  c_t = c_t->left;
1773  c_d = (c_d+1)%N;
1774  } else
1775  {
1776  actionType = 1;
1777  }
1778  break;
1779  case 1: // backleft
1780 
1781  for(i = 0; i < N; i++)
1782  {
1783  if((c_t->x[i] < range[2*i])||(c_t->x[i] > range[2*i+1]))
1784  break;
1785  }
1786 
1787  if(i == N)
1788  {
1789 
1790  // *** Visit Tree ***
1791 
1792  // Check if xi is in the window centered about yk_ptr
1793  // If so - use it to compute y(k+1)
1794  s = 0;
1795  for(j = 0; j < kp; j++)
1796  {
1797 
1798  // test each sub-dimension independently
1799  diff = 0;
1800  for(k = 0; k < P[j]; k++)
1801  {
1802  el = (c_t->x[s+k] - yk_ptr[s+k])/h[j];
1803  diff += uv[s+k] = el*el; // Update uv and diff
1804  if(diff >= offset[j]) // Partial Distortion Search (PDS)
1805  break;
1806  }
1807 
1808  if(diff >= offset[j]) // PDS
1809  break;
1810 
1811  s += P[j]; // next subspace
1812 
1813  }
1814 
1815  // j == kp indicates that all subspaces passed the test:
1816  // the data point is within the search window
1817  if(j == kp) j--;
1818  if(diff < offset[j])
1819  {
1820 
1821  // Initialize total weight to 1
1822  tw = 1;
1823 
1824  // Calculate weight factor using weight function
1825  // lookup tables and uv
1826  s = 0;
1827  for(j = 0; j < kp; j++)
1828  {
1829  if(kernel[j]) // not uniform kernel
1830  {
1831  // Compute u[i]
1832  u = 0;
1833  for(k = 0; k < P[j]; k++)
1834  u += uv[s+k];
1835 
1836  // Accumulate tw using calculated u
1837  // and weight function lookup table
1838 
1839  // Linear interpolate values given by
1840  // lookup table
1841 
1842  // Calculate x0 and x1, the points surounding
1843  // u
1844  x0 = (int)(u/increment[j]);
1845  x1 = x0+1;
1846 
1847  // Get y0 and y1 from the lookup table
1848  y0 = w[j][x0];
1849  y1 = w[j][x1];
1850 
1851  // Accumulate tw using linear interpolation
1852  tw *= (((double)(x1)*increment[j] - u)*y0+(u - (double)(x0)*increment[j])*y1)/(double)(x1*increment[j] - x0*increment[j]);
1853 
1854  }
1855  s += P[j]; // next subspace
1856  }
1857 
1858  // Perform weighted sum using xi
1859  for(j = 0; j < N; j++)
1860  Mh_ptr[j] += tw*c_t->x[j];
1861 
1862  // Increment wsum by tw
1863  wsum += tw;
1864 
1865  }
1866  }
1867  if ((c_t->x[c_d] < range[2*c_d+1]) && ((c_t->right) != NULL))
1868  {
1869  c_t = c_t->right;
1870  c_d = (c_d+1)%N;
1871  actionType = 0;
1872  } else
1873  {
1874  actionType = 2;
1875  }
1876  break;
1877  case 2: // backright
1878  c_d = (c_d+N-1)%N;
1879 
1880  if (c_t->parent == NULL)
1881  {
1882  c_t = NULL;
1883  break;
1884  }
1885 
1886  if (c_t->parent->left == c_t)
1887  actionType = 1;
1888  else
1889  actionType = 2;
1890  c_t = c_t->parent;
1891  break;
1892  }
1893  }
1894 }
1895 
1896  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
1897  /*** Mean Shift: Using Lattice ***/
1898  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
1899 
1900 /*******************************************************/
1901 /*Uniform Lattice Search */
1902 /*******************************************************/
1903 /*Performs search on data set for all points lying */
1904 /*within the search window defined using a uniform */
1905 /*kernel. Their point-wise sum and count is computed */
1906 /*and returned. */
1907 /* */
1908 /*NOTE: This method is the only method in the */
1909 /* MeanShift class that uses the weight */
1910 /* map asside from optUniformLSearch. */
1911 /*******************************************************/
1912 /*Pre: */
1913 /* - Mh_ptr is a length N array of doubles */
1914 /* - yk_ptr is a length N array of doubles */
1915 /* - Mh_ptr is the sum of the data points found */
1916 /* within search window having center yk_ptr */
1917 /*Post: */
1918 /* - a search on the data set using the lattice */
1919 /* has been performed, and all points found to */
1920 /* lie within the search window defined using */
1921 /* a uniform kernel are summed and counted. */
1922 /* - their point wise sum is pointed to by Mh_ptr */
1923 /* and their count is stored by wsum. */
1924 /*******************************************************/
1925 
1926 void MeanShift::uniformLSearch(double *Mh_ptr, double *yk_ptr)
1927 {
1928 
1929  //Declare variables
1930  register int i, j, k;
1931  int s, p, dataPoint, lN;
1932  double diff, el, dx, dy, tx, weight;
1933 
1934  //Define lattice data dimension...
1935  lN = N + 2;
1936 
1937  //Define bounds of lattice...
1938 
1939  //the lattice is a 2dimensional subspace whose
1940  //search window bandwidth is specified by
1941  //h[0]:
1942  tx = yk_ptr[0] - h[0] + DELTA + 0.99;
1943  if (tx < 0)
1944  LowerBoundX = 0;
1945  else
1946  LowerBoundX = (int) tx;
1947  tx = yk_ptr[1] - h[0] + DELTA + 0.99;
1948  if (tx < 0)
1949  LowerBoundY = 0;
1950  else
1951  LowerBoundY = (int) tx;
1952  tx = yk_ptr[0] + h[0] - DELTA;
1953  if (tx >= width)
1954  UpperBoundX = width-1;
1955  else
1956  UpperBoundX = (int) tx;
1957  tx = yk_ptr[1] + h[0] - DELTA;
1958  if (tx >= height)
1959  UpperBoundY = height - 1;
1960  else
1961  UpperBoundY = (int) tx;
1962 
1963  //Perform search using lattice
1964  for(i = LowerBoundY; i <= UpperBoundY; i++)
1965  for(j = LowerBoundX; j <= UpperBoundX; j++)
1966  {
1967 
1968  //get index into data array
1969  dataPoint = N*(i*width+j);
1970 
1971  //Determine if inside search window
1972  k = 1;
1973  s = 0;
1974  dx = j - yk_ptr[0];
1975  dy = i - yk_ptr[1];
1976  diff = (dx*dx+dy*dy)/(h[0]*h[0]);
1977  while((diff < 1.0)&&(k != kp)) // Partial Distortion Search
1978  {
1979  //Calculate distance squared of sub-space s
1980  diff = 0;
1981  for(p = 0; p < P[k]; p++)
1982  {
1983  el = (data[dataPoint+p+s]-yk_ptr[p+s+2])/h[k];
1984  if((!p)&&(yk_ptr[2] > 80))
1985  diff += 4*el*el;
1986  else
1987  diff += el*el;
1988  }
1989 
1990  //next subspace
1991  s += P[k];
1992  k++;
1993  }
1994 
1995  //if its inside search window perform sum and count
1996  if(diff < 1.0)
1997  {
1998  weight = 1 - weightMap[i*width+j];
1999  Mh_ptr[0] += weight*j;
2000  Mh_ptr[1] += weight*i;
2001  for(k = 2; k < lN; k++)
2002  Mh_ptr[k] += weight*data[dataPoint+k-2];
2003  wsum += weight;
2004  }
2005  //done.
2006  }
2007  //done.
2008  return;
2009 
2010 }
2011 
2012 /*******************************************************/
2013 /*Optimized Uniform Latice Search */
2014 /*******************************************************/
2015 /*Performs search on data set for all points lying */
2016 /*within the search window defined using a uniform */
2017 /*kernel. Their point-wise sum and count is computed */
2018 /*and returned. Also the points that lie within the */
2019 /*window are stored into the basin of attraction stru- */
2020 /*cture used by the optimized mean shift algorithms. */
2021 /* */
2022 /*NOTE: This method is the only method in the */
2023 /* MeanShift class that uses the weight */
2024 /* map asside from uniformLSearch. */
2025 /*******************************************************/
2026 /*Pre: */
2027 /* - Mh_ptr is a length N array of doubles */
2028 /* - yk_ptr is a length N array of doubles */
2029 /* - Mh_ptr is the sum of the data points found */
2030 /* within search window having center yk_ptr */
2031 /*Post: */
2032 /* - a search on the data set using the latice */
2033 /* has been performed, and all points found to */
2034 /* lie within the search window defined using */
2035 /* a uniform kernel are summed and counted. */
2036 /* - their point wise sum is pointed to by Mh_ptr */
2037 /* and their count is stored by wsum. */
2038 /* - the data points lying within h of of yk_ptr */
2039 /* have been stored into the basin of attract- */
2040 /* ion data structure. */
2041 /*******************************************************/
2042 
2043 void MeanShift::optUniformLSearch(double *Mh_ptr, double *yk_ptr)
2044 {
2045 
2046  //Declare variables
2047  register int i, j, k;
2048  int s, p, dataPoint, pointIndx, lN;
2049  double diff, el, dx, dy, tx, weight;
2050 
2051  //Define latice data dimension...
2052  lN = N + 2;
2053 
2054  //Define bounds of latice...
2055 
2056  //the latice is a 2dimensional subspace whose
2057  //search window bandwidth is specified by
2058  //h[0]:
2059  tx = yk_ptr[0] - h[0] + DELTA + 0.99;
2060  if (tx < 0)
2061  LowerBoundX = 0;
2062  else
2063  LowerBoundX = (int) tx;
2064  tx = yk_ptr[1] - h[0] + DELTA + 0.99;
2065  if (tx < 0)
2066  LowerBoundY = 0;
2067  else
2068  LowerBoundY = (int) tx;
2069  tx = yk_ptr[0] + h[0] - DELTA;
2070  if (tx >= width)
2071  UpperBoundX = width-1;
2072  else
2073  UpperBoundX = (int) tx;
2074  tx = yk_ptr[1] + h[0] - DELTA;
2075  if (tx >= height)
2076  UpperBoundY = height - 1;
2077  else
2078  UpperBoundY = (int) tx;
2079 
2080  //Perform search using latice
2081  for(i = LowerBoundY; i <= UpperBoundY; i++)
2082  for(j = LowerBoundX; j <= UpperBoundX; j++)
2083  {
2084 
2085  //get index into data array
2086  pointIndx = i*width+j;
2087  dataPoint = N*(pointIndx);
2088 
2089  //Determine if inside search window
2090  k = 1;
2091  s = 0;
2092  dx = j - yk_ptr[0];
2093  dy = i - yk_ptr[1];
2094  diff = (dx*dx+dy*dy)/(h[0]*h[0]);
2095  while((diff < 1.0)&&(k != kp)) // Partial Distortion Search
2096  {
2097  //Calculate distance squared of sub-space s
2098  diff = 0;
2099  for(p = 0; p < P[k]; p++)
2100  {
2101  el = (data[dataPoint+p+s]-yk_ptr[p+s+2])/h[k];
2102  if((!p)&&(yk_ptr[2] > 80))
2103  diff += 4*el*el;
2104  else
2105  diff += el*el;
2106  }
2107 
2108  //next subspace
2109  s += P[k];
2110  k++;
2111  }
2112 
2113  //if its inside search window perform sum and count
2114  if(diff < 1.0)
2115  {
2116  weight = 1 - weightMap[i*width+j];
2117  Mh_ptr[0] += weight*j;
2118  Mh_ptr[1] += weight*i;
2119  for(k = 2; k < lN; k++)
2120  Mh_ptr[k] += weight*data[dataPoint+k-2];
2121  wsum += weight;
2122 
2123  //set basin of attraction mode table
2124  if (diff < 0.5)
2125  {
2126  if(modeTable[pointIndx] == 0)
2127  {
2128  pointList[pointCount++] = pointIndx;
2129  modeTable[pointIndx] = 2;
2130  }
2131  }
2132 
2133  }
2134 
2135  //done.
2136 
2137  }
2138 
2139  //done.
2140  return;
2141 
2142 }
2143 
2144 /*******************************************************/
2145 /*General Lattice Search */
2146 /*******************************************************/
2147 /*Performs search on data set for all points lying */
2148 /*within the search window defined using a general */
2149 /*kernel. Their point-wise sum and count is computed */
2150 /*and returned. */
2151 /*******************************************************/
2152 /*Pre: */
2153 /* - Mh_ptr is a length N array of doubles */
2154 /* - yk_ptr is a length N array of doubles */
2155 /* - Mh_ptr is the sum of the data points found */
2156 /* within search window having center yk_ptr */
2157 /*Post: */
2158 /* - a search on the data set using the lattice */
2159 /* has been performed, and all points found to */
2160 /* lie within the search window defined using */
2161 /* a general kernel are summed and counted */
2162 /* - their point wise sum is pointed to by Mh_ptr */
2163 /* and their count is stored by wsum */
2164 /*******************************************************/
2165 
2166 void MeanShift::generalLSearch(double *Mh_ptr, double *yk_ptr)
2167 {
2168 
2169  //Declare variables
2170  register int i, j, k;
2171  int s, p, dataPoint, lN, x0, x1;
2172  double diff, el, dx, dy, tw, u, y0, y1, tx;
2173 
2174  //Define lattice data dimension...
2175  lN = N + 2;
2176 
2177  //Define bounds of lattice...
2178 
2179  //the lattice is a 2dimensional subspace whose
2180  //search window bandwidth is specified by
2181  //h[0]:
2182  tx = yk_ptr[0] - h[0] + DELTA + 0.99;
2183  if (tx < 0)
2184  LowerBoundX = 0;
2185  else
2186  LowerBoundX = (int) tx;
2187  tx = yk_ptr[1] - h[0] + DELTA + 0.99;
2188  if (tx < 0)
2189  LowerBoundY = 0;
2190  else
2191  LowerBoundY = (int) tx;
2192  tx = yk_ptr[0] + h[0] - DELTA;
2193  if (tx >= width)
2194  UpperBoundX = width-1;
2195  else
2196  UpperBoundX = (int) tx;
2197  tx = yk_ptr[1] + h[0] - DELTA;
2198  if (tx >= height)
2199  UpperBoundY = height - 1;
2200  else
2201  UpperBoundY = (int) tx;
2202 
2203  //Perform search using lattice
2204  for(i = LowerBoundY; i <= UpperBoundY; i++)
2205  for(j = LowerBoundX; j <= UpperBoundX; j++)
2206  {
2207 
2208  //get index into data array
2209  dataPoint = N*(i*width+j);
2210 
2211  //Determine if inside search window
2212  k = 1;
2213  s = 0;
2214  dx = j - yk_ptr[0];
2215  dy = i - yk_ptr[1];
2216  uv[0] = (dx*dx)/(h[0]*h[0]);
2217  uv[1] = (dy*dy)/(h[0]*h[0]);
2218  diff = uv[0] + uv[1];
2219  while((diff < offset[k-1])&&(k != kp)) // Partial Distortion Search
2220  {
2221  //Calculate distance squared of sub-space s
2222  diff = 0;
2223  for(p = 0; p < P[k]; p++)
2224  {
2225  el = (data[dataPoint+p+s]-yk_ptr[p+s+2])/h[k];
2226  diff += uv[p+s+2] = el*el;
2227  }
2228 
2229  //next subspace
2230  s += P[k];
2231  k++;
2232  }
2233 
2234  //if its inside search window perform weighted sum and count
2235  if(diff < offset[k-1])
2236  {
2237 
2238  // Initialize total weight to 1
2239  tw = 1;
2240 
2241  // Calculate weight factor using weight function
2242  // lookup tables and uv
2243  s = 0;
2244  for(k = 0; k < kp; k++)
2245  {
2246  if(kernel[k]) // not uniform kernel
2247  {
2248  // Compute u[i]
2249  u = 0;
2250  for(p = 0; p < P[k]; p++)
2251  u += uv[s+p];
2252 
2253  // Accumulate tw using calculated u
2254  // and weight function lookup table
2255 
2256  // Linear interpolate values given by
2257  // lookup table
2258 
2259  // Calculate x0 and x1, the points surounding
2260  // u
2261  x0 = (int)(u/increment[k]);
2262  x1 = x0+1;
2263 
2264  // Get y0 and y1 from the lookup table
2265  y0 = w[k][x0];
2266  y1 = w[k][x1];
2267 
2268  // Accumulate tw using linear interpolation
2269  tw *= (((double)(x1)*increment[k] - u)*y0+(u - (double)(x0)*increment[k])*y1)/(double)(x1*increment[k] - x0*increment[k]);
2270 
2271  }
2272  s += P[k]; // next subspace
2273  }
2274 
2275  // Perform weighted sum using xi
2276  Mh_ptr[0] += tw*j;
2277  Mh_ptr[1] += tw*i;
2278  for(k = 0; k < N; k++)
2279  Mh_ptr[k+2] += tw*data[dataPoint+k];
2280 
2281  // Increment wsum by tw
2282  wsum += tw;
2283 
2284  }
2285 
2286  //done.
2287 
2288  }
2289 
2290  //done.
2291  return;
2292 
2293 }
2294 
2295 /*******************************************************/
2296 /*Optimized General Lattice Search */
2297 /*******************************************************/
2298 /*Performs search on data set for all points lying */
2299 /*within the search window defined using a general */
2300 /*kernel. Their point-wise sum and count is computed */
2301 /*and returned. Also the points that lie within the */
2302 /*window are stored into the basin of attraction stru- */
2303 /*cture used by the optimized mean shift algorithms. */
2304 /*******************************************************/
2305 /*Pre: */
2306 /* - Mh_ptr is a length N array of doubles */
2307 /* - yk_ptr is a length N array of doubles */
2308 /* - Mh_ptr is the sum of the data points found */
2309 /* within search window having center yk_ptr */
2310 /*Post: */
2311 /* - a search on the data set using the lattice */
2312 /* has been performed, and all points found to */
2313 /* lie within the search window defined using */
2314 /* a general kernel are summed and counted */
2315 /* - their point wise sum is pointed to by Mh_ptr */
2316 /* and their count is stored by wsum */
2317 /* - the data points lying within h*offset of */
2318 /* yk_ptr have been stored into the basin of */
2319 /* attraction data structure. */
2320 /*******************************************************/
2321 
2322 void MeanShift::optGeneralLSearch(double *Mh_ptr, double *yk_ptr)
2323 {
2324 
2325  //Declare variables
2326  register int i, j, k;
2327  int s, p, dataPoint, pointIndx, lN, x0, x1;
2328  double diff, el, dx, dy, tw, u, y0, y1, tx;
2329 
2330  //Define lattice data dimension...
2331  lN = N + 2;
2332 
2333  //Define bounds of lattice...
2334 
2335  //the lattice is a 2dimensional subspace whose
2336  //search window bandwidth is specified by
2337  //h[0]:
2338  tx = yk_ptr[0] - h[0] + DELTA + 0.99;
2339  if (tx < 0)
2340  LowerBoundX = 0;
2341  else
2342  LowerBoundX = (int) tx;
2343  tx = yk_ptr[1] - h[0] + DELTA + 0.99;
2344  if (tx < 0)
2345  LowerBoundY = 0;
2346  else
2347  LowerBoundY = (int) tx;
2348  tx = yk_ptr[0] + h[0] - DELTA;
2349  if (tx >= width)
2350  UpperBoundX = width-1;
2351  else
2352  UpperBoundX = (int) tx;
2353  tx = yk_ptr[1] + h[0] - DELTA;
2354  if (tx >= height)
2355  UpperBoundY = height - 1;
2356  else
2357  UpperBoundY = (int) tx;
2358 
2359  //Perform search using lattice
2360  for(i = LowerBoundY; i <= UpperBoundY; i++)
2361  for(j = LowerBoundX; j <= UpperBoundX; j++)
2362  {
2363 
2364  //get index into data array
2365  pointIndx = i*width+j;
2366  dataPoint = N*(i*width+j);
2367 
2368  //Determine if inside search window
2369  k = 1;
2370  s = 0;
2371  dx = j - yk_ptr[0];
2372  dy = i - yk_ptr[1];
2373  uv[0] = (dx*dx)/(h[0]*h[0]);
2374  uv[1] = (dy*dy)/(h[0]*h[0]);
2375  diff = uv[0] + uv[1];
2376  while((diff < offset[k-1])&&(k != kp)) // Partial Distortion Search
2377  {
2378  //Calculate distance squared of sub-space s
2379  diff = 0;
2380  for(p = 0; p < P[k]; p++)
2381  {
2382  el = (data[dataPoint+p+s]-yk_ptr[p+s+2])/h[k];
2383  diff += uv[p+s+2] = el*el;
2384  }
2385 
2386  //next subspace
2387  s += P[k];
2388  k++;
2389  }
2390 
2391  //if its inside search window perform weighted sum and count
2392  if(diff < offset[k-1])
2393  {
2394 
2395  // Initialize total weight to 1
2396  tw = 1;
2397 
2398  // Calculate weight factor using weight function
2399  // lookup tables and uv
2400  s = 0;
2401  for(k = 0; k < kp; k++)
2402  {
2403  if(kernel[k]) // not uniform kernel
2404  {
2405  // Compute u[i]
2406  u = 0;
2407  for(p = 0; p < P[k]; p++)
2408  u += uv[s+p];
2409 
2410  // Accumulate tw using calculated u
2411  // and weight function lookup table
2412 
2413  // Linear interpolate values given by
2414  // lookup table
2415 
2416  // Calculate x0 and x1, the points surounding
2417  // u
2418  x0 = (int)(u/increment[k]);
2419  x1 = x0+1;
2420 
2421  // Get y0 and y1 from the lookup table
2422  y0 = w[k][x0];
2423  y1 = w[k][x1];
2424 
2425  // Accumulate tw using linear interpolation
2426  tw *= (((double)(x1)*increment[k] - u)*y0+(u - (double)(x0)*increment[k])*y1)/(double)(x1*increment[k] - x0*increment[k]);
2427 
2428  }
2429  s += P[k]; // next subspace
2430  }
2431 
2432  // Perform weighted sum using xi
2433  Mh_ptr[0] += tw*j;
2434  Mh_ptr[1] += tw*i;
2435  for(k = 0; k < N; k++)
2436  Mh_ptr[k+2] += tw*data[dataPoint+k];
2437 
2438  // Increment wsum by tw
2439  wsum += tw;
2440 
2441  //set basin of attraction mode table
2442  if(modeTable[pointIndx] == 0)
2443  {
2444  pointList[pointCount++] = pointIndx;
2445  modeTable[pointIndx] = 2;
2446  }
2447 
2448  }
2449 
2450  //done.
2451 
2452  }
2453 
2454  //done.
2455  return;
2456 
2457 }
2458 
2459 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
2460 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
2461 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ END OF CLASS DEFINITION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
2462 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
2463 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
2464 
2465