Browse Source

initialization

Bjoern Froehlich 12 years ago
commit
2fd42714e0
57 changed files with 17219 additions and 0 deletions
  1. 59 0
      GenericRegionSegmentationMethodSelection.h
  2. 8 0
      Makefile
  3. 103 0
      Makefile.inc
  4. 161 0
      RSCache.cpp
  5. 57 0
      RSCache.h
  6. 93 0
      RSGraphBased.cpp
  7. 58 0
      RSGraphBased.h
  8. 768 0
      RSMarkovCluster.cpp
  9. 174 0
      RSMarkovCluster.h
  10. 141 0
      RSMeanShift.cpp
  11. 70 0
      RSMeanShift.h
  12. 117 0
      RSSlic.cpp
  13. 57 0
      RSSlic.h
  14. 225 0
      RegionGraph.cpp
  15. 205 0
      RegionGraph.h
  16. 287 0
      RegionSegmentationMethod.cpp
  17. 91 0
      RegionSegmentationMethod.h
  18. 103 0
      SLIC/Makefile.inc
  19. 1331 0
      SLIC/SLIC.cpp
  20. 234 0
      SLIC/SLIC.h
  21. 176 0
      edisonSegm/MSReadme.txt
  22. 103 0
      edisonSegm/Makefile.inc
  23. 172 0
      edisonSegm/RAList.cpp
  24. 92 0
      edisonSegm/RAList.h
  25. 1 0
      edisonSegm/libdepend.inc
  26. 2467 0
      edisonSegm/ms.cpp
  27. 926 0
      edisonSegm/ms.h
  28. 4711 0
      edisonSegm/msImageProcessor.cpp
  29. 800 0
      edisonSegm/msImageProcessor.h
  30. 236 0
      edisonSegm/msSys.cpp
  31. 229 0
      edisonSegm/msSys.h
  32. 339 0
      edisonSegm/rlist.cpp
  33. 337 0
      edisonSegm/rlist.h
  34. 51 0
      edisonSegm/tdef.h
  35. 339 0
      felzenszwalb/COPYING
  36. 23 0
      felzenszwalb/Makefile
  37. 25 0
      felzenszwalb/README
  38. 76 0
      felzenszwalb/convolve.h
  39. 81 0
      felzenszwalb/disjoint-set.h
  40. 103 0
      felzenszwalb/filter.h
  41. 103 0
      felzenszwalb/image.h
  42. 181 0
      felzenszwalb/imconv.h
  43. 70 0
      felzenszwalb/imutil.h
  44. 69 0
      felzenszwalb/misc.h
  45. 213 0
      felzenszwalb/pnmfile.h
  46. 86 0
      felzenszwalb/segment-graph.h
  47. 173 0
      felzenszwalb/segment-image.h
  48. 49 0
      felzenszwalb/segment.cpp
  49. 3 0
      libdepend.inc
  50. 8 0
      math/Makefile
  51. 103 0
      math/Makefile.inc
  52. 130 0
      math/NodeCentricRepMatrix.cpp
  53. 115 0
      math/NodeCentricRepMatrix.h
  54. 2 0
      math/libdepend.inc
  55. 88 0
      progs/Makefile.inc
  56. 70 0
      progs/testMarkov.cpp
  57. 127 0
      progs/testSegmentation.cpp

+ 59 - 0
GenericRegionSegmentationMethodSelection.h

@@ -0,0 +1,59 @@
+/**
+* @brief Class which represents a generic RS selection.
+* @author Eric Bach
+* @date 03/05/12
+*/
+
+#ifndef _NICE_OBJREC_SEGMENTATIONSELECTION_INCLUDE
+#define _NICE_OBJREC_SEGMENTATIONSELECTION_INCLUDE
+
+#include <segmentation/RegionSegmentationMethod.h>
+#include <segmentation/RSMarkovCluster.h>
+#include <segmentation/RSMeanShift.h>
+#include <segmentation/RSSlic.h>
+#include <segmentation/RSGraphBased.h>
+
+namespace OBJREC
+{
+class GenericRegionSegmentationMethodSelection
+{
+  public:
+    /**
+    * @brief Return a instanz of the segmentationmethode which has defined in [segmenatation]:methode within conf.
+    * @return RegionSegmentationMethod*, if methode is defined; NULL, else
+    */
+    static RegionSegmentationMethod*
+    selectRegionSegmentationMethod(const Config* conf, const std::string& section = "segmentation")
+    {
+      RegionSegmentationMethod* segmentationAlgo = NULL;
+      std::string methode = conf->gS(section, "methode", "");
+
+      if (methode == "MarkovCluster")
+      {
+        segmentationAlgo = new RSMarkovCluster(conf);
+      }
+      else if (methode == "GraphBased")
+      {
+        segmentationAlgo = new RSGraphBased(conf);
+      }
+      else if (methode == "MeanShift")
+      {
+        segmentationAlgo = new RSMeanShift(conf);
+      }
+      else if (methode == "SLIC")
+      {
+        segmentationAlgo = new RSSlic(conf);
+      }
+
+      if ( segmentationAlgo == NULL )
+      {
+        fthrow(Exception, "Region Segmentation Method not found: " << methode );
+        return segmentationAlgo;
+      }
+
+      return segmentationAlgo;
+    };
+};
+}
+
+#endif

+ 8 - 0
Makefile

@@ -0,0 +1,8 @@
+#TARGETS_FROM:=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM)
+#$(info recursivly going up: $(TARGETS_FROM) ($(shell pwd)))
+
+all:
+
+%:
+	$(MAKE) TARGETS_FROM=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM) -C .. $@
+

+ 103 - 0
Makefile.inc

@@ -0,0 +1,103 @@
+# LIBRARY-DIRECTORY-MAKEFILE
+# conventions:
+# - all subdirectories containing a "Makefile.inc" are considered sublibraries
+#   exception: "progs/" and "tests/" subdirectories!
+# - all ".C", ".cpp" and ".c" files in the current directory are linked to a
+#   library
+# - the library depends on all sublibraries 
+# - the library name is created with $(LIBNAME), i.e. it will be somehow
+#   related to the directory name and with the extension .a
+#   (e.g. lib1/sublib -> lib1_sublib.a)
+# - the library will be added to the default build list ALL_LIBRARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+ifeq "$(SUBDIR)" "./"
+SUBDIR:=
+endif
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# you can specify libraries needed by the individual objects or by the whole
+# directory. the object specific additional libraries are only considered
+# when compiling the specific object files
+# TODO: update documentation...
+
+-include $(SUBDIR)libdepend.inc
+
+$(foreach d,$(filter-out %progs %tests,$(SUBDIRS_OF_$(SUBDIR))),$(eval $(call PKG_DEPEND_INT,$(d))))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+	  $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+LIBRARY_BASENAME:=$(call LIBNAME,$(SUBDIR))
+ifneq "$(SUBDIR)" ""
+ALL_LIBRARIES+=$(LIBDIR)$(LIBRARY_BASENAME).$(LINK_FILE_EXTENSION)
+endif
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. the current library depends on all sublibraries.
+# all other dependencies have to be added manually by specifying, that the
+# current .pc file depends on some other .pc file. binaries depending on
+# libraries should exclusivelly use the .pc files as well.
+
+ifeq "$(SKIP_BUILD_$(OBJDIR))" "1"
+$(LIBDIR)$(LIBRARY_BASENAME).a:
+else
+$(LIBDIR)$(LIBRARY_BASENAME).a:$(OBJS) \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).a,.$(LINK_FILE_EXTENSION))
+endif
+
+$(PKGDIR)$(LIBRARY_BASENAME).pc: \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).pc,.pc)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 161 - 0
RSCache.cpp

@@ -0,0 +1,161 @@
+#include "RSCache.h"
+
+#include <iostream>
+#include <fstream>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "vislearning/baselib/Globals.h"
+#include "core/basics/StringTools.h"
+#include "core/basics/ossettings.h"
+
+#include <unistd.h>
+
+using namespace OBJREC;
+using namespace NICE;
+using namespace std;
+
+RSCache::RSCache ( const Config *conf, RegionSegmentationMethod *_rsmethod )
+{
+  rsmethod = _rsmethod;
+
+
+  cachedir = conf->gS ( "cache", "root", "/tmp/" );
+
+  cachedir += "/regionsegmentation";
+  forcedwrite = conf->gB ( "RSCache", "forcedwrite", false );
+
+  // Verzeichnis anlegen
+  struct stat info;
+  if ( stat ( cachedir.c_str(), &info ) < 0 )
+  {
+    if ( mkdir ( cachedir.c_str(), 0755 ) < 0 )
+    {
+      cerr << "RSCache:: unable to create directory: " << cachedir << endl;
+      exit ( -1 );
+    }
+  }
+}
+
+RSCache::~RSCache()
+{
+}
+
+int RSCache::segRegions ( const NICE::Image & img, NICE::Matrix & mask ) const
+{
+  std::string filename = Globals::getCurrentImgFN();
+
+  vector<string> mylistdir;
+
+  // Zerlege Dateipfad (alles zwischen den /)
+  StringTools::split ( filename, FILESEP, mylistdir );
+
+  if ( mylistdir.size() < 2 )
+  {
+    cerr << "RSCache::getCacheFilename: unable to parse filename " << filename << endl;
+    exit ( -1 );
+  }
+
+  std::string name = mylistdir[mylistdir.size()-1];
+
+
+  vector<string> mylist;
+  // Zerlege den Dateinamen in Namen und Endung
+  StringTools::split ( name, '.', mylist );
+
+  name = "";
+  for ( uint k = 0 ; k < mylist.size()-1 ; k++ )
+    if ( k == 0 )
+      name = name + mylist[k];
+    else
+      name = name + "." + mylist[k];
+
+  filename = cachedir + FILESEPSTRING + name;
+
+  std::string imgname = filename+".ppm";
+  filename += ".mask";
+
+  int cn = -1;
+
+  struct stat dummy;
+  if ( stat ( filename.c_str(), &dummy ) < 0 || forcedwrite )
+  {
+    cn  = rsmethod->segRegions ( img, mask );
+    ofstream fout ( filename.c_str(), ios::out );
+    fout << cn << endl;
+    fout << mask;
+    fout.close();
+
+  }
+  else
+  {
+
+    // read from file
+    ifstream fin ( filename.c_str() );
+    fin >> cn;
+    fin >> mask;
+    fin.close();
+  }
+
+  return cn;
+}
+
+int RSCache::segRegions ( const NICE::ColorImage & img, NICE::Matrix & mask ) const
+{
+  std::string filename = Globals::getCurrentImgFN();
+
+  vector<string> mylistdir;
+
+  // Zerlege Dateipfad (alles zwischen den /)
+  StringTools::split ( filename, FILESEP, mylistdir );
+
+  if ( mylistdir.size() < 2 )
+  {
+    cerr << "RSCache::getCacheFilename: unable to parse filename " << filename << endl;
+    exit ( -1 );
+  }
+
+  std::string name = mylistdir[mylistdir.size()-1];
+
+
+  vector<string> mylist;
+  // Zerlege den Dateinamen in Namen und Endung
+  StringTools::split ( name, '.', mylist );
+
+  name = "";
+  for ( uint k = 0 ; k < mylist.size()-1 ; k++ )
+    if ( k == 0 )
+      name = name + mylist[k];
+    else
+      name = name + "." + mylist[k];
+
+  filename = cachedir + FILESEPSTRING + name;
+
+  std::string imgname = filename+".ppm";
+  filename += ".mask";
+
+  int cn = -1;
+
+  struct stat dummy;
+  if ( stat ( filename.c_str(), &dummy ) < 0 || forcedwrite )
+  {
+    cn  = rsmethod->segRegions ( img, mask );
+    ofstream fout ( filename.c_str(), ios::out );
+    fout << cn << endl;
+    fout << mask;
+    fout.close();
+
+  }
+  else
+  {
+
+    // read from file
+    ifstream fin ( filename.c_str() );
+    fin >> cn;
+    fin >> mask;
+    fin.close();
+  }
+
+  return cn;
+}

+ 57 - 0
RSCache.h

@@ -0,0 +1,57 @@
+/**
+ * @file RSCache.h
+ * @brief read and save the RegionSegmentation
+ * @author Björn Fröhlich
+ * @date 05/07/2009
+ */
+#ifndef RSCACHE
+#define RSCACHE
+
+#include "core/basics/Config.h"
+#include "RegionSegmentationMethod.h"
+
+namespace OBJREC
+{
+
+class RSCache: public RegionSegmentationMethod
+{
+
+  protected:
+    //! the RegionSegmentation method
+    RegionSegmentationMethod *rsmethod;
+
+    //! where to save or to load the caches data
+    std::string cachedir;
+
+    //! just write features, don't read them
+    bool forcedwrite;
+
+
+  public:
+
+    /** simple constructor */
+    RSCache ( const NICE::Config *conf, RegionSegmentationMethod *_rsmethod );
+
+    /** simple destructor */
+    ~RSCache();
+
+    /**
+     * returns the regions of a given image
+     * @param img input image
+     * @param mask output regions, each region has it own number
+     * @return count of region
+     */
+    virtual int segRegions ( const NICE::Image & img, NICE::Matrix & mask ) const;
+
+    /**
+     * returns the regions of a given image
+     * @param img input colorimage
+     * @param mask output regions, each region has it own number
+     * @return count of region
+     */
+    virtual int segRegions ( const NICE::ColorImage & cimg, NICE::Matrix & mask ) const;
+};
+
+} // namespace
+
+#endif

+ 93 - 0
RSGraphBased.cpp

@@ -0,0 +1,93 @@
+#include "RSGraphBased.h"
+
+#include <iostream>
+#include <fstream>
+
+#ifdef NICE_USELIB_OPENMP
+#include <omp.h>
+#endif
+
+#include "felzenszwalb/image.h"
+#include "felzenszwalb/misc.h"
+#include "felzenszwalb/segment-image.h"
+#include "felzenszwalb/pnmfile.h"
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+using namespace felzenszwalb;
+
+RSGraphBased::RSGraphBased()
+{
+  parameter_k = 500;
+  parameter_min_size = 200;
+  parameter_sigma = 1.5;
+}
+
+RSGraphBased::RSGraphBased(const Config *conf )
+{
+  //thr = conf->gD( "RSGraphBased", "threshold", 5.0);
+  parameter_k = conf->gD("RSGraphBased", "k", 500);
+  parameter_min_size = conf->gI("RSGraphBased", "min_size", 200);
+  parameter_sigma = conf->gD("RSGraphBased", "sigma", 1.5);
+}
+
+RSGraphBased::~RSGraphBased()
+{
+}
+
+int RSGraphBased::segRegions ( const NICE::Image & img, NICE::Matrix & mask) const
+{
+  cerr << "not implemented yet" << endl;
+  return -1;
+}
+
+int RSGraphBased::segRegions ( const NICE::ColorImage & img, NICE::Matrix & mask) const
+{
+  const unsigned int imageWidth  = img.width();
+  const unsigned int imageHeight = img.height();
+
+  // Kopieren der Werte aus dem ColorImage -> image<rgb>
+
+  image<rgb> *inputImage = new image<rgb>( imageWidth, imageHeight, false );
+
+#pragma omp parallel for
+  for ( unsigned int y = 0; y < imageHeight; y++ )
+  {
+    for ( unsigned int x = 0; x < imageWidth; x++ )
+    {
+      imRef( inputImage, x, y ).r = img.getPixelQuick( x, y, 0 );
+      imRef( inputImage, x, y ).g = img.getPixelQuick( x, y, 1 );
+      imRef( inputImage, x, y ).b = img.getPixelQuick( x, y, 2 );
+    }
+  }
+
+
+  // Eingabebild segmentieren
+  int num_ccs; // Anzahl der segmentierten Regionen
+  image<rgb> *tempResultImage = segment_image( inputImage, parameter_sigma, parameter_k, parameter_min_size, &num_ccs );
+
+  // Kopieren der Werte aus dem image<rgb> -> ColorImage
+  NICE::ColorImage resultImage( imageWidth, imageHeight );
+
+#pragma omp parallel for
+  for ( unsigned int y = 0; y < imageHeight; y++ )
+  {
+    for ( unsigned int x = 0; x < imageWidth; x++ )
+    {
+      resultImage.setPixelQuick( x, y, 0, imRef(tempResultImage, x, y ).r );
+      resultImage.setPixelQuick( x, y, 1, imRef(tempResultImage, x, y ).g );
+      resultImage.setPixelQuick( x, y, 2, imRef(tempResultImage, x, y ).b );
+    }
+  }
+
+  // Speicher freigeben
+  delete inputImage;
+  inputImage = NULL;
+  delete tempResultImage;
+  tempResultImage = NULL;
+
+  transformSegmentedImg( resultImage, mask);
+
+  return num_ccs;
+}

+ 58 - 0
RSGraphBased.h

@@ -0,0 +1,58 @@
+/**
+ * @file RSGraphBased.h
+ * @brief fast Segmentation Method based on Felzenszwalb2004
+ * @author Björn Fröhlich
+ * @date 02/22/2010
+ */
+#ifndef RSGraphBasedINCLUDE
+#define RSGraphBasedINCLUDE
+
+#include "core/basics/Config.h"
+#include "RegionSegmentationMethod.h"
+
+namespace OBJREC {
+
+class RSGraphBased: public RegionSegmentationMethod
+{
+
+  protected:
+    double parameter_k;
+    int parameter_min_size;
+    double parameter_sigma;
+
+  public:
+    /** simple constructor */
+    RSGraphBased();
+
+    /** simple constructor */
+    RSGraphBased(double t);
+
+    /**
+     * standard constructor
+     * @param conf config file
+     */
+    RSGraphBased(const NICE::Config *conf );
+
+    /** simple destructor */
+    ~RSGraphBased();
+
+    /**
+     * returns the regions of a given image
+     * @param img input image
+     * @param mask output regions, each region has it own number
+     * @return count of region
+     */
+    virtual int segRegions ( const NICE::Image & img, NICE::Matrix & mask ) const;
+
+    /**
+     * returns the regions of a given image
+     * @param img input color image
+     * @param mask output regions, each region has it own number
+     * @return count of region
+     */
+    virtual int segRegions ( const NICE::ColorImage & img, NICE::Matrix & mask) const;
+};
+
+} //namespace
+
+#endif

+ 768 - 0
RSMarkovCluster.cpp

@@ -0,0 +1,768 @@
+#include "RSMarkovCluster.h"
+
+/*
+ Alle Koordinatenangaben orientieren sich an der Matrixschreibweise, dh. (y,x)
+ Zeile y und Spalte x. Gespeichert werden Koordianten (soweit nicht anders angegeben)
+ im typedef Coord. Dieses baut auf std::pair<int,int> auf. Damit ist coord.first die
+ Zeile und coord.second die Spalte.
+*/
+
+
+using namespace OBJREC;
+using namespace NICE;
+using namespace std;
+
+#define DEBUGMODE
+#ifdef DEBUGMODE
+#include <boost/date_time/posix_time/posix_time.hpp>
+using namespace boost::posix_time;
+#endif
+
+RSMarkovCluster::RSMarkovCluster ( const Config* conf )
+{
+  const string section = "MarkovCluster";
+
+  // Parameter aus der Konfigurationsdatei auslesen
+  r   = conf->gD ( section, "clusterradius", 4.5 );
+  mu   = conf->gD ( section, "edgeweight_parameter", 10.0 );
+  p   = conf->gD ( section, "inflation_parameter", 1.4 );
+  chaosThreshold  = conf->gD ( section, "chaos_threshold", 0.001 );
+  iterations = conf->gI ( section, "iterations", 23 );
+}
+
+
+/*
+ offsets = {(y,x) | norm((y,x),2)<=r}
+ Menge aller moeglichen Offsets, dh. offsets enthaelt alle Koordinatenverschiebungen,
+ welche vom Ursprung (0,0) gesehen kleiner als der gegebene compact-pruning-Parameter
+ ist. Dadurch wird die Nachbarschaft definiert und die Groesse der Cluster begrenzt.
+*/
+void
+RSMarkovCluster::precalcOffsets ( RSMarkovCluster::Offsets& offsets ) const
+{
+  // Fuege in die Offsets alle Pixel der 8er Nachbarschaft und sich selber ein.
+  offsets.push_back ( Coord ( 0, 0 ) );
+  offsets.push_back ( Coord ( -1, -1 ) );
+  offsets.push_back ( Coord ( -1, 0 ) );
+  offsets.push_back ( Coord ( -1, 1 ) );
+  offsets.push_back ( Coord ( 0, -1 ) );
+  offsets.push_back ( Coord ( 0, 1 ) );
+  offsets.push_back ( Coord ( 1, -1 ) );
+  offsets.push_back ( Coord ( 1, 0 ) );
+  offsets.push_back ( Coord ( 1, 1 ) );
+
+
+  int bound = round ( this->r );
+
+
+  for ( int m = -bound; m <= bound; m++ )
+  {
+    for ( int n = -bound; n <= bound; n++ )
+    {
+      Coord newCoord ( m, n );
+
+      if ( ( newCoord.pnorm ( 2 ) <= ( this->r ) )
+           && ! ( ( m == -1 ) && ( n == -1 ) )
+           && ! ( ( m == -1 ) && ( n == 0 ) )
+           && ! ( ( m == -1 ) && ( n == 1 ) )
+           && ! ( ( m == 0 ) && ( n == -1 ) )
+           && ! ( ( m == 0 ) && ( n == 0 ) )
+           && ! ( ( m == 0 ) && ( n == 1 ) )
+           && ! ( ( m == 1 ) && ( n == -1 ) )
+           && ! ( ( m == 1 ) && ( n == 0 ) )
+           && ! ( ( m == 1 ) && ( n == 1 ) ) )
+
+      {
+        offsets.push_back ( newCoord );
+      }
+    }
+  }
+}
+
+/*
+ detours[e] = {(i,j) | offsets(i)+offsets(j)=offsets(e)}
+ Menger aller moeglichen 2er Pfade von einem gegebenen Pixel zum offset[e].
+*/
+void
+RSMarkovCluster::precalcDetours ( RSMarkovCluster::Detours& detours, const RSMarkovCluster::Offsets& offsets ) const
+{
+  // Anzahl der offsets (Nachbarn)
+  const uint N_e = offsets.size();
+  // Groesse von Detours anpassen
+  detours.resize ( N_e );
+
+  // diese Tour muss fuer alle Nachbarn berechnet werden
+  for ( uint e = 0; e < N_e; e++ )
+  {
+    // Touren fuer den Offset e
+    vector< pair< uint, uint > > detours_e;
+
+    for ( uint i = 0; i < N_e; i++ )
+    {
+      for ( uint j = 0; j < N_e; j++ )
+      {
+        if ( ( offsets[i].first + offsets[j].first == offsets[e].first ) && ( offsets[i].second + offsets[j].second == offsets[e].second ) )
+        {
+          detours_e.push_back ( pair< uint, uint> ( i, j ) );
+        }
+      }
+    }
+    detours[e] = detours_e;
+  }
+}
+
+int
+RSMarkovCluster::segRegions ( const Image& img, Matrix& mask ) const
+{
+  RSMarkovCluster::Offsets offsets;
+  RSMarkovCluster::Detours detours;
+
+  // Vorausberechnungen der fuer das Clustering erforderlichen Offsets und Detours.
+  precalcOffsets ( offsets );
+  const uint n_e = offsets.size();
+
+  precalcDetours ( detours, offsets );
+
+  // Bilddaten
+  const uchar* imageData    = img.getPixelPointerXY ( 0, 0 );
+  const uint   imageHeight  = img.height();
+  const uint   imageWidth   = img.width();
+  const uint   channelCount = img.channels();
+
+  // MarkovMatrix
+  NodeCentricRepMatrix L ( imageHeight, imageWidth, n_e );
+
+  // Initialisierung der MarkovMatrix.
+  initMarkovMatrix ( imageData, imageHeight, imageWidth, channelCount, offsets, L );
+
+
+#ifdef DEBUGMODE
+  // Anfangszeitpunkt
+  ptime start ( microsec_clock::local_time() ); //
+#endif
+  // Start des MarkovClustering Prozesses
+  runClustering ( offsets, detours, L );
+#ifdef DEBUGMODE
+  // Endzeitpunkt
+  ptime end ( microsec_clock::local_time() );   //
+  printf ( "[log] Laufzeit Clustering: %ld.%3ldsek\n", ( end - start ).total_milliseconds() / 1000, ( end - start ).total_milliseconds() % 1000 );
+#endif
+
+  // Finde die Cluster innerhalb der Matrix
+  const uint clusterCount = findCluster ( offsets, L, mask );
+
+  return clusterCount;
+}
+
+int
+RSMarkovCluster::segRegions ( const ColorImage &cimg, Matrix &mask ) const
+{
+  RSMarkovCluster::Offsets offsets;
+  RSMarkovCluster::Detours detours;
+
+  // Vorausberechnungen der fuer das Clustering erforderlichen Offsets und Detours.
+  precalcOffsets ( offsets );
+  const uint n_e = offsets.size();
+
+  precalcDetours ( detours, offsets );
+
+  // Bilddaten
+  const uchar* imageData    = cimg.getPixelPointerXY ( 0, 0 );
+  const uint   imageHeight  = cimg.height();
+  const uint   imageWidth   = cimg.width();
+  const uint   channelCount = cimg.channels();
+
+  // MarkovMatrix
+  NodeCentricRepMatrix L ( imageHeight, imageWidth, n_e );
+
+  // Initialisierung der MarkovMatrix.
+  initMarkovMatrix ( imageData, imageHeight, imageWidth, channelCount, offsets, L );
+
+#ifdef DEBUGMODE
+  // Anfangszeitpunkt
+  ptime start ( microsec_clock::local_time() ); //
+#endif
+  // Start des MarkovClustering Prozesses
+  runClustering ( offsets, detours, L );
+#ifdef DEBUGMODE
+  // Endzeitpunkt
+  ptime end ( microsec_clock::local_time() );   //
+  printf ( "[log] Laufzeit Clustering: %ld.%3ldsek\n", ( end - start ).total_milliseconds() / 1000, ( end - start ).total_milliseconds() % 1000 );
+#endif
+
+  // Finde die Cluster innerhalb der Matrix
+  const uint clusterCount = findCluster ( offsets, L, mask );
+
+  return clusterCount;
+}
+
+int
+RSMarkovCluster::findCluster ( const RSMarkovCluster::Offsets & offsets, NodeCentricRepMatrix& L, Matrix& mask ) const
+{
+  // Bild zum Anzeigen der Attracktoren
+  Matrix att ( L.getM(), L.getN(), 0.0 );
+  // L' Matrix: dort werden die Veraenderungen der L-Matrix gespeichert.
+  NodeCentricRepMatrix M ( L.getM(), L.getN(), L.getE() );
+
+
+  Image attImage ( L.getN(), L.getM() );
+  for ( uint y = 0;y < L.getM();y++ )
+  {
+    for ( uint x = 0;x < L.getN();x++ )
+    {
+      attImage.setPixel ( x, y, 0 );
+    }
+  }
+
+
+  printf ( "schwache Kanten entfernen\n" );
+
+  // Delta um den Kantenschwellwert zu berechnen. Dieser wird von der Summe der abgehenden Kanten abgezogen
+  const double delta = 0.01;
+  // Loeschen von schwachten Kanten & Finden der Attracktoren.
+  for ( uint y = 0;y < L.getM();y++ )
+  {
+    for ( uint x = 0;x < L.getN();x++ )
+    {
+      // Pointer auf das die "Nachbarschaft"
+      double* efirst = &L ( y, x, 0 );
+      // Alle Kanten, die vom Knoten (y,x) abgehen
+      valarray<double> outgoingEdges = valarray<double> ( efirst, L.getE() );
+      // die Summe der quadratischen abgehenden Kantengewichte
+      double edgeThreshold = pow ( outgoingEdges, 2.0 ).sum() - delta;
+
+      for ( uint e = 0;e < L.getE();e++ )
+      {
+        if ( L ( y, x, e ) >= edgeThreshold )
+        {
+          M ( y, x, e ) = L ( y, x, e );
+        }
+        else
+        {
+          M ( y, x, e ) = 0.0;
+        }
+        if ( L ( y, x, e ) > L ( y, x, 0 ) )
+        {
+          M ( y, x, e ) = L ( y, x, e );
+        }
+        else
+        {
+          M ( y, x, e ) = 0.0;
+        }
+
+      }
+
+      // Pointer auf das die "Nachbarschaft"
+      efirst = &M ( y, x, 0 );
+      // Alle Kanten, die vom Knoten (y,x) abgehen
+      outgoingEdges = valarray<double> ( efirst, M.getE() );
+      // die Summe der quadratischen abgehenden Kantengewichte
+      double edgeSum = outgoingEdges.sum();
+
+      if ( edgeSum == 0.0 )
+        //if(M(y,x,0)!=0.0)
+      {
+        att ( y, x ) = 1.0;
+        if ( L ( y, x, 0 ) > 0.75 )
+          attImage.setPixel ( x, y, 255 );
+        else if ( L ( y, x, 0 ) > 0.5 )
+          attImage.setPixel ( x, y, 180 );
+        else if ( L ( y, x, 0 ) > 0.25 )
+          attImage.setPixel ( x, y, 100 );
+        else
+          attImage.setPixel ( x, y, 50 );
+      }
+    }
+  }
+
+  showImage ( attImage );
+
+  printf ( "aquivalenzklassen finden\n" );
+  for ( uint y = 0;y < att.rows();y++ )
+  {
+    for ( uint x = 0;x < att.cols();x++ )
+    {
+      // aktueller Pixel ist ein Attraktor
+      if ( att ( y, x ) == 1.0 )
+      {
+        uint strongestAttIndex = 0;
+        double strongestAttValue = 0.0;
+
+        for ( uint e = 1;e < L.getE();e++ )
+        {
+          // "-->" Relation
+          if ( L ( y, x, e ) > 0 )
+          {
+            Coord st = Coord ( y, x ) + offsets[e];
+            if ( att ( st.first, st.second ) == 1.0 )
+            {
+              // benachbarter Attraktor gefunden
+
+              // Welcher der beiden ist der "staerkere" ?
+              if ( ( L ( y, x, 0 ) <= L ( st.first, st.second, 0 ) ) && ( L ( st.first, st.second, 0 ) > strongestAttValue ) )
+              {
+                strongestAttValue = L ( st.first, st.second, 0 );
+                strongestAttIndex = e;
+              }
+            }
+          }
+        }
+
+        if ( strongestAttIndex != 0 )
+        {
+          M ( y, x, strongestAttIndex ) = strongestAttValue;
+          att ( y, x ) = 0.0;
+          attImage.setPixel ( x, y, 0 );
+        }
+      }
+    }
+  }
+  showImage ( attImage );
+
+  //return 0;
+  // Erste Operation auf der Ausgabemaske: Markieren der Attraktoren
+
+  uint clusterCount = 0;
+  printf ( "Attraktoren markieren\n" );
+//#pragma omp parallel for
+  for ( uint y = 0;y < att.rows();y++ )
+  {
+    for ( uint x = 0;x < att.cols();x++ )
+    {
+      if ( att ( y, x ) == 1.0 )
+      {
+        // Jeder Attraktor bekommt eine eindeutige Identifikation & wird in der Maske markiert
+        mask ( y, x ) = ++clusterCount;
+      }
+    }
+  }
+  printf ( "Attraktoren markiert\n" );
+
+  printf ( "bla\n" );
+  printf ( "finde cluster\n" );
+
+  for ( uint y = 0;y < mask.rows();y++ )
+  {
+    for ( uint x = 0;x < mask.cols();x++ )
+    {
+      if ( mask ( y, x ) == 0.0 )
+      {
+        // (x,y) Pixel wurde noch keinem Cluster zugewiesen
+        Coord st = Coord ( y, x );
+        do
+        {
+          // Pointer auf das die "Nachbarschaft"
+          const double* efirst = &M.at ( st.first, st.second, 0 );
+          // Alle Kanten, die vom Knoten (y,x) abgehen
+          const valarray<double> outgoingEdges = valarray<double> ( efirst, M.getE() );
+          // maximaler Kantenwert, der von (y,x) abgeht
+          const double maxEdgeWeight = outgoingEdges.max();
+
+          // (s,t) Nachbarpixel zu dem die staerkste Kante fuerhte
+          uint e = 0;
+          for ( ;e < M.getE();e++ ) {
+            if ( M ( st.first, st.second, e ) == maxEdgeWeight ) break;
+          };
+          st += offsets[e];
+          //printf("(%d,%d)\n",st.second,st.first);
+        } while ( att ( st.first, st.second ) == 0.0 );
+
+        mask ( y, x ) = mask ( st.first, st.second );
+      }
+    }
+  }
+
+
+
+  //showImage(att);
+
+  return clusterCount;
+
+
+  //printf("[log] start clustering\n");
+  // erzeuge den DAG fuer die L-Matrix. Dh. es werden nur Kanten behalten, welche folgendes Kriterium erfuellen:
+  // seien A,B Knoten aus V und sei w(*) das Gewicht der Kante der beiden Knoten. Dann enthaelt der DAG nur die
+  // Kanten, fuer die gilt: w(A->B)>w(A->A). Dabei entstehen senken, welche welche von den Attracktoren gebildet
+  // werden, da diese diese Bedingung nicht erfüllen. Dieses Vorgehen erzeugt ein ueberlappendes Clustering, dass
+  // in der Bildsegmentierung nicht gewuenscht ist. Darum wird der DAG wie folgt erweitert:
+  // Def. siehe oben. Zusaetzliche Bedingung ist, dass w(A->B) die staerkste abgehende Kante von A ist.
+
+  // Maske zum Speichern der max. Kante. Dabei wird der entsprechende Offsetindex gespeichert.
+  //Matrix maxEdgeIndexMatrix(L.getM(),L.getN(),-1);
+
+  /*
+  #pragma omp parallel for
+  for(uint y=0;y<L.getM();y++)
+  {
+   for(uint x=0;x<L.getN();x++)
+   {
+    // Pointer auf das die "Nachbarschaft"
+    double* efirst=&L.at(y,x,0);
+    // Alle Kanten, die vom Knoten (y,x) abgehen
+    valarray<double> outgoingEdges=valarray<double>(efirst,L.getE());
+    // maximaler Kantenwert, der von (y,x) abgeht
+    double maxEdgeWeight=outgoingEdges.max();
+
+
+    if(maxEdgeWeight==0.5) printf("[debug] max. edgeweight=%.2f\n",maxEdgeWeight);
+
+    // Alle Kanten loeschen, die kleineres Gewicht als
+    for(uint e=0;e<L.getE();e++)
+    {
+     if(L.at(y,x,e)!=maxEdgeWeight)
+     {
+      L.at(y,x,e)=0.0;
+     }
+     else
+     {
+      // Index der maximalen Kante wird gespeichert.
+      maxEdgeIndexMatrix(y,x)=e;
+     }
+
+    }
+   }
+  }
+  */
+
+  /*
+  for(uint y=0;y<L.getM();y++)
+  {
+   for(uint x=0;x<L.getN();x++)
+   {
+    // wenn es sich um einen Attracktor handelt, dann ist der Eintrag in der maxEdgeIndexMatrix=0
+    if(maxEdgeIndexMatrix(y,x)==0)
+    {
+     clusterCount++;
+     mask(y,x)=indexOfPixel(Coord(y,x),L.getN());
+     continue;
+    }
+
+    Coord st(y,x);
+    do
+    {
+     // Update st auf die Koordinaten des Knotens zu dem die staerkste Kante geht.
+     st+=offsets[maxEdgeIndexMatrix(st.first,st.second)];
+
+     // Wir sind auf einen Pixel gestossen, der bereits markiert ist.
+     if(mask(st.first,st.second)!=(-1))
+     {
+      mask(y,x)=mask(st.first,st.second);
+      break;
+     }
+    }while(maxEdgeIndexMatrix(st.first,st.second)!=0);
+
+    if(mask(y,x)==(-1)) mask(y,x)=indexOfPixel(st,L.getN());
+   }
+  }*/
+
+
+  //return clusterCount;
+}
+
+inline uint
+RSMarkovCluster::indexOfPixel ( const Coord& yx, const uint xSize ) const
+{
+  return yx.first*xSize + yx.second;
+}
+
+
+void
+RSMarkovCluster::normalize ( NodeCentricRepMatrix& L ) const
+{
+#pragma omp parallel for
+  for ( uint y = 0;y < L.getM();y++ )
+  {
+    for ( uint x = 0;x < L.getN();x++ )
+    {
+      // Pointer auf das die "Nachbarschaft"
+      double* efirst = &L ( y, x, 0 );
+      // Alle Kanten, die vom Knoten (y,x) abgehen
+      valarray<double> outgoingEdges = valarray<double> ( efirst, L.getE() );
+      // maximaler Kantenwert, der von (y,x) abgeht
+      double sum = outgoingEdges.sum();
+
+      for ( uint e = 0;e < L.getE();e++ )
+      {
+        L ( y, x, e ) = checkForNAN ( L ( y, x, e ) / sum );
+      }
+
+    }
+  }
+
+}
+
+void
+RSMarkovCluster::inflation ( const NodeCentricRepMatrix& Lin, NodeCentricRepMatrix& Lout ) const
+{
+#pragma omp parallel for
+  for ( uint y = 0;y < Lin.getM();y++ )
+  {
+    for ( uint x = 0;x < Lin.getN();x++ )
+    {
+      for ( uint e = 0;e < Lin.getE();e++ )
+      {
+        Lout ( y, x, e ) = checkForNAN ( pow ( Lin ( y, x, e ), this->p ) );
+      }
+    }
+  }
+}
+
+void
+RSMarkovCluster::expansion ( const NodeCentricRepMatrix& Lin, NodeCentricRepMatrix& Lout, const Offsets& offsets, const Detours& detours ) const
+{
+#pragma omp parallel for
+  for ( uint y = 0;y < Lin.getM();y++ )
+  {
+    for ( uint x = 0;x < Lin.getN();x++ )
+    {
+      // neues Kantengewicht fuer alle "adjazenten" Knoten berechnen
+      for ( uint e = 0;e < Lin.getE();e++ )
+      {
+        double w_xy_mn = 0.0;
+
+        for ( uint d = 0;d < detours[e].size();d++ )
+        {
+          uint efirst = detours[e][d].first;
+          uint esecond = detours[e][d].second;
+
+          Coord st = Coord ( y, x ) + offsets[efirst];
+
+          double w_xy_st = 0.0;
+          double w_st_mn = 0.0;
+
+          if ( ( st.first >= 0 ) && ( st.first < (int)Lin.getM() ) && ( st.second >= 0 ) && ( st.second < (int)Lin.getN() ) )
+          {
+            w_xy_st = Lin ( y, x, efirst );
+            w_st_mn = Lin ( st.first, st.second, esecond );
+          }
+
+          w_xy_mn += w_xy_st * w_st_mn;
+        }
+        Lout ( y, x, e ) = checkForNAN ( w_xy_mn );
+      }
+    }
+  }
+}
+
+inline double
+RSMarkovCluster::checkForNAN ( const double val ) const
+{
+  if ( ! ( val == val ) || ( val == -std::numeric_limits < double >::quiet_NaN () ) )
+    return 0.0;
+  else
+    return val;
+}
+
+void
+RSMarkovCluster::runClustering ( const RSMarkovCluster::Offsets& offsets, const RSMarkovCluster::Detours& detours, NodeCentricRepMatrix& L1 ) const
+{
+  //printMatrix(L1,offsets,"Linit");
+
+  // Initialisierte Markovmatrix muss normalisiert werden.
+  normalize ( L1 );
+
+  // Mass fuer die Aenderungen innerhalb der Matrix.
+  //double chaos = 1.0;
+  //uint sameChaosCounter = 0; // Wenn sich Chaos eine bestimmte Anzahl von Iterationen nicht mehr veraendert, dann wird abgebrochen.
+  // 2te Markovmatrix zum Vergleichen der Veraenderungen
+  NodeCentricRepMatrix L2 ( L1.getM(), L1.getN(), L1.getE() );
+
+  uint iterationCounter = 0;
+
+#ifdef DEBUGMODE
+  time_duration expAvgTime ( 0, 0, 0, 0 );
+  time_duration infAvgTime ( 0, 0, 0, 0 );
+  time_duration norAvgTime ( 0, 0, 0, 0 );
+#endif
+  printf ( "%d\n", iterations );
+
+  //while(chaos>chaosThreshold)
+  while ( iterationCounter < (uint)iterations )
+  {
+#ifdef DEBUGMODE
+    // Anfangszeitpunkt
+    ptime start ( microsec_clock::local_time() ); //
+#endif
+    // rufe Matrix L1 und speichere in Matrix L2 (L2<--exp(L1))
+    expansion ( L1, L2, offsets, detours );
+#ifdef DEBUGMODE
+    // Endzeitpunkt
+    ptime end ( microsec_clock::local_time() );   //
+
+    // Zeit, die der Expansionschritt gebraucht hat.
+    time_duration expDuration ( end - start );
+    printf ( "[log] expansion: %ld.%3ldsek\n", expDuration.total_milliseconds() / 1000, expDuration.total_milliseconds() % 1000 );
+
+    // Gesamtlaufzeit des Expansionschritts
+    expAvgTime += expDuration;
+#endif
+#ifdef DEBUGMODE
+    // Anfangszeitpunkt
+    start = microsec_clock::local_time(); //
+#endif
+    // rufe Matrix L2 und speichere in Matrix L1 (L1<--inf(L2))
+    inflation ( L2, L1 );
+#ifdef DEBUGMODE
+    // Endzeitpunkt
+    end = microsec_clock::local_time(); //
+
+    // Zeit, die der Expansionschritt gebraucht hat.
+    time_duration infDuration ( end - start );
+    printf ( "[log] inflation: %ld.%3ldsek\n", infDuration.total_milliseconds() / 1000, infDuration.total_milliseconds() % 1000 );
+
+    // Gesamtlaufzeit des Expansionschritts
+    infAvgTime += infDuration;
+#endif
+#ifdef DEBUGMODE
+    // Anfangszeitpunkt
+    start = microsec_clock::local_time(); //
+#endif
+    // vor dem Ende jeder Iteration muss normalisiert werden.
+    normalize ( L1 );
+#ifdef DEBUGMODE
+    // Endzeitpunkt
+    end = microsec_clock::local_time(); //
+
+    // Zeit, die der Expansionschritt gebraucht hat.
+    time_duration norDuration ( end - start );
+    printf ( "[log] normalize: %ld.%3ldsek\n", norDuration.total_milliseconds() / 1000, norDuration.total_milliseconds() % 1000 );
+
+    // Gesamtlaufzeit des Expansionschritts
+    norAvgTime += norDuration;
+#endif
+
+    //double lastChaos=chaos;
+    // berechne die Veraenderungen der Matrix nach dem Schritt t
+    //double maxDiffValue=NodeCentricRepMatrix::maxValue(L1-L2);
+    //chaos=min(maxDiffValue,chaos);
+
+    //printf("[log] %d iteration: chaos=%.5f\n",iterationCounter,chaos);
+    //printf("[debug] %.5f\n",maxDiffValue);
+
+    iterationCounter++;
+    printf ( "[log] %d. Iteration\n", iterationCounter );
+
+    /*
+    if(lastChaos==chaos)
+    {
+     sameChaosCounter++;
+
+     if(sameChaosCounter==maxConstantInteration)
+     {
+      break;
+     }
+    }
+    else
+    {
+     sameChaosCounter=0;
+    }
+    */
+  }
+
+#ifdef DEBUGMODE
+  long int expAvgTimeUSec = expAvgTime.total_milliseconds() / ( iterationCounter - 1 );
+  long int infAvgTimeUSec = infAvgTime.total_milliseconds() / ( iterationCounter - 1 );
+  long int norAvgTimeUSec = norAvgTime.total_milliseconds() / ( iterationCounter - 1 );
+
+  printf ( "[log] Durchschnittszeit fuer Expansion: %ld.%3ldsek\n", expAvgTimeUSec / 1000, expAvgTimeUSec % 1000 );
+  printf ( "[log] Durchschnittszeit fuer Inflation: %ld.%3ldsek\n", infAvgTimeUSec / 1000, infAvgTimeUSec % 1000 );
+  printf ( "[log] Durchschnittszeit fuer Normalize: %ld.%3ldsek\n", norAvgTimeUSec / 1000, norAvgTimeUSec % 1000 );
+#endif
+}
+
+
+void
+RSMarkovCluster::initMarkovMatrix ( const uchar* imageData, const uint imageHeight, const uint imageWidth, const uint channelCount, const RSMarkovCluster::Offsets& offsets, NodeCentricRepMatrix& L ) const
+{
+  // Initialisierung erfolgt fuer jeden Pixel und die 8er Nachbarschaft. Dabei wird im Loops initialisiert.
+#pragma omp parallel for
+  for ( uint y = 0;y < imageHeight;y++ )
+  {
+    for ( uint x = 0;x < imageWidth;x++ )
+    {
+      for ( uint e = 0; e < 9; e++ )
+      {
+        // Koordinaten des Nachbarpixels
+        RSMarkovCluster::Coord yxN = RSMarkovCluster::Coord ( y, x ) + offsets[e];
+
+        // Eine Verbindung zu einem Nachbarn ausserhalb des Bildes hat das Gewicht 0.
+        if ( ( yxN.first < 0 ) || ( yxN.first >= (int)imageHeight ) || ( yxN.second < 0 ) || ( yxN.second >= (int)imageWidth ) )
+          continue;
+
+        Vector imageValue ( channelCount );
+
+        for ( uint c = 0;c < channelCount;c++ )
+        {
+          uint indexP = y * imageWidth * channelCount + x * channelCount + c;
+          uint indexN = yxN.first * imageWidth * channelCount + yxN.second * channelCount + c;
+
+          imageValue[c] = ( double ( imageData[indexP] ) - double ( imageData[indexN] ) ) / 255.0;
+        }
+
+        L.at ( y, x, e ) = edgeWeight ( imageValue );
+      }
+    }
+  }
+}
+
+inline double
+RSMarkovCluster::edgeWeight ( const Vector& imageValueDiff ) const
+{
+  return exp ( - ( this->mu ) * pow ( imageValueDiff.normL2 (), 2 ) );
+}
+
+void
+RSMarkovCluster::printMatrix ( const NodeCentricRepMatrix& L, const RSMarkovCluster::Offsets& offsets , const string& filename ) const
+{
+  // Bemerkung in Offset ist [0]=x && [1]=y
+  const uint n_x = L.getN ();
+  const uint n_y = L.getM ();
+  const uint n_e = L.getE ();
+  Matrix oMatrix ( ( n_y*n_x ), ( n_y*n_x ) );
+
+  Matrix::iterator it = oMatrix.begin();
+  for ( ;it != oMatrix.end();++it ) {
+    ( *it ) = 0;
+  }
+
+  for ( uint y = 0;y < n_y;y++ )
+  {
+    for ( uint x = 0;x < n_x;x++ )
+    {
+      for ( uint e = 0;e < n_e;e++ )
+      {
+        double value = L.at ( y, x, e );
+        int n = offsets[e].second;
+        int m = offsets[e].first;
+
+        int indexP = y * n_x + x;
+        int indexN = ( y + m ) * n_x + ( x + n );
+
+        if ( ( indexP >= 0 ) && ( indexP < ( n_y*n_x ) ) && ( indexN >= 0 ) && ( indexN < ( n_y*n_x ) ) )
+          oMatrix ( indexP, indexN ) = value;
+      }
+    }
+  }
+
+  ofstream fout;
+  fout.open ( filename.c_str() );
+  for ( int y = 0;y < ( n_y*n_x );y++ )
+  {
+    string line = "";
+    for ( int x = 0;x < ( n_y*n_x );x++ )
+    {
+      if ( oMatrix ( x, y ) == 0.0 ) line += "----\t";
+      else
+      {
+        char entry[16];
+        sprintf ( entry, "%.3f\t", oMatrix ( x, y ) );
+        line += string ( entry );
+      }
+
+    }
+    fout << line << endl;
+  }
+  fout.close();
+}
+
+

+ 174 - 0
RSMarkovCluster.h

@@ -0,0 +1,174 @@
+#ifndef RSMARKOVCLUSTER
+#define RSMARKOVCLUSTER
+
+#include <core/vector/VectorT.h>
+#include <core/basics/Config.h>
+#include <segmentation/math/NodeCentricRepMatrix.h>
+#include <core/vector/VVector.h>
+#include <segmentation/RegionSegmentationMethod.h>
+
+#include <core/imagedisplay/ImageDisplay.h>
+
+// std - includes
+#include <algorithm>
+#include <limits>
+#include <sys/types.h>
+
+namespace OBJREC
+{
+class RSMarkovCluster : public RegionSegmentationMethod
+{
+    /* Typedefs und Memberklassen */
+  public:
+    /**
+    * @brief Memberklasse um ein Koordinatenpaar zu repraesentieren.
+    */
+    class Coord : public std::pair< int, int >
+    {
+      public:
+        //! Standard-Konstruktor
+        Coord() : std::pair<int, int>() {};
+
+        //! Initialisierungs-Konstruktor
+        Coord ( const int y, const int x ) : std::pair<int, int> ( y, x ) {};
+
+        //! Copy-Konstruktor
+        Coord ( Coord const& coord ) : std::pair <int, int> ( coord ) {};
+
+        //! Standard-Destruktor
+        ~Coord() {};
+
+        /**
+        * @brief Einfache Methode zum berechnen der PNorm eines Koordinatenpaares.
+        * @param p - Normart
+        * @return p-Norm
+        */
+        inline double pnorm ( const uint p ) const
+        {
+          return pow ( pow ( abs ( std::pair< int, int >::first ), p ) + pow ( abs ( std::pair< int, int >::second ), p ), ( 1.0 / p ) );
+        };
+
+        /* Operatoren */
+        //! =+ operator
+        Coord& operator+= ( Coord const& rhs )
+        {
+          ( *this ).first += rhs.first;
+          ( *this ).second += rhs.second;
+          return ( *this );
+        };
+        //! + operator
+        Coord operator+ ( Coord const& rhs )
+        {
+          Coord tmp ( ( *this ) );
+          tmp += rhs;
+          return tmp;
+        };
+    };
+
+  private:
+    //! Simpler Datentyp um die Offsets zu speichern.
+    typedef std::vector< RSMarkovCluster::Coord > Offsets;
+    //! Simpler Datentyp zum Speichern der Detours.
+    typedef std::vector< std::vector< std::pair< uint, uint > > > Detours;
+
+    /* Membermethoden und -variablen */
+  public:
+    //! Standard-Konstruktor
+    RSMarkovCluster ( const NICE::Config* conf );
+
+    //! Standard-Destruktor
+    ~RSMarkovCluster() {};
+
+    /* Ueberschriebene Methoden */
+    /**
+    * @brief Segmentierungsmethode.
+    * @param Image - (Grauwert) Eingabebild
+    * @param Matrix - Segmentierungsmaske
+    */
+    int segRegions ( const NICE::Image &img, NICE::Matrix &mask ) const;
+
+    /**
+    * @brief Segmentierungsmethode.
+    * @param ColorImage - (Farbbild) Eingabebild
+    * @param Matrix - Segmentierungsmaske
+    */
+    int segRegions ( const NICE::ColorImage &cimg, NICE::Matrix &mask ) const;
+
+  private:
+    int iterations;
+    //! Clusterradius
+    double r;
+    //! Edgeweight Parameter
+    double mu;
+    //! Inflation Parameter
+    double p;
+    //! Chaosthreshold
+    double chaosThreshold;
+
+
+    /* */
+    /**
+    * @brief Vorausberechnung der Offsets
+    */
+    void precalcOffsets ( Offsets& offsets ) const;
+
+    /**
+    * @brief Vorausberechnung der Detours
+    */
+    void precalcDetours ( Detours& detours, const Offsets& offsets ) const;
+
+    /**
+    * @brief Finder Cluster und markieren derer in der mark Maske.
+    */
+    int findCluster ( const Offsets& offsets, OBJREC::NodeCentricRepMatrix& L, NICE::Matrix& mark ) const;
+
+    /**
+    * @brief Errechnen des Indexes eines Pixels anhand seiner Koordinaten.
+    */
+    inline uint indexOfPixel ( const Coord& yx, const uint xSize ) const;
+
+    /**
+    * @brief Normalisieren der L Matrix. Dh. alle abgehenenden Kanten werden zu 1 normiert.
+    */
+    void normalize ( OBJREC::NodeCentricRepMatrix& L ) const;
+
+    /**
+    * @brief Inflationoperator anwenden. Es gilt: Lout<--inf(Lin)
+    */
+    void inflation ( const OBJREC::NodeCentricRepMatrix& Lin, OBJREC::NodeCentricRepMatrix& Lout ) const;
+
+    /**
+    * @brief Expansionoperator anwenden. Es gilt: Lout<--exp(Lin)
+    */
+    void expansion ( const OBJREC::NodeCentricRepMatrix& Lin, OBJREC::NodeCentricRepMatrix& Lout, const Offsets& offsets, const Detours& detours ) const;
+
+    /**
+    * @brief Ueberprueft auf negativ NaN und gibt in dem Falle 0.0 zurueck, sonst val.
+    */
+    inline double checkForNAN ( const double val ) const;
+
+    /**
+    * @brief Anwenden des Clusterings auf die L1-Matrix.
+    * @note Kovergenzkriterium ist die Veraenderung innerhalb der Matrix zwischen aufeinanderfolgenden Iterationen.
+    */
+    void runClustering ( const Offsets& offsets, const Detours& detours, OBJREC::NodeCentricRepMatrix& L1 ) const;
+
+    /**
+    * @brief Initialisierung der MarkovMatrix. Diese Methode ist anwendbar fuer Farb- und Grauwertbilder.
+    */
+    void initMarkovMatrix ( const uchar* imageData, const uint imageHeight, const uint imageWidth, const uint channelCount, const Offsets& offsets, OBJREC::NodeCentricRepMatrix& L ) const;
+
+    /**
+    * @brief Berechnung der Kantenstaerke fuer eine gegebene Farb- oder Grauwertdifferenz.
+    */
+    inline double edgeWeight ( const NICE::Vector& imageValueDiff ) const;
+
+    /**
+    * @brief Ausgabe der Matrix in eine Datei. VORSICHT: nur fuer sehr kleine Bilder anwenden.
+    */
+    void printMatrix ( const OBJREC::NodeCentricRepMatrix& L, const Offsets& offsets, const std::string& filename ) const;
+
+};
+}
+
+#endif

+ 141 - 0
RSMeanShift.cpp

@@ -0,0 +1,141 @@
+#include "RSMeanShift.h"
+
+#ifdef NICE_USELIB_OPENMP
+#include <omp.h>
+#endif
+
+#include <iostream>
+#include <fstream>
+
+#include "core/basics/StringTools.h"
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+RSMeanShift::RSMeanShift()
+{
+  minimumRegionArea = 50;
+  rangeBandwidth = 6.5;
+
+  spatialBandwidth = 7;
+
+  imageProc = new msImageProcessor();
+  speedUpLevel =  MED_SPEEDUP;
+}
+RSMeanShift::RSMeanShift ( const Config *conf )
+{
+  imageProc = new msImageProcessor();
+  minimumRegionArea = conf->gI ( "RSMeanShift", "MinimumRegionArea",            50 );
+  rangeBandwidth    = conf->gD ( "RSMeanShift", "RangeBandwidth",              6.5 );
+  spatialBandwidth  = conf->gI ( "RSMeanShift", "SpatialBandwidth",              7 );
+  speedUpLvlStr     = conf->gS ( "RSMeanShift", "SpeedUpLevel",           "MEDIUM" );
+  if ( speedUpLvlStr ==   "NONE" ) speedUpLevel =   NO_SPEEDUP;
+  else if ( speedUpLvlStr == "MEDIUM" ) speedUpLevel =  MED_SPEEDUP;
+  else if ( speedUpLvlStr ==   "HIGH" ) speedUpLevel = HIGH_SPEEDUP;
+  else
+  {
+    cerr << "[err] RSMeanShift::RSMeanShift: Wrong SpeedUpLevel-Value (" << speedUpLvlStr << ") only NONE, MEDIUM and HIGH allowed! Take default Value (MED_SPEEDUP)" << endl;
+    speedUpLevel = MED_SPEEDUP;
+  }
+}
+
+RSMeanShift::~RSMeanShift()
+{
+  delete imageProc;
+}
+
+int RSMeanShift::segRegions ( const NICE::Image & img, NICE::Matrix & mask ) const
+{
+  ColorImage cimg ( img.width(), img.height() );
+  for(int y = 0; y < img.height(); y++)
+  {
+    for(int x = 0; x < img.width(); x++)
+    {
+      for(int c = 0; c < 3; c++)
+      {
+        cimg.setPixelQuick(x,y,c,img.getPixelQuick(x,y));
+      }
+    }
+  }
+  return segRegions ( cimg, mask );
+}
+
+int RSMeanShift::segRegions ( const NICE::ColorImage & img, NICE::Matrix & mask ) const
+{
+  clog << "[log] RSMeanShift::segRegions: EDISON-Implementation" << endl;
+
+  /* >> ColorImage an EDISON uebergeben
+
+     BEM: Dabei werden die Bilddaten als Pointer an die msImageProcessor::DefineImage Methode uebergeben.
+     Der Parameter hat in der EDISON-Implementierung KEINEN 'const' Qualifier.
+  */
+  unsigned int width   = img.width();
+  unsigned int height  = img.height();
+  const unsigned int channels = 3;
+  // notwendiger Bildspeicher
+  const unsigned int imageSize = width * height * channels;
+
+
+  byte* rawImageData = NULL;
+#ifdef NICE_USELIB_IPP
+  /* ipp Speichert die Bilddaten anders, so dass das Bild pixelweise kopiert werden muss. */
+  // Speicher fuer das Bild reservieren
+  rawImageData = new byte[ imageSize ];
+  // Pixelkoordinaten
+  unsigned int x, y;
+  x = y = 0;
+  // "Breite" des Bildes im Speicher
+  // unsigned int yStepWidth = width * 3;
+
+  for ( unsigned int i = 0; i < imageSize; i += 3 )
+  {
+    rawImageData[ i     ] = img.getPixel ( x, y, 0 );
+    rawImageData[ i + 1 ] = img.getPixel ( x, y, 1 );
+    rawImageData[ i + 2 ] = img.getPixel ( x, y, 2 );
+
+    // neue Pixelkoordinaten berechnen
+    if ( ( ++x ) == width ) {
+      x = 0;
+      y++;
+    }
+  }
+#else
+  // img in nicht 'const' ColorImage kopieren
+  ColorImage tempImage ( img );
+  rawImageData = tempImage.getPixelPointer();
+#endif
+  imageProc->DefineImage ( rawImageData, COLOR, height, width );
+
+  /* >> Segementierung durchfuehren */
+  imageProc->Segment ( spatialBandwidth, rangeBandwidth, minimumRegionArea, speedUpLevel );
+
+  /* >> Ergebnisbild aus EDISON auslesen */
+  byte resultRawImageData[ width * height * 3 ];
+  imageProc->GetResults ( resultRawImageData );
+
+  /* >> Maske erstellen */
+#ifdef NICE_USELIB_IPP
+  delete[] rawImageData;
+  rawImageData = 0;
+
+  ColorImage ippTempImage ( width, height );
+
+  x = y = 0;
+
+  for ( unsigned int i = 0; i < imageSize; i += 3 )
+  {
+    ippTempImage.setPixel ( x, y, 0, resultRawImageData[ i     ] );
+    ippTempImage.setPixel ( x, y, 1, resultRawImageData[ i + 1 ] );
+    ippTempImage.setPixel ( x, y, 2, resultRawImageData[ i + 2 ] );
+
+    // neue Pixelkoordinaten berechnen
+    if ( ( ++x ) == width ) {
+      x = 0;
+      y++;
+    }
+  }
+  return transformSegmentedImg ( ippTempImage, mask );
+#else
+  return transformSegmentedImg ( ColorImage ( resultRawImageData, width, height, GrayColorImageCommonImplementation::noAlignment ), mask );
+#endif
+}

+ 70 - 0
RSMeanShift.h

@@ -0,0 +1,70 @@
+/**
+ * @file RSMeanShift.h
+ * @brief implementation of the MeanShift algorithm (uses EDISON)
+ * @author Björn Fröhlich
+ * @date 05/05/2009
+ */
+#ifndef RSMEANSHIFT
+#define RSMEANSHIFT
+
+#include "core/basics/Config.h"
+#include "RegionSegmentationMethod.h"
+
+#include <segmentation/edisonSegm/tdef.h>
+#include <segmentation/edisonSegm/msImageProcessor.h>
+
+namespace OBJREC {
+
+class RSMeanShift: public RegionSegmentationMethod
+{
+
+  protected:
+    //! Specifies the minimum allowable region area (in pixels) contained in the segmented image
+    int minimumRegionArea;
+
+    //! Specifies the bandwidth of the search window in the range subspace during the computation of mean shift
+    double rangeBandwidth;
+
+    //! Specifies a spatial search window of size (2r+1)x (2r+1) during the mean shift computation, where r is the spatial bandwidth
+    int spatialBandwidth;
+
+    //! Specifies the SpeedUpLevel. See EDISON Manual for details.
+    std::string speedUpLvlStr;
+    SpeedUpLevel speedUpLevel;
+
+    //! EDISON - ImageProcessor
+    msImageProcessor *imageProc;
+
+  public:
+    /** simple constructor */
+    RSMeanShift();
+
+    /**
+     * standard constructor
+     * @param conf config file
+     */
+    RSMeanShift(const NICE::Config *conf );
+
+    /** simple destructor */
+    ~RSMeanShift();
+
+    /**
+     * returns the regions of a given image
+     * @param img input image
+     * @param mask output regions, each region has it own number
+     * @return count of region
+     */
+    int segRegions ( const NICE::Image & img, NICE::Matrix & mask ) const;
+
+    /**
+     * returns the regions of a given image
+     * @param img input image
+     * @param mask output regions, each region has it own number
+     * @return count of region
+     */
+    int segRegions ( const NICE::ColorImage & img, NICE::Matrix & mask ) const;
+};
+
+} //namespace
+
+#endif

+ 117 - 0
RSSlic.cpp

@@ -0,0 +1,117 @@
+#include "RSSlic.h"
+
+#include <iostream>
+#include <fstream>
+
+#ifdef NICE_USELIB_OPENMP
+#include <omp.h>
+#endif
+
+#include "SLIC/SLIC.h"
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+
+RSSlic::RSSlic()
+{
+  //spcount = 100000;
+  spcount = 200;
+  compactness = 10.0;
+}
+
+RSSlic::RSSlic(const Config *conf )
+{
+  spcount = conf->gI("RSSlic", "m_spcount", 2000);
+  compactness = conf->gD("RSSlic", "compactness", 10.0);
+}
+
+RSSlic::~RSSlic()
+{
+}
+
+int RSSlic::segRegions ( const NICE::Image & img, NICE::Matrix & mask) const
+{
+  cerr << "not implemented yet" << endl;
+  return -1;
+}
+
+int RSSlic::segRegions ( const NICE::ColorImage & img, NICE::Matrix & mask) const
+{
+  const unsigned int imageWidth  = img.width();
+  const unsigned int imageHeight = img.height();
+
+  // Kopieren der Werte aus dem ColorImage -> image<rgb>
+
+  uint *inputImage = new uint[3*imageWidth*imageHeight];
+
+//#pragma omp parallel for
+  unsigned long int counter = 0;
+  for (int c = 0; c < 3; c++)
+  {
+    for ( unsigned int y = 0; y < imageHeight; y++ )
+    {
+      for ( unsigned int x = 0; x < imageWidth; x++, counter++)
+      {
+        inputImage[counter] = img.getPixelQuick( x, y, c );
+      }
+    }
+  }
+
+  int* labels = new int[imageWidth*imageHeight];
+
+  // Eingabebild segmentieren
+  SLIC slic;
+  int numlabels = 0;
+  slic.DoSuperpixelSegmentation_ForGivenNumberOfSuperpixels(inputImage, imageWidth, imageHeight, labels, numlabels, spcount, compactness);
+
+  slic.DrawContoursAroundSegments(inputImage, labels, imageWidth, imageHeight, 0);
+
+  NICE::ColorImage resultImage( imageWidth, imageHeight );
+  /*
+  counter = 0;
+  for (int c = 0; c < 3; c++)
+  {
+    for ( unsigned int y = 0; y < imageHeight; y++ )
+    {
+      for ( unsigned int x = 0; x < imageWidth; x++, counter++ )
+      {
+        resultImage.setPixelQuick( x, y, c, inputImage[counter] );
+      }
+    }
+  }
+
+  resultImage.write("tmp.ppm");
+*/
+
+  mask.resize(imageWidth, imageHeight);
+  counter = 0;
+  for ( unsigned int y = 0; y < imageHeight; y++ )
+  {
+    for ( unsigned int x = 0; x < imageWidth; x++, counter++ )
+    {
+      mask(x, y) = labels[counter];
+    }
+  }
+/*
+  counter = 0;
+  for ( unsigned int y = 0; y < imageHeight; y++ )
+  {
+    for ( unsigned int x = 0; x < imageWidth; x++, counter++ )
+    {
+      for(int c = 0; c < 3; c++)
+      {
+        resultImage.setPixelQuick( x, y, c, labels[counter]);
+      }
+    }
+  }
+  transformSegmentedImg( resultImage, mask);*/
+
+  // Speicher freigeben
+  delete inputImage;
+  inputImage = NULL;
+  delete labels;
+  labels = NULL;
+
+  return numlabels -1;
+}

+ 57 - 0
RSSlic.h

@@ -0,0 +1,57 @@
+/**
+ * @file RSSlic.h
+ * @brief SLIC Superpixels from "SLIC Superpixels Compared to State-of-the-art Superpixel Methods,"
+ * @author Björn Fröhlich
+ * @date 02/02/2013
+ */
+#ifndef RSSlicINCLUDE
+#define RSSlicINCLUDE
+
+#include "core/basics/Config.h"
+#include "RegionSegmentationMethod.h"
+
+namespace OBJREC {
+
+class RSSlic: public RegionSegmentationMethod
+{
+
+protected:
+    int spcount; //number of regions
+    double compactness; //value between 0 and 40
+
+public:
+    /** simple constructor */
+    RSSlic();
+
+    /** simple constructor */
+    RSSlic(double t);
+
+    /**
+     * standard constructor
+     * @param conf config file
+     */
+    RSSlic(const NICE::Config *conf );
+
+    /** simple destructor */
+    ~RSSlic();
+
+    /**
+     * returns the regions of a given image
+     * @param img input image
+     * @param mask output regions, each region has it own number
+     * @return count of region
+     */
+    virtual int segRegions ( const NICE::Image & img, NICE::Matrix & mask ) const;
+
+    /**
+     * returns the regions of a given image
+     * @param img input color image
+     * @param mask output regions, each region has it own number
+     * @return count of region
+     */
+    virtual int segRegions ( const NICE::ColorImage & img, NICE::Matrix & mask) const;
+};
+
+} //namespace
+
+#endif

+ 225 - 0
RegionGraph.cpp

@@ -0,0 +1,225 @@
+#include "RegionGraph.h"
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+
+Node::Node(int n)
+{
+  atborder = false;
+  number = n;
+  size = 0;
+  amountx = 0;
+  amounty = 0;
+  maxx = -numeric_limits<int>::max();
+  maxy = -numeric_limits<int>::max();
+  minx = numeric_limits<int>::max();
+  miny = numeric_limits<int>::max();
+}
+
+void Node::addNeighbor(Node *nb)
+{
+  neighbors.push_back(nb);
+
+  int l = nb->getLabel();
+
+  if (l != label)
+    atborder = true;
+}
+
+void Node::getRect(int &x0, int &y0, int &x1, int &y1)
+{
+  x0 = minx;
+  x1 = maxx;
+  y0 = miny;
+  y1 = maxy;
+}
+
+void Node::change(int nblabel)
+{
+  if (nblabel != label)
+    atborder = true;
+  else
+  {
+    atborder = false;
+    for (int i = 0; i < (int) neighbors.size(); i++)
+    {
+      if (neighbors[i]->getLabel() != label)
+        atborder = true;
+    }
+  }
+}
+
+bool Node::isAtBorder()
+{
+  return atborder;
+}
+
+void Node::setLabel(int l)
+{
+  label = l;
+}
+
+int Node::getLabel() const
+{
+  return label;
+}
+
+void Node::getNeighbors(vector<Node*> &nb) const
+{
+  nb = neighbors;
+}
+
+int Node::getRegion() const
+{
+  return number;
+}
+
+void Node::incSize(int s)
+{
+  size += s;
+}
+
+void Node::addPos(int x, int y)
+{
+  amountx += x;
+  amounty += y;
+  minx = std::min(minx, x);
+  miny = std::min(miny, y);
+  maxx = std::max(maxx, x);
+  maxy = std::max(maxy, y);
+}
+
+void Node::getCentroid(int &x, int &y) const
+{
+  x = amountx / size;
+  y = amounty / size;
+}
+
+int Node::getSize() const
+{
+  return size;
+}
+
+int Node::getSpan() const
+{
+  return std::max(maxx - minx, maxy - miny);
+}
+
+int Node::store(ofstream & fout)
+{
+  fout << number << " "  << size << " " << amountx / size << " " << amounty / size << " " << minx << " " << miny << " " << maxx << " " << maxy << endl;
+  for (uint i = 0; i < neighbors.size(); i++)
+  {
+    fout << neighbors[i]->getNumber() << " ";
+  }
+  fout << endl;
+  for (uint i = 0; i < probs.size(); i++)
+  {
+    fout << probs[i] << " ";
+  }
+  fout << endl;
+}
+
+void Node::setProbs(vector<double> _probs)
+{
+  probs = _probs;
+}
+
+RegionGraph::~RegionGraph()
+{
+  for (int i = 0; i < (int)nodes.size();i++)
+  {
+    delete nodes[i];
+  }
+}
+
+void RegionGraph::computeGraph(const Examples &regions, const NICE::Matrix &mask)
+{
+  int rs = (int)regions.size();
+  computeGraph(mask, rs);
+
+  for (int i = 0; i < rs; i++)
+  {
+    nodes[i]->setLabel(regions[i].first);
+  }
+}
+
+void RegionGraph::get(vector<Node*> &n) const
+{
+  n = nodes;
+}
+
+void RegionGraph::computeGraph(const NICE::Matrix &mask, const int &rgcount)
+{
+  vector<set<int> > nbs;
+  for (int i = 0; i < rgcount; i++)
+  {
+    Node * a = new Node(i);
+    nodes.push_back(a);
+    nodes[i]->setLabel(0);
+    set<int> nb;
+    nbs.push_back(nb);
+  }
+
+  for (int y = 0; y < (int)mask.cols(); y++)
+  {
+    for (int x = 0; x < (int)mask.rows(); x++)
+    {
+      int val = mask(x, y);
+
+      for (int i = -1; i < 2; i++)
+      {
+        if (x + i < 0 || x + i >= (int)mask.rows())
+          continue;
+        for (int j = -1; j < 2; j++)
+        {
+          if (y + j < 0 || y + j >= (int)mask.cols())
+            continue;
+
+          int val2 = mask(x + i, y + j);
+
+          if (val2 != val)
+          {
+            nbs[val].insert(val2);
+          }
+        }
+      }
+      nodes[val]->incSize();
+      nodes[val]->addPos(x, y);
+    }
+  }
+
+  for (int i = 0; i < rgcount; i++)
+  {
+    for ( set<int>::const_iterator iter = nbs[i].begin();iter != nbs[i].end();++iter)
+    {
+      nodes[i]->addNeighbor(nodes[*iter]);
+    }
+  }
+}
+
+int RegionGraph::size() const
+{
+  return (int)nodes.size();
+}
+
+Node* RegionGraph::operator[](int i) const
+{
+  return nodes[i];
+}
+
+void RegionGraph::write(string file)
+{
+  ofstream fout(file.c_str());
+
+  fout << nodes.size() << endl;
+
+  for (int i = 0; i < nodes.size(); i++)
+  {
+    nodes[i]->store(fout);
+  }
+  fout.close();
+
+  return;
+}

+ 205 - 0
RegionGraph.h

@@ -0,0 +1,205 @@
+/**
+ * @file Graph.h
+ * @brief a simple graph interface for superregion growing
+ * @author Björn Fröhlich
+ * @date 08/19/2009
+
+ */
+#ifndef GRAPHINCLUDE
+#define GRAPHINCLUDE
+
+#include "vislearning/cbaselib/Example.h"
+#include <set>
+
+namespace OBJREC {
+
+class Node
+{
+  protected:
+    //! list of the neighbor nodes
+    std::vector<Node*> neighbors;
+
+    //! is it a borderregion?
+    bool atborder;
+
+    //! number of the region for lookup in Examples
+    int number;
+
+    //! actual class label of the region
+    int label;
+
+    //! size of the region in pixel
+    int size;
+
+    //! used to compute the centroid of the region
+    int amountx, amounty;
+
+    //! saving the bounding box
+    int minx, miny, maxx, maxy;
+
+    //! probabilities for each class
+    std::vector<double> probs;
+  public:
+
+    /**
+      * simple constructor
+     */
+    Node(int n);
+
+    /**
+     * adds a neighbor to the current node
+     * @param nb pointer to a neighbor
+     */
+    void addNeighbor(Node *nb);
+
+    /**
+     * set atborder to true if the region is a border region
+     * @param nblabel changed label of the neighbor
+     */
+    void change(int nblabel);
+
+    /**
+     * returns the label of the node
+     * @return
+     */
+    int getLabel() const;
+
+
+    /**
+     * return size of region
+     * @return
+     */
+    int getSize() const;
+
+    /**
+     * set a new label
+     * @param l
+     */
+    void setLabel(int l);
+
+    /**
+     * returns true if region is a borderregion
+     * @return
+     */
+    bool isAtBorder();
+
+    /**
+     * returns the neighbors of the node
+     * @param nb
+     */
+    void getNeighbors(std::vector<Node*> &nb) const;
+
+    /**
+     * returns the number of the region for lookup in Examples
+     * @return
+     */
+    int getRegion() const;
+
+    /**
+     * returns the number of the region for lookup in Examples
+     * @return
+     */
+    int getNumber() const {
+      return number;
+    };
+
+    /**
+     * increments the size of the actual region
+     * @param s
+     */
+    void incSize(int s = 1);
+
+    /**
+     * add the position of a pixel of the region
+     * used to compute the centroid of the region
+     * @param x
+     * @param y
+     */
+    void addPos(int x, int y);
+
+    /**
+     * returns the postion of the centroid of the region
+     * @param x
+     * @param y
+     */
+    void getCentroid(int &x, int &y) const;
+
+    /**
+     * set probabilities for each class
+     * @param _probs vector of probabilities
+     */
+    void setProbs(std::vector<double> _probs);
+
+
+    /**
+     * get the max of width and height
+     * @return max of width and height of the region
+     */
+    int getSpan() const;
+
+    /**
+     * return the bounding box
+     * @param x0
+     * @param y0
+     * @param x1
+     * @param y1
+     */
+    void getRect(int &x0, int &y0, int &x1, int &y1);
+
+    /**
+     * save node information in filestream
+     * @param fout outputfilestream
+     */
+    int store(std::ofstream & fout);
+};
+
+class RegionGraph
+{
+  protected:
+    //! the nodes of the graph
+    std::vector<Node*> nodes;
+
+  public:
+
+    /**
+     * simple constructor
+     */
+    RegionGraph() {};
+
+    ~RegionGraph();
+
+    void get(std::vector<Node*> &n) const;
+
+    /**
+     * creates the graph out of a region matrix
+     * @param mask region label for each pixel
+     * @param rgcount number of different regions
+     */
+    void computeGraph(const NICE::Matrix &mask, const int &rgcount);
+
+    /**
+     * creates the graph ot of a region matrix mask
+     * @param regions
+     * @param mask
+     */
+    void computeGraph(const Examples &regions, const NICE::Matrix &mask);
+
+
+    /**
+     * returns the number of nodes
+     * @return number of nodes
+     */
+    int size() const;
+
+    /**
+     * get pointer to the i-th node
+     * @param i number of node
+     * @return node
+     */
+    Node* operator[](int i) const;
+
+    void write(std::string file);
+};
+
+} //namespace
+#endif

+ 287 - 0
RegionSegmentationMethod.cpp

@@ -0,0 +1,287 @@
+#include "RegionSegmentationMethod.h"
+
+#include <core/image/CrossT.h>
+#include <core/image/LineT.h>
+#include <core/image/CircleT.h>
+#include <core/imagedisplay/ImageDisplay.h>
+
+using namespace OBJREC;
+using namespace NICE;
+using namespace std;
+
+RegionSegmentationMethod::RegionSegmentationMethod()
+{
+
+}
+
+RegionSegmentationMethod::RegionSegmentationMethod ( const Config *c )
+{
+  conf = c;
+}
+
+RegionSegmentationMethod::~RegionSegmentationMethod()
+{
+
+}
+
+//überprüfe, ob Elterpixel neugelabelt wurde, wenn ja dann label auch Kind neu
+inline int rootOf ( int *l, int j )
+{
+  while ( l[j] != j ) {
+    // short path compression
+    l[j] = l[l[j]];
+    j    = l[j];
+  }
+  return j;
+}
+
+int RegionSegmentationMethod::transformSegmentedImg ( const NICE::ColorImage & img, NICE::Matrix & mask ) const
+{
+  int xsize = img.width();
+  int ysize = img.height();
+  int n = xsize * ysize;
+  int *l = new int[n];
+  int v[3], vo[3];
+
+  int j = 0;
+  for ( int y = 0 ; y < ysize ; y++ ) // horizontal
+  {
+    l[j] = j;
+    vo[0] = img.getPixel ( 0, y, 2 );
+    vo[1] = img.getPixel ( 0, y, 0 );
+    vo[2] = img.getPixel ( 0, y, 1 );
+    j++;
+    for ( int x = 1 ; x < xsize ; x++, j++ )
+    {
+      v[0] = img.getPixel ( x, y, 2 );
+      v[1] = img.getPixel ( x, y, 0 );
+      v[2] = img.getPixel ( x, y, 1 );
+      if ( v[0] == vo[0] && v[1] == vo[1] && v[2] == vo[2] )
+      {
+        l[j] = l[j-1];
+      }
+      else
+      {
+        l[j] = j;
+      }
+      vo[0] = v[0];
+      vo[1] = v[1];
+      vo[2] = v[2];
+    }
+  }
+
+  j = 0;
+  for ( int x = 0 ; x < xsize ; x++ ) //vertikal
+  {
+    vo[0] = img.getPixel ( x, 0, 2 );
+    vo[1] = img.getPixel ( x, 0, 0 );
+    vo[2] = img.getPixel ( x, 0, 1 );
+    for ( int y = 1 ; y < ysize ; y++ )
+    {
+      j = y * ( xsize ) + x;
+      v[0] = img.getPixel ( x, y, 2 );
+      v[1] = img.getPixel ( x, y, 0 );
+      v[2] = img.getPixel ( x, y, 1 );
+      if ( v[0] == vo[0] && v[1] == vo[1] && v[2] == vo[2] ) {
+        int rj = rootOf ( l, j );
+        int rn = rootOf ( l, j - xsize );
+        if ( rj != rn ) {
+          l[rj] = rn;
+        }
+      }
+      vo[0] = v[0];
+      vo[1] = v[1];
+      vo[2] = v[2];
+    }
+  }
+
+  j = 0;
+  for ( int x = 1 ; x < xsize ; x++ ) //links oben
+  {
+    vo[0] = img.getPixel ( x - 1, 0, 2 );
+    vo[1] = img.getPixel ( x - 1, 0, 0 );
+    vo[2] = img.getPixel ( x - 1, 0, 1 );
+    for ( int y = 1 ; y < ysize ; y++ )
+    {
+      j = y * ( xsize ) + x;
+      v[0] = img.getPixel ( x, y, 2 );
+      v[1] = img.getPixel ( x, y, 0 );
+      v[2] = img.getPixel ( x, y, 1 );
+      if ( v[0] == vo[0] && v[1] == vo[1] && v[2] == vo[2] ) {
+        int rj = rootOf ( l, j );
+        int rn = rootOf ( l, j - xsize - 1 );
+        if ( rj != rn ) {
+          l[rj] = rn;
+        }
+      }
+      vo[0] = img.getPixel ( x - 1, y, 2 );
+      vo[1] = img.getPixel ( x - 1, y, 0 );
+      vo[2] = img.getPixel ( x - 1, y, 1 );
+    }
+  }
+
+  j = 0;
+  for ( int x = xsize - 2 ; x >= 0 ; x-- ) //rechts oben
+  {
+    vo[0] = img.getPixel ( x + 1, 0, 2 );
+    vo[1] = img.getPixel ( x + 1, 0, 0 );
+    vo[2] = img.getPixel ( x + 1, 0, 1 );
+    for ( int y = 1 ; y < ysize ; y++ )
+    {
+      j = y * ( xsize ) + x;
+      v[0] = img.getPixel ( x, y, 2 );
+      v[1] = img.getPixel ( x, y, 0 );
+      v[2] = img.getPixel ( x, y, 1 );
+      if ( v[0] == vo[0] && v[1] == vo[1] && v[2] == vo[2] ) {
+        int rj = rootOf ( l, j );
+        int rn = rootOf ( l, j - xsize + 1 );
+        if ( rj != rn ) {
+          l[rj] = rn;
+        }
+      }
+      vo[0] = img.getPixel ( x + 1, y, 2 );
+      vo[1] = img.getPixel ( x + 1, y, 0 );
+      vo[2] = img.getPixel ( x + 1, y, 1 );
+    }
+  }
+
+  int size = 0;
+
+  // relabel
+  std::map<int, int> bijection;
+  for ( j = 0 ; j < n ; j++ )
+  {
+    if ( l[j] == j ) {
+      bijection[j] = size;
+      size++;
+    }
+  }
+
+  if ( size <= 0 ) {
+    fprintf ( stderr, "RegionSegmentationMethod:: no components of this color found !!\n" );
+    return -1;
+  }
+
+  mask.resize ( xsize, ysize );
+
+  for ( j = 0 ; j < n ; j++ )
+  {
+    int label = rootOf ( l, j );
+    int x = j % ( xsize );
+    int y = j / ( xsize );
+
+    mask ( x, y ) = bijection[label];
+  }
+  delete [] l;
+
+  return size;
+}
+
+void RegionSegmentationMethod::getGraphRepresentation ( const NICE::ColorImage & cimg, NICE::Matrix & mask, RegionGraph & rg )
+{
+  int regioncount = segRegions ( cimg, mask );
+  rg.computeGraph ( mask, regioncount );
+}
+
+int RegionSegmentationMethod::segRegions ( const NICE::ColorImage & cimg, NICE::Matrix & mask ) const
+{
+  Image img ( cimg.width(), cimg.height() );
+  for ( int y = 0; y < cimg.height(); y++ )
+  {
+    for ( int x = 0; x < cimg.width(); x++ )
+    {
+      int val = 0;
+      for ( int i = 0; i < 3; i++ )
+        val += cimg.getPixel ( x, y, i );
+      val /= 3;
+      img.setPixel ( x, y, val );
+    }
+  }
+  cerr << "no color segmentation method, using grayimage segmentation instead" << endl;
+  return segRegions ( img, mask );
+}
+
+void RegionSegmentationMethod::markContours ( const NICE::ColorImage & cimg, NICE::Matrix & mask, std::vector<int> &color, NICE::ColorImage &marked )
+{
+  // mark contours
+  for ( int y = 1; y < cimg.height() - 1; y++ )
+  {
+    for ( int x = 1; x < cimg.width() - 1; x++ )
+    {
+      bool diff = false;
+      for ( int i = -1; i < 2; i++ )
+      {
+        for ( int j = -1; j < 2; j++ )
+        {
+          if ( mask ( x, y ) != mask ( x + i, y + j ) )
+            diff = true;
+        }
+        if ( diff )
+          break;
+      }
+      if ( diff )
+      {
+        for(int c = 0; c < 3; c++)
+          marked.setPixel ( x, y, c, color[c] );
+      }
+      else
+      {
+        for(int c = 0; c < 3; c++)
+          marked.setPixel ( x, y, c, cimg.getPixel(x,y,c) );
+      }
+    }
+  }
+}
+
+void RegionSegmentationMethod::visualizeGraphRepresentation ( const NICE::ColorImage & cimg, NICE::Matrix & mask )
+{
+  RegionGraph rg;
+  getGraphRepresentation ( cimg, mask, rg );
+
+  vector<Node*> g;
+  rg.get ( g );
+
+  Image overlay ( cimg.width(), cimg.height() );
+  overlay.set ( 0 );
+
+  // mark contours
+  for ( int y = 1; y < cimg.height() - 1; y++ )
+  {
+    for ( int x = 1; x < cimg.width() - 1; x++ )
+    {
+      bool diff = false;
+      for ( int i = -1; i < 2; i++ )
+      {
+        for ( int j = -1; j < 2; j++ )
+        {
+          if ( mask ( x, y ) != mask ( x + i, y + j ) )
+            diff = true;
+        }
+        if ( diff )
+          break;
+      }
+      if ( diff )
+        overlay.setPixel ( x, y, 3 );
+    }
+  }
+
+  // mark graph
+  for ( int i = 0 ; i < ( int ) g.size() ; i++ )
+  {
+    int x, y;
+    g[i]->getCentroid ( x, y );
+    Cross cross ( Coord ( x, y ) , 7 );
+    overlay.draw ( cross, 1 );
+    vector<Node*> nb;
+    g[i]->getNeighbors ( nb );
+    for ( int j = 0; j < ( int ) nb.size(); j++ )
+    {
+      int xn, yn;
+      nb[j]->getCentroid ( xn, yn );
+      Line line ( Coord ( x, y ), Coord ( xn, yn ) );
+      overlay.draw ( line, 2 );
+    }
+  }
+
+  showImageOverlay ( cimg, overlay, "Regions" );
+}

+ 91 - 0
RegionSegmentationMethod.h

@@ -0,0 +1,91 @@
+/**
+ * @file RegionSegmentationMethod.h
+ * @brief abstract interface for region segmantation
+ * @author Björn Fröhlich
+ * @date 05/05/2009
+ */
+#ifndef REGIONSEGMENTATIONMETHOD
+#define REGIONSEGMENTATIONMETHOD
+
+#include "core/basics/Config.h"
+
+#undef DEBUGRS
+
+#include "RegionGraph.h"
+
+
+namespace OBJREC {
+
+class RegionSegmentationMethod
+{
+
+  protected:
+    const NICE::Config *conf;
+
+  public:
+
+    /** simple constructor */
+    RegionSegmentationMethod();
+
+    /** simple constructor */
+    RegionSegmentationMethod(const NICE::Config *c );
+
+    /** simple destructor */
+    ~RegionSegmentationMethod();
+
+    /**
+     * returns the regions of a given image
+     * @param img input image
+     * @param mask output regions, each region has it own number
+     * @return count of region
+     */
+    virtual int segRegions ( const NICE::Image & img, NICE::Matrix & mask ) const = 0;
+
+    /**
+     * returns the regions of a given image
+     * @param img input color image
+     * @param mask output regions, each region has it own number
+     * @return count of region
+     */
+    virtual int segRegions ( const NICE::ColorImage & cimg, NICE::Matrix & mask) const;
+
+    /**
+     * transform a segmented color image in a grayimage, where each region has its own label
+     * @param img input image
+     * @param mask output mask
+     * @return count of regions
+     */
+    int transformSegmentedImg( const NICE::ColorImage & img, NICE::Matrix & mask) const;
+
+    /**
+     * get the Graph representation of an segmentationa
+     * @param cimg input color image
+     * @param mask result mask of the regions
+     * @param rg graph representation
+     */
+    void getGraphRepresentation(const NICE::ColorImage & cimg, NICE::Matrix & mask, RegionGraph & rg);
+    
+    
+    /**
+     * @brief mark contours with given segmentation
+     *
+     * @param cimg input image
+     * @param mask result segmentation
+     * @param color RGB values of marking color
+     * @param marked resultimage
+     * @return void
+     **/
+    void markContours ( const NICE::ColorImage & cimg, NICE::Matrix & mask, std::vector<int> &color, NICE::ColorImage &marked );
+
+    /**
+     * visualize the graph representation
+     * @param cimg input color image
+     * @param mask result mask of the regions
+     */
+    void visualizeGraphRepresentation(const NICE::ColorImage & cimg, NICE::Matrix & mask);
+};
+
+
+} // namespace
+
+#endif

+ 103 - 0
SLIC/Makefile.inc

@@ -0,0 +1,103 @@
+# LIBRARY-DIRECTORY-MAKEFILE
+# conventions:
+# - all subdirectories containing a "Makefile.inc" are considered sublibraries
+#   exception: "progs/" and "tests/" subdirectories!
+# - all ".C", ".cpp" and ".c" files in the current directory are linked to a
+#   library
+# - the library depends on all sublibraries 
+# - the library name is created with $(LIBNAME), i.e. it will be somehow
+#   related to the directory name and with the extension .a
+#   (e.g. lib1/sublib -> lib1_sublib.a)
+# - the library will be added to the default build list ALL_LIBRARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+ifeq "$(SUBDIR)" "./"
+SUBDIR:=
+endif
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# you can specify libraries needed by the individual objects or by the whole
+# directory. the object specific additional libraries are only considered
+# when compiling the specific object files
+# TODO: update documentation...
+
+-include $(SUBDIR)libdepend.inc
+
+$(foreach d,$(filter-out %progs %tests,$(SUBDIRS_OF_$(SUBDIR))),$(eval $(call PKG_DEPEND_INT,$(d))))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+	  $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+LIBRARY_BASENAME:=$(call LIBNAME,$(SUBDIR))
+ifneq "$(SUBDIR)" ""
+ALL_LIBRARIES+=$(LIBDIR)$(LIBRARY_BASENAME).$(LINK_FILE_EXTENSION)
+endif
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. the current library depends on all sublibraries.
+# all other dependencies have to be added manually by specifying, that the
+# current .pc file depends on some other .pc file. binaries depending on
+# libraries should exclusivelly use the .pc files as well.
+
+ifeq "$(SKIP_BUILD_$(OBJDIR))" "1"
+$(LIBDIR)$(LIBRARY_BASENAME).a:
+else
+$(LIBDIR)$(LIBRARY_BASENAME).a:$(OBJS) \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).a,.$(LINK_FILE_EXTENSION))
+endif
+
+$(PKGDIR)$(LIBRARY_BASENAME).pc: \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).pc,.pc)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 1331 - 0
SLIC/SLIC.cpp

@@ -0,0 +1,1331 @@
+// SLIC.cpp: implementation of the SLIC class.
+//
+// Copyright (C) Radhakrishna Achanta 2012
+// All rights reserved
+// Email: firstname.lastname@epfl.ch
+//////////////////////////////////////////////////////////////////////
+//#include "stdafx.h"
+#include <cfloat>
+#include <cmath>
+#include <iostream>
+#include <fstream>
+#include "SLIC.h"
+
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+SLIC::SLIC()
+{
+    m_lvec = NULL;
+    m_avec = NULL;
+    m_bvec = NULL;
+
+    m_lvecvec = NULL;
+    m_avecvec = NULL;
+    m_bvecvec = NULL;
+}
+
+SLIC::~SLIC()
+{
+    if (m_lvec) delete [] m_lvec;
+    if (m_avec) delete [] m_avec;
+    if (m_bvec) delete [] m_bvec;
+
+
+    if (m_lvecvec)
+    {
+        for ( int d = 0; d < m_depth; d++ ) delete [] m_lvecvec[d];
+        delete [] m_lvecvec;
+    }
+    if (m_avecvec)
+    {
+        for ( int d = 0; d < m_depth; d++ ) delete [] m_avecvec[d];
+        delete [] m_avecvec;
+    }
+    if (m_bvecvec)
+    {
+        for ( int d = 0; d < m_depth; d++ ) delete [] m_bvecvec[d];
+        delete [] m_bvecvec;
+    }
+}
+
+//==============================================================================
+/// RGB2XYZ
+///
+/// sRGB (D65 illuninant assumption) to XYZ conversion
+//==============================================================================
+void SLIC::RGB2XYZ(
+    const int&    sR,
+    const int&    sG,
+    const int&    sB,
+    double&     X,
+    double&     Y,
+    double&     Z)
+{
+    double R = sR/255.0;
+    double G = sG/255.0;
+    double B = sB/255.0;
+
+    double r, g, b;
+
+    if (R <= 0.04045) r = R/12.92;
+    else        r = pow((R+0.055)/1.055,2.4);
+    if (G <= 0.04045) g = G/12.92;
+    else        g = pow((G+0.055)/1.055,2.4);
+    if (B <= 0.04045) b = B/12.92;
+    else        b = pow((B+0.055)/1.055,2.4);
+
+    X = r*0.4124564 + g*0.3575761 + b*0.1804375;
+    Y = r*0.2126729 + g*0.7151522 + b*0.0721750;
+    Z = r*0.0193339 + g*0.1191920 + b*0.9503041;
+}
+
+//===========================================================================
+/// RGB2LAB
+//===========================================================================
+void SLIC::RGB2LAB(const int& sR, const int& sG, const int& sB, double& lval, double& aval, double& bval)
+{
+    //------------------------
+    // sRGB to XYZ conversion
+    //------------------------
+    double X, Y, Z;
+    RGB2XYZ(sR, sG, sB, X, Y, Z);
+
+    //------------------------
+    // XYZ to LAB conversion
+    //------------------------
+    double epsilon = 0.008856;  //actual CIE standard
+    double kappa   = 903.3;   //actual CIE standard
+
+    double Xr = 0.950456; //reference white
+    double Yr = 1.0;    //reference white
+    double Zr = 1.088754; //reference white
+
+    double xr = X/Xr;
+    double yr = Y/Yr;
+    double zr = Z/Zr;
+
+    double fx, fy, fz;
+    if (xr > epsilon) fx = pow(xr, 1.0/3.0);
+    else        fx = (kappa*xr + 16.0)/116.0;
+    if (yr > epsilon) fy = pow(yr, 1.0/3.0);
+    else        fy = (kappa*yr + 16.0)/116.0;
+    if (zr > epsilon) fz = pow(zr, 1.0/3.0);
+    else        fz = (kappa*zr + 16.0)/116.0;
+
+    lval = 116.0*fy-16.0;
+    aval = 500.0*(fx-fy);
+    bval = 200.0*(fy-fz);
+}
+
+//===========================================================================
+/// DoRGBtoLABConversion
+///
+/// For whole image: overlaoded floating point version
+//===========================================================================
+void SLIC::DoRGBtoLABConversion(
+    const unsigned int*&    ubuff,
+    double*&          lvec,
+    double*&          avec,
+    double*&          bvec)
+{
+    int sz = m_width*m_height;
+    lvec = new double[sz];
+    avec = new double[sz];
+    bvec = new double[sz];
+
+    for ( int j = 0; j < sz; j++ )
+    {
+        int r = (ubuff[j] >> 16) & 0xFF;
+        int g = (ubuff[j] >>  8) & 0xFF;
+        int b = (ubuff[j]      ) & 0xFF;
+
+        RGB2LAB( r, g, b, lvec[j], avec[j], bvec[j] );
+    }
+}
+
+//===========================================================================
+/// DoRGBtoLABConversion
+///
+/// For whole volume
+//===========================================================================
+void SLIC::DoRGBtoLABConversion(
+    unsigned int**&   ubuff,
+    double**&         lvec,
+    double**&         avec,
+    double**&         bvec)
+{
+    int sz = m_width*m_height;
+    for ( int d = 0; d < m_depth; d++ )
+    {
+        for ( int j = 0; j < sz; j++ )
+        {
+            int r = (ubuff[d][j] >> 16) & 0xFF;
+            int g = (ubuff[d][j] >>  8) & 0xFF;
+            int b = (ubuff[d][j]      ) & 0xFF;
+
+            RGB2LAB( r, g, b, lvec[d][j], avec[d][j], bvec[d][j] );
+        }
+    }
+}
+
+//=================================================================================
+/// DrawContoursAroundSegments
+///
+/// Internal contour drawing option exists. One only needs to comment the if
+/// statement inside the loop that looks at neighbourhood.
+//=================================================================================
+void SLIC::DrawContoursAroundSegments(
+    unsigned int*&      ubuff,
+    int*&         labels,
+    const int&        width,
+    const int&        height,
+    const unsigned int&       color )
+{
+    const int dx8[8] = {-1, -1,  0,  1, 1, 1, 0, -1};
+    const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1,  1};
+
+    /*  int sz = width*height;
+
+      vector<bool> istaken(sz, false);
+
+      int mainindex(0);
+      for( int j = 0; j < height; j++ )
+      {
+        for( int k = 0; k < width; k++ )
+        {
+          int np(0);
+          for( int i = 0; i < 8; i++ )
+          {
+            int x = k + dx8[i];
+            int y = j + dy8[i];
+
+            if( (x >= 0 && x < width) && (y >= 0 && y < height) )
+            {
+              int index = y*width + x;
+
+              if( false == istaken[index] )//comment this to obtain internal contours
+              {
+                if( labels[mainindex] != labels[index] ) np++;
+              }
+            }
+          }
+          if( np > 1 )//change to 2 or 3 for thinner lines
+          {
+            ubuff[mainindex] = color;
+            istaken[mainindex] = true;
+          }
+          mainindex++;
+        }
+      }*/
+
+
+    int sz = width*height;
+    vector<bool> istaken(sz, false);
+    vector<int> contourx(sz);
+    vector<int> contoury(sz);
+    int mainindex(0);
+    int cind(0);
+    for ( int j = 0; j < height; j++ )
+    {
+        for ( int k = 0; k < width; k++ )
+        {
+            int np(0);
+            for ( int i = 0; i < 8; i++ )
+            {
+                int x = k + dx8[i];
+                int y = j + dy8[i];
+
+                if ( (x >= 0 && x < width) && (y >= 0 && y < height) )
+                {
+                    int index = y*width + x;
+
+                    //if( false == istaken[index] )//comment this to obtain internal contours
+                    {
+                        if ( labels[mainindex] != labels[index] ) np++;
+                    }
+                }
+            }
+            if ( np > 1 )
+            {
+                contourx[cind] = k;
+                contoury[cind] = j;
+                istaken[mainindex] = true;
+                //img[mainindex] = color;
+                cind++;
+            }
+            mainindex++;
+        }
+    }
+
+    int numboundpix = cind;//int(contourx.size());
+    for ( int j = 0; j < numboundpix; j++ )
+    {
+        int ii = contoury[j]*width + contourx[j];
+        ubuff[ii] = 0xffffff;
+
+        for ( int n = 0; n < 8; n++ )
+        {
+            int x = contourx[j] + dx8[n];
+            int y = contoury[j] + dy8[n];
+            if ( (x >= 0 && x < width) && (y >= 0 && y < height) )
+            {
+                int ind = y*width + x;
+                if (!istaken[ind]) ubuff[ind] = 0;
+            }
+        }
+    }
+}
+
+
+//==============================================================================
+/// DetectLabEdges
+//==============================================================================
+void SLIC::DetectLabEdges(
+    const double*       lvec,
+    const double*       avec,
+    const double*       bvec,
+    const int&          width,
+    const int&          height,
+    vector<double>&       edges)
+{
+    int sz = width*height;
+
+    edges.resize(sz,0);
+    for ( int j = 1; j < height-1; j++ )
+    {
+        for ( int k = 1; k < width-1; k++ )
+        {
+            int i = j*width+k;
+
+            double dx = (lvec[i-1]-lvec[i+1])*(lvec[i-1]-lvec[i+1]) +
+                        (avec[i-1]-avec[i+1])*(avec[i-1]-avec[i+1]) +
+                        (bvec[i-1]-bvec[i+1])*(bvec[i-1]-bvec[i+1]);
+
+            double dy = (lvec[i-width]-lvec[i+width])*(lvec[i-width]-lvec[i+width]) +
+                        (avec[i-width]-avec[i+width])*(avec[i-width]-avec[i+width]) +
+                        (bvec[i-width]-bvec[i+width])*(bvec[i-width]-bvec[i+width]);
+
+            //edges[i] = fabs(dx) + fabs(dy);
+            edges[i] = dx*dx + dy*dy;
+        }
+    }
+}
+
+//===========================================================================
+/// PerturbSeeds
+//===========================================================================
+void SLIC::PerturbSeeds(
+    vector<double>&       kseedsl,
+    vector<double>&       kseedsa,
+    vector<double>&       kseedsb,
+    vector<double>&       kseedsx,
+    vector<double>&       kseedsy,
+    const vector<double>&                   edges)
+{
+    const int dx8[8] = {-1, -1,  0,  1, 1, 1, 0, -1};
+    const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1,  1};
+
+    int numseeds = kseedsl.size();
+
+    for ( int n = 0; n < numseeds; n++ )
+    {
+        int ox = kseedsx[n];//original x
+        int oy = kseedsy[n];//original y
+        int oind = oy*m_width + ox;
+
+        int storeind = oind;
+        for ( int i = 0; i < 8; i++ )
+        {
+            int nx = ox+dx8[i];//new x
+            int ny = oy+dy8[i];//new y
+
+            if ( nx >= 0 && nx < m_width && ny >= 0 && ny < m_height)
+            {
+                int nind = ny*m_width + nx;
+                if ( edges[nind] < edges[storeind])
+                {
+                    storeind = nind;
+                }
+            }
+        }
+        if (storeind != oind)
+        {
+            kseedsx[n] = storeind%m_width;
+            kseedsy[n] = storeind/m_width;
+            kseedsl[n] = m_lvec[storeind];
+            kseedsa[n] = m_avec[storeind];
+            kseedsb[n] = m_bvec[storeind];
+        }
+    }
+}
+
+
+//===========================================================================
+/// GetLABXYSeeds_ForGivenStepSize
+///
+/// The k seed values are taken as uniform spatial pixel samples.
+//===========================================================================
+void SLIC::GetLABXYSeeds_ForGivenStepSize(
+    vector<double>&       kseedsl,
+    vector<double>&       kseedsa,
+    vector<double>&       kseedsb,
+    vector<double>&       kseedsx,
+    vector<double>&       kseedsy,
+    const int&          STEP,
+    const bool&         perturbseeds,
+    const vector<double>&       edgemag)
+{
+    const bool hexgrid = false;
+    int numseeds(0);
+    int n(0);
+
+    //int xstrips = m_width/STEP;
+    //int ystrips = m_height/STEP;
+    int xstrips = (0.5+double(m_width)/double(STEP));
+    int ystrips = (0.5+double(m_height)/double(STEP));
+
+    int xerr = m_width  - STEP*xstrips;
+    if (xerr < 0) {
+        xstrips--;
+        xerr = m_width - STEP*xstrips;
+    }
+    int yerr = m_height - STEP*ystrips;
+    if (yerr < 0) {
+        ystrips--;
+        yerr = m_height- STEP*ystrips;
+    }
+
+    double xerrperstrip = double(xerr)/double(xstrips);
+    double yerrperstrip = double(yerr)/double(ystrips);
+
+    int xoff = STEP/2;
+    int yoff = STEP/2;
+    //-------------------------
+    numseeds = xstrips*ystrips;
+    //-------------------------
+    kseedsl.resize(numseeds);
+    kseedsa.resize(numseeds);
+    kseedsb.resize(numseeds);
+    kseedsx.resize(numseeds);
+    kseedsy.resize(numseeds);
+
+    for ( int y = 0; y < ystrips; y++ )
+    {
+        int ye = y*yerrperstrip;
+        for ( int x = 0; x < xstrips; x++ )
+        {
+            int xe = x*xerrperstrip;
+            int seedx = (x*STEP+xoff+xe);
+            if (hexgrid) {
+                seedx = x*STEP+(xoff<<(y&0x1))+xe;    //for hex grid sampling
+                seedx = min(m_width-1,seedx);
+            }
+            int seedy = (y*STEP+yoff+ye);
+            int i = seedy*m_width + seedx;
+
+            kseedsl[n] = m_lvec[i];
+            kseedsa[n] = m_avec[i];
+            kseedsb[n] = m_bvec[i];
+            kseedsx[n] = seedx;
+            kseedsy[n] = seedy;
+            n++;
+        }
+    }
+
+
+    if (perturbseeds)
+    {
+        PerturbSeeds(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, edgemag);
+    }
+}
+
+//===========================================================================
+/// GetKValues_LABXYZ
+///
+/// The k seed values are taken as uniform spatial pixel samples.
+//===========================================================================
+void SLIC::GetKValues_LABXYZ(
+    vector<double>&       kseedsl,
+    vector<double>&       kseedsa,
+    vector<double>&       kseedsb,
+    vector<double>&       kseedsx,
+    vector<double>&       kseedsy,
+    vector<double>&       kseedsz,
+    const int&        STEP)
+{
+    const bool hexgrid = false;
+    int numseeds(0);
+    int n(0);
+
+    int xstrips = (0.5+double(m_width)/double(STEP));
+    int ystrips = (0.5+double(m_height)/double(STEP));
+    int zstrips = (0.5+double(m_depth)/double(STEP));
+
+    int xerr = m_width  - STEP*xstrips;
+    if (xerr < 0) {
+        xstrips--;
+        xerr = m_width - STEP*xstrips;
+    }
+    int yerr = m_height - STEP*ystrips;
+    if (yerr < 0) {
+        ystrips--;
+        yerr = m_height- STEP*ystrips;
+    }
+    int zerr = m_depth  - STEP*zstrips;
+    if (zerr < 0) {
+        zstrips--;
+        zerr = m_depth - STEP*zstrips;
+    }
+
+    double xerrperstrip = double(xerr)/double(xstrips);
+    double yerrperstrip = double(yerr)/double(ystrips);
+    double zerrperstrip = double(zerr)/double(zstrips);
+
+    int xoff = STEP/2;
+    int yoff = STEP/2;
+    int zoff = STEP/2;
+    //-------------------------
+    numseeds = xstrips*ystrips*zstrips;
+    //-------------------------
+    kseedsl.resize(numseeds);
+    kseedsa.resize(numseeds);
+    kseedsb.resize(numseeds);
+    kseedsx.resize(numseeds);
+    kseedsy.resize(numseeds);
+    kseedsz.resize(numseeds);
+
+    for ( int z = 0; z < zstrips; z++ )
+    {
+        int ze = z*zerrperstrip;
+        int d = (z*STEP+zoff+ze);
+        for ( int y = 0; y < ystrips; y++ )
+        {
+            int ye = y*yerrperstrip;
+            for ( int x = 0; x < xstrips; x++ )
+            {
+                int xe = x*xerrperstrip;
+                int i = (y*STEP+yoff+ye)*m_width + (x*STEP+xoff+xe);
+
+                kseedsl[n] = m_lvecvec[d][i];
+                kseedsa[n] = m_avecvec[d][i];
+                kseedsb[n] = m_bvecvec[d][i];
+                kseedsx[n] = (x*STEP+xoff+xe);
+                kseedsy[n] = (y*STEP+yoff+ye);
+                kseedsz[n] = d;
+                n++;
+            }
+        }
+    }
+}
+
+//===========================================================================
+/// PerformSuperpixelSLIC
+///
+/// Performs k mean segmentation. It is fast because it looks locally, not
+/// over the entire image.
+//===========================================================================
+void SLIC::PerformSuperpixelSLIC(
+    vector<double>&       kseedsl,
+    vector<double>&       kseedsa,
+    vector<double>&       kseedsb,
+    vector<double>&       kseedsx,
+    vector<double>&       kseedsy,
+    int*&         klabels,
+    const int&        STEP,
+    const vector<double>&                   edgemag,
+    const double&       M)
+{
+    int sz = m_width*m_height;
+    const int numk = kseedsl.size();
+    //----------------
+    int offset = STEP;
+    //if(STEP < 8) offset = STEP*1.5;//to prevent a crash due to a very small step size
+    //----------------
+
+    vector<double> clustersize(numk, 0);
+    vector<double> inv(numk, 0);//to store 1/clustersize[k] values
+
+    vector<double> sigmal(numk, 0);
+    vector<double> sigmaa(numk, 0);
+    vector<double> sigmab(numk, 0);
+    vector<double> sigmax(numk, 0);
+    vector<double> sigmay(numk, 0);
+    vector<double> distvec(sz, DBL_MAX);
+
+    double invwt = 1.0/((STEP/M)*(STEP/M));
+
+    int x1, y1, x2, y2;
+    double l, a, b;
+    double dist;
+    double distxy;
+    for ( int itr = 0; itr < 10; itr++ )
+    {
+        distvec.assign(sz, DBL_MAX);
+        for ( int n = 0; n < numk; n++ )
+        {
+            y1 = max(0.0,     kseedsy[n]-offset);
+            y2 = min((double)m_height,  kseedsy[n]+offset);
+            x1 = max(0.0,     kseedsx[n]-offset);
+            x2 = min((double)m_width, kseedsx[n]+offset);
+
+
+            for ( int y = y1; y < y2; y++ )
+            {
+                for ( int x = x1; x < x2; x++ )
+                {
+                    int i = y*m_width + x;
+
+                    l = m_lvec[i];
+                    a = m_avec[i];
+                    b = m_bvec[i];
+
+                    dist =      (l - kseedsl[n])*(l - kseedsl[n]) +
+                             (a - kseedsa[n])*(a - kseedsa[n]) +
+                             (b - kseedsb[n])*(b - kseedsb[n]);
+
+                    distxy =    (x - kseedsx[n])*(x - kseedsx[n]) +
+                              (y - kseedsy[n])*(y - kseedsy[n]);
+
+                    //------------------------------------------------------------------------
+                    dist += distxy*invwt;//dist = sqrt(dist) + sqrt(distxy*invwt);//this is more exact
+                    //------------------------------------------------------------------------
+                    if ( dist < distvec[i] )
+                    {
+                        distvec[i] = dist;
+                        klabels[i]  = n;
+                    }
+                }
+            }
+        }
+        //-----------------------------------------------------------------
+        // Recalculate the centroid and store in the seed values
+        //-----------------------------------------------------------------
+        //instead of reassigning memory on each iteration, just reset.
+
+        sigmal.assign(numk, 0);
+        sigmaa.assign(numk, 0);
+        sigmab.assign(numk, 0);
+        sigmax.assign(numk, 0);
+        sigmay.assign(numk, 0);
+        clustersize.assign(numk, 0);
+        //------------------------------------
+        //edgesum.assign(numk, 0);
+        //------------------------------------
+
+        {
+            int ind(0);
+            for ( int r = 0; r < m_height; r++ )
+            {
+                for ( int c = 0; c < m_width; c++ )
+                {
+                    sigmal[klabels[ind]] += m_lvec[ind];
+                    sigmaa[klabels[ind]] += m_avec[ind];
+                    sigmab[klabels[ind]] += m_bvec[ind];
+                    sigmax[klabels[ind]] += c;
+                    sigmay[klabels[ind]] += r;
+                    //------------------------------------
+                    //edgesum[klabels[ind]] += edgemag[ind];
+                    //------------------------------------
+                    clustersize[klabels[ind]] += 1.0;
+                    ind++;
+                }
+            }
+        }
+
+        {
+            for ( int k = 0; k < numk; k++ )
+            {
+                if ( clustersize[k] <= 0 ) clustersize[k] = 1;
+                inv[k] = 1.0/clustersize[k];//computing inverse now to multiply, than divide later
+            }
+        }
+
+        {
+            for ( int k = 0; k < numk; k++ )
+            {
+                kseedsl[k] = sigmal[k]*inv[k];
+                kseedsa[k] = sigmaa[k]*inv[k];
+                kseedsb[k] = sigmab[k]*inv[k];
+                kseedsx[k] = sigmax[k]*inv[k];
+                kseedsy[k] = sigmay[k]*inv[k];
+                //------------------------------------
+                //edgesum[k] *= inv[k];
+                //------------------------------------
+            }
+        }
+    }
+}
+
+//===========================================================================
+/// PerformSupervoxelSLIC
+///
+/// Performs k mean segmentation. It is fast because it searches locally, not
+/// over the entire image.
+//===========================================================================
+void SLIC::PerformSupervoxelSLIC(
+    vector<double>&       kseedsl,
+    vector<double>&       kseedsa,
+    vector<double>&       kseedsb,
+    vector<double>&       kseedsx,
+    vector<double>&       kseedsy,
+    vector<double>&       kseedsz,
+    int**&          klabels,
+    const int&        STEP,
+    const double&       compactness)
+{
+    int sz = m_width*m_height;
+    const int numk = kseedsl.size();
+    //int numitr(0);
+
+    //----------------
+    int offset = STEP;
+    //if(STEP < 8) offset = STEP*1.5;//to prevent a crash due to a very small step size
+    //----------------
+
+    vector<double> clustersize(numk, 0);
+    vector<double> inv(numk, 0);//to store 1/clustersize[k] values
+
+    vector<double> sigmal(numk, 0);
+    vector<double> sigmaa(numk, 0);
+    vector<double> sigmab(numk, 0);
+    vector<double> sigmax(numk, 0);
+    vector<double> sigmay(numk, 0);
+    vector<double> sigmaz(numk, 0);
+
+    vector< double > initdouble(sz, DBL_MAX);
+    vector< vector<double> > distvec(m_depth, initdouble);
+    //vector<double> distvec(sz, DBL_MAX);
+
+    double invwt = 1.0/((STEP/compactness)*(STEP/compactness));//compactness = 20.0 is usually good.
+
+    int x1, y1, x2, y2, z1, z2;
+    double l, a, b;
+    double dist;
+    double distxyz;
+    for ( int itr = 0; itr < 5; itr++ )
+    {
+        distvec.assign(m_depth, initdouble);
+        for ( int n = 0; n < numk; n++ )
+        {
+            y1 = max(0.0,     kseedsy[n]-offset);
+            y2 = min((double)m_height,  kseedsy[n]+offset);
+            x1 = max(0.0,     kseedsx[n]-offset);
+            x2 = min((double)m_width, kseedsx[n]+offset);
+            z1 = max(0.0,     kseedsz[n]-offset);
+            z2 = min((double)m_depth, kseedsz[n]+offset);
+
+
+            for ( int z = z1; z < z2; z++ )
+            {
+                for ( int y = y1; y < y2; y++ )
+                {
+                    for ( int x = x1; x < x2; x++ )
+                    {
+                        int i = y*m_width + x;
+
+                        l = m_lvecvec[z][i];
+                        a = m_avecvec[z][i];
+                        b = m_bvecvec[z][i];
+
+                        dist =      (l - kseedsl[n])*(l - kseedsl[n]) +
+                                 (a - kseedsa[n])*(a - kseedsa[n]) +
+                                 (b - kseedsb[n])*(b - kseedsb[n]);
+
+                        distxyz =   (x - kseedsx[n])*(x - kseedsx[n]) +
+                                   (y - kseedsy[n])*(y - kseedsy[n]) +
+                                   (z - kseedsz[n])*(z - kseedsz[n]);
+                        //------------------------------------------------------------------------
+                        dist += distxyz*invwt;
+                        //------------------------------------------------------------------------
+                        if ( dist < distvec[z][i] )
+                        {
+                            distvec[z][i] = dist;
+                            klabels[z][i]  = n;
+                        }
+                    }
+                }
+            }
+        }
+        //-----------------------------------------------------------------
+        // Recalculate the centroid and store in the seed values
+        //-----------------------------------------------------------------
+        //instead of reassigning memory on each iteration, just reset.
+
+        sigmal.assign(numk, 0);
+        sigmaa.assign(numk, 0);
+        sigmab.assign(numk, 0);
+        sigmax.assign(numk, 0);
+        sigmay.assign(numk, 0);
+        sigmaz.assign(numk, 0);
+        clustersize.assign(numk, 0);
+
+        for ( int d = 0; d < m_depth; d++  )
+        {
+            int ind(0);
+            for ( int r = 0; r < m_height; r++ )
+            {
+                for ( int c = 0; c < m_width; c++ )
+                {
+                    sigmal[klabels[d][ind]] += m_lvecvec[d][ind];
+                    sigmaa[klabels[d][ind]] += m_avecvec[d][ind];
+                    sigmab[klabels[d][ind]] += m_bvecvec[d][ind];
+                    sigmax[klabels[d][ind]] += c;
+                    sigmay[klabels[d][ind]] += r;
+                    sigmaz[klabels[d][ind]] += d;
+
+                    clustersize[klabels[d][ind]] += 1.0;
+                    ind++;
+                }
+            }
+        }
+
+        {
+            for ( int k = 0; k < numk; k++ )
+            {
+                if ( clustersize[k] <= 0 ) clustersize[k] = 1;
+                inv[k] = 1.0/clustersize[k];//computing inverse now to multiply, than divide later
+            }
+        }
+
+        {
+            for ( int k = 0; k < numk; k++ )
+            {
+                kseedsl[k] = sigmal[k]*inv[k];
+                kseedsa[k] = sigmaa[k]*inv[k];
+                kseedsb[k] = sigmab[k]*inv[k];
+                kseedsx[k] = sigmax[k]*inv[k];
+                kseedsy[k] = sigmay[k]*inv[k];
+                kseedsz[k] = sigmaz[k]*inv[k];
+            }
+        }
+    }
+}
+
+
+//===========================================================================
+/// SaveSuperpixelLabels
+///
+/// Save labels in raster scan order.
+//===========================================================================
+void SLIC::SaveSuperpixelLabels(
+    const int*&         labels,
+    const int&          width,
+    const int&          height,
+    const string&       filename,
+    const string&       path)
+{
+#ifdef WINDOWS
+    char fname[256];
+    char extn[256];
+    _splitpath(filename.c_str(), NULL, NULL, fname, extn);
+    string temp = fname;
+    string finalpath = path + temp + string(".dat");
+#else
+    string nameandextension = filename;
+    size_t pos = filename.find_last_of("/");
+    if (pos != string::npos)//if a slash is found, then take the filename with extension
+    {
+        nameandextension = filename.substr(pos+1);
+    }
+    string newname = nameandextension.replace(nameandextension.rfind(".")+1, 3, "dat");//find the position of the dot and replace the 3 characters following it.
+    string finalpath = path+newname;
+#endif
+
+    int sz = width*height;
+    ofstream outfile;
+    outfile.open(finalpath.c_str(), ios::binary);
+    for ( int i = 0; i < sz; i++ )
+    {
+        outfile.write((const char*)&labels[i], sizeof(int));
+    }
+    outfile.close();
+}
+
+
+//===========================================================================
+/// SaveSupervoxelLabels
+///
+/// Save labels in raster scan order.
+//===========================================================================
+void SLIC::SaveSupervoxelLabels(
+    const int**&        labels,
+    const int&          width,
+    const int&          height,
+    const int&          depth,
+    const string&       filename,
+    const string&       path)
+{
+#ifdef WINDOWS
+    char fname[256];
+    char extn[256];
+    _splitpath(filename.c_str(), NULL, NULL, fname, extn);
+    string temp = fname;
+    string finalpath = path + temp + string(".dat");
+#else
+    string nameandextension = filename;
+    size_t pos = filename.find_last_of("/");
+    if (pos != string::npos)//if a slash is found, then take the filename with extension
+    {
+        nameandextension = filename.substr(pos+1);
+    }
+    string newname = nameandextension.replace(nameandextension.rfind(".")+1, 3, "dat");//find the position of the dot and replace the 3 characters following it.
+    string finalpath = path+newname;
+#endif
+
+    int sz = width*height;
+    ofstream outfile;
+    outfile.open(finalpath.c_str(), ios::binary);
+    for ( int d = 0; d < depth; d++ )
+    {
+        for ( int i = 0; i < sz; i++ )
+        {
+            outfile.write((const char*)&labels[d][i], sizeof(int));
+        }
+    }
+    outfile.close();
+}
+
+//===========================================================================
+/// EnforceLabelConnectivity
+///
+///   1. finding an adjacent label for each new component at the start
+///   2. if a certain component is too small, assigning the previously found
+///       adjacent label to this component, and not incrementing the label.
+//===========================================================================
+void SLIC::EnforceLabelConnectivity(
+    const int*          labels,//input labels that need to be corrected to remove stray labels
+    const int         width,
+    const int         height,
+    int*&           nlabels,//new labels
+    int&            numlabels,//the number of labels changes in the end if segments are removed
+    const int&          K) //the number of superpixels desired by the user
+{
+//  const int dx8[8] = {-1, -1,  0,  1, 1, 1, 0, -1};
+//  const int dy8[8] = { 0, -1, -1, -1, 0, 1, 1,  1};
+
+    const int dx4[4] = {-1,  0,  1,  0};
+    const int dy4[4] = { 0, -1,  0,  1};
+
+    const int sz = width*height;
+    const int SUPSZ = sz/K;
+    //nlabels.resize(sz, -1);
+    for ( int i = 0; i < sz; i++ ) nlabels[i] = -1;
+    int label(0);
+    int* xvec = new int[sz];
+    int* yvec = new int[sz];
+    int oindex(0);
+    int adjlabel(0);//adjacent label
+    for ( int j = 0; j < height; j++ )
+    {
+        for ( int k = 0; k < width; k++ )
+        {
+            if ( 0 > nlabels[oindex] )
+            {
+                nlabels[oindex] = label;
+                //--------------------
+                // Start a new segment
+                //--------------------
+                xvec[0] = k;
+                yvec[0] = j;
+                //-------------------------------------------------------
+                // Quickly find an adjacent label for use later if needed
+                //-------------------------------------------------------
+                {
+                    for ( int n = 0; n < 4; n++ )
+                    {
+                        int x = xvec[0] + dx4[n];
+                        int y = yvec[0] + dy4[n];
+                        if ( (x >= 0 && x < width) && (y >= 0 && y < height) )
+                        {
+                            int nindex = y*width + x;
+                            if (nlabels[nindex] >= 0) adjlabel = nlabels[nindex];
+                        }
+                    }
+                }
+
+                int count(1);
+                for ( int c = 0; c < count; c++ )
+                {
+                    for ( int n = 0; n < 4; n++ )
+                    {
+                        int x = xvec[c] + dx4[n];
+                        int y = yvec[c] + dy4[n];
+
+                        if ( (x >= 0 && x < width) && (y >= 0 && y < height) )
+                        {
+                            int nindex = y*width + x;
+
+                            if ( 0 > nlabels[nindex] && labels[oindex] == labels[nindex] )
+                            {
+                                xvec[count] = x;
+                                yvec[count] = y;
+                                nlabels[nindex] = label;
+                                count++;
+                            }
+                        }
+
+                    }
+                }
+                //-------------------------------------------------------
+                // If segment size is less then a limit, assign an
+                // adjacent label found before, and decrement label count.
+                //-------------------------------------------------------
+                if (count <= SUPSZ >> 2)
+                {
+                    for ( int c = 0; c < count; c++ )
+                    {
+                        int ind = yvec[c]*width+xvec[c];
+                        nlabels[ind] = adjlabel;
+                    }
+                    label--;
+                }
+                label++;
+            }
+            oindex++;
+        }
+    }
+    numlabels = label;
+
+    if (xvec) delete [] xvec;
+    if (yvec) delete [] yvec;
+}
+
+
+//===========================================================================
+/// RelabelStraySupervoxels
+//===========================================================================
+void SLIC::EnforceSupervoxelLabelConnectivity(
+    int**&            labels,//input - previous labels, output - new labels
+    const int&          width,
+    const int&          height,
+    const int&          depth,
+    int&            numlabels,
+    const int&          STEP)
+{
+    const int dx10[10] = {-1,  0,  1,  0, -1,  1,  1, -1,  0, 0};
+    const int dy10[10] = { 0, -1,  0,  1, -1, -1,  1,  1,  0, 0};
+    const int dz10[10] = { 0,  0,  0,  0,  0,  0,  0,  0, -1, 1};
+
+    int sz = width*height;
+    const int SUPSZ = STEP*STEP*STEP;
+
+    int adjlabel(0);//adjacent label
+    int* xvec = new int[SUPSZ*10];//a large enough size
+    int* yvec = new int[SUPSZ*10];//a large enough size
+    int* zvec = new int[SUPSZ*10];//a large enough size
+    //------------------
+    // memory allocation
+    //------------------
+    int** nlabels = new int*[depth];
+    {
+        for ( int d = 0; d < depth; d++ )
+        {
+            nlabels[d] = new int[sz];
+            for ( int i = 0; i < sz; i++ ) nlabels[d][i] = -1;
+        }
+    }
+    //------------------
+    // labeling
+    //------------------
+    int lab(0);
+    {
+        for ( int d = 0; d < depth; d++ )
+        {
+            int i(0);
+            for ( int h = 0; h < height; h++ )
+            {
+                for ( int w = 0; w < width; w++ )
+                {
+                    if (nlabels[d][i] < 0)
+                    {
+                        nlabels[d][i] = lab;
+                        //-------------------------------------------------------
+                        // Quickly find an adjacent label for use later if needed
+                        //-------------------------------------------------------
+                        {
+                            for ( int n = 0; n < 10; n++ )
+                            {
+                                int x = w + dx10[n];
+                                int y = h + dy10[n];
+                                int z = d + dz10[n];
+                                if ( (x >= 0 && x < width) && (y >= 0 && y < height) && (z >= 0 && z < depth) )
+                                {
+                                    int nindex = y*width + x;
+                                    if (nlabels[z][nindex] >= 0)
+                                    {
+                                        adjlabel = nlabels[z][nindex];
+                                    }
+                                }
+                            }
+                        }
+
+                        xvec[0] = w;
+                        yvec[0] = h;
+                        zvec[0] = d;
+                        int count(1);
+                        for ( int c = 0; c < count; c++ )
+                        {
+                            for ( int n = 0; n < 10; n++ )
+                            {
+                                int x = xvec[c] + dx10[n];
+                                int y = yvec[c] + dy10[n];
+                                int z = zvec[c] + dz10[n];
+
+                                if ( (x >= 0 && x < width) && (y >= 0 && y < height) && (z >= 0 && z < depth))
+                                {
+                                    int nindex = y*width + x;
+
+                                    if ( 0 > nlabels[z][nindex] && labels[d][i] == labels[z][nindex] )
+                                    {
+                                        xvec[count] = x;
+                                        yvec[count] = y;
+                                        zvec[count] = z;
+                                        nlabels[z][nindex] = lab;
+                                        count++;
+                                    }
+                                }
+
+                            }
+                        }
+                        //-------------------------------------------------------
+                        // If segment size is less then a limit, assign an
+                        // adjacent label found before, and decrement label count.
+                        //-------------------------------------------------------
+                        if (count <= (SUPSZ >> 2))//this threshold can be changed according to needs
+                        {
+                            for ( int c = 0; c < count; c++ )
+                            {
+                                int ind = yvec[c]*width+xvec[c];
+                                nlabels[zvec[c]][ind] = adjlabel;
+                            }
+                            lab--;
+                        }
+                        //--------------------------------------------------------
+                        lab++;
+                    }
+                    i++;
+                }
+            }
+        }
+    }
+    //------------------
+    // mem de-allocation
+    //------------------
+    {
+        for ( int d = 0; d < depth; d++ )
+        {
+            for ( int i = 0; i < sz; i++ ) labels[d][i] = nlabels[d][i];
+        }
+    }
+    {
+        for ( int d = 0; d < depth; d++ )
+        {
+            delete [] nlabels[d];
+        }
+    }
+    delete [] nlabels;
+    //------------------
+    if (xvec) delete [] xvec;
+    if (yvec) delete [] yvec;
+    if (zvec) delete [] zvec;
+    //------------------
+    numlabels = lab;
+    //------------------
+}
+
+//===========================================================================
+/// DoSuperpixelSegmentation_ForGivenSuperpixelSize
+///
+/// The input parameter ubuff conains RGB values in a 32-bit unsigned integers
+/// as follows:
+///
+/// [1 1 1 1 1 1 1 1]  [1 1 1 1 1 1 1 1]  [1 1 1 1 1 1 1 1]  [1 1 1 1 1 1 1 1]
+///
+///        Nothing              R                 G                  B
+///
+/// The RGB values are accessed from (and packed into) the unsigned integers
+/// using bitwise operators as can be seen in the function DoRGBtoLABConversion().
+///
+/// compactness value depends on the input pixels values. For instance, if
+/// the input is greyscale with values ranging from 0-100, then a compactness
+/// value of 20.0 would give good results. A greater value will make the
+/// superpixels more compact while a smaller value would make them more uneven.
+///
+/// The labels can be saved if needed using SaveSuperpixelLabels()
+//===========================================================================
+void SLIC::DoSuperpixelSegmentation_ForGivenSuperpixelSize(
+    const unsigned int*         ubuff,
+    const int         width,
+    const int         height,
+    int*&           klabels,
+    int&            numlabels,
+    const int&          superpixelsize,
+    const double&               compactness)
+{
+    //------------------------------------------------
+    const int STEP = sqrt(double(superpixelsize))+0.5;
+    //------------------------------------------------
+    vector<double> kseedsl(0);
+    vector<double> kseedsa(0);
+    vector<double> kseedsb(0);
+    vector<double> kseedsx(0);
+    vector<double> kseedsy(0);
+
+    //--------------------------------------------------
+    m_width  = width;
+    m_height = height;
+    int sz = m_width*m_height;
+    //klabels.resize( sz, -1 );
+    //--------------------------------------------------
+    klabels = new int[sz];
+    for ( int s = 0; s < sz; s++ ) klabels[s] = -1;
+    //--------------------------------------------------
+    if (1)//LAB, the default option
+    {
+        DoRGBtoLABConversion(ubuff, m_lvec, m_avec, m_bvec);
+    }
+    else//RGB
+    {
+        m_lvec = new double[sz];
+        m_avec = new double[sz];
+        m_bvec = new double[sz];
+        for ( int i = 0; i < sz; i++ )
+        {
+            m_lvec[i] = ubuff[i] >> 16 & 0xff;
+            m_avec[i] = ubuff[i] >>  8 & 0xff;
+            m_bvec[i] = ubuff[i]       & 0xff;
+        }
+    }
+    //--------------------------------------------------
+    bool perturbseeds(false);//perturb seeds is not absolutely necessary, one can set this flag to false
+    vector<double> edgemag(0);
+    if (perturbseeds) DetectLabEdges(m_lvec, m_avec, m_bvec, m_width, m_height, edgemag);
+    GetLABXYSeeds_ForGivenStepSize(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, STEP, perturbseeds, edgemag);
+
+    PerformSuperpixelSLIC(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, klabels, STEP, edgemag,compactness);
+    numlabels = kseedsl.size();
+
+    int* nlabels = new int[sz];
+    EnforceLabelConnectivity(klabels, m_width, m_height, nlabels, numlabels, double(sz)/double(STEP*STEP));
+    {
+        for (int i = 0; i < sz; i++ ) klabels[i] = nlabels[i];
+    }
+    if (nlabels) delete [] nlabels;
+}
+
+//===========================================================================
+/// DoSuperpixelSegmentation_ForGivenNumberOfSuperpixels
+///
+/// The input parameter ubuff conains RGB values in a 32-bit unsigned integers
+/// as follows:
+///
+/// [1 1 1 1 1 1 1 1]  [1 1 1 1 1 1 1 1]  [1 1 1 1 1 1 1 1]  [1 1 1 1 1 1 1 1]
+///
+///        Nothing              R                 G                  B
+///
+/// The RGB values are accessed from (and packed into) the unsigned integers
+/// using bitwise operators as can be seen in the function DoRGBtoLABConversion().
+///
+/// compactness value depends on the input pixels values. For instance, if
+/// the input is greyscale with values ranging from 0-100, then a compactness
+/// value of 20.0 would give good results. A greater value will make the
+/// superpixels more compact while a smaller value would make them more uneven.
+///
+/// The labels can be saved if needed using SaveSuperpixelLabels()
+//===========================================================================
+void SLIC::DoSuperpixelSegmentation_ForGivenNumberOfSuperpixels(
+    const unsigned int*                             ubuff,
+    const int         width,
+    const int         height,
+    int*&           klabels,
+    int&            numlabels,
+    const int&          K,//required number of superpixels
+    const double&                                   compactness)//weight given to spatial distance
+{
+    const int superpixelsize = 0.5+double(width*height)/double(K);
+    DoSuperpixelSegmentation_ForGivenSuperpixelSize(ubuff,width,height,klabels,numlabels,superpixelsize,compactness);
+}
+
+//===========================================================================
+/// DoSupervoxelSegmentation
+///
+/// There is option to save the labels if needed.
+///
+/// The input parameter ubuffvec holds all the video frames. It is a
+/// 2-dimensional array. The first dimension is depth and the second dimension
+/// is pixel location in a frame. For example, to access a pixel in the 3rd
+/// frame (i.e. depth index 2), in the 4th row (i.e. height index 3) on the
+/// 37th column (i.e. width index 36), you would write:
+///
+/// unsigned int the_pixel_i_want = ubuffvec[2][3*width + 36]
+///
+/// In addition, here is how the RGB values are contained in a 32-bit unsigned
+/// integer:
+///
+/// [1 1 1 1 1 1 1 1]  [1 1 1 1 1 1 1 1]  [1 1 1 1 1 1 1 1]  [1 1 1 1 1 1 1 1]
+///
+///        Nothing              R                 G                  B
+///
+/// The RGB values are accessed from (and packed into) the unsigned integers
+/// using bitwise operators as can be seen in the function DoRGBtoLABConversion().
+///
+/// compactness value depends on the input pixels values. For instance, if
+/// the input is greyscale with values ranging from 0-100, then a compactness
+/// value of 20.0 would give good results. A greater value will make the
+/// supervoxels more compact while a smaller value would make them more uneven.
+//===========================================================================
+void SLIC::DoSupervoxelSegmentation(
+    unsigned int**&       ubuffvec,
+    const int&          width,
+    const int&          height,
+    const int&          depth,
+    int**&            klabels,
+    int&            numlabels,
+    const int&          supervoxelsize,
+    const double&               compactness)
+{
+    //---------------------------------------------------------
+    const int STEP = 0.5 + pow(double(supervoxelsize),1.0/3.0);
+    //---------------------------------------------------------
+    vector<double> kseedsl(0);
+    vector<double> kseedsa(0);
+    vector<double> kseedsb(0);
+    vector<double> kseedsx(0);
+    vector<double> kseedsy(0);
+    vector<double> kseedsz(0);
+
+    //--------------------------------------------------
+    m_width  = width;
+    m_height = height;
+    m_depth  = depth;
+    int sz = m_width*m_height;
+
+    //--------------------------------------------------
+    //klabels = new int*[depth];
+    m_lvecvec = new double*[depth];
+    m_avecvec = new double*[depth];
+    m_bvecvec = new double*[depth];
+    for ( int d = 0; d < depth; d++ )
+    {
+        //klabels[d] = new int[sz];
+        m_lvecvec[d] = new double[sz];
+        m_avecvec[d] = new double[sz];
+        m_bvecvec[d] = new double[sz];
+        for ( int s = 0; s < sz; s++ )
+        {
+            klabels[d][s] = -1;
+        }
+    }
+
+    DoRGBtoLABConversion(ubuffvec, m_lvecvec, m_avecvec, m_bvecvec);
+
+    GetKValues_LABXYZ(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, kseedsz, STEP);
+
+    PerformSupervoxelSLIC(kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, kseedsz, klabels, STEP, compactness);
+
+    EnforceSupervoxelLabelConnectivity(klabels, width, height, depth, numlabels, STEP);
+}
+

+ 234 - 0
SLIC/SLIC.h

@@ -0,0 +1,234 @@
+// SLIC.h: interface for the SLIC class.
+//===========================================================================
+// This code implements the superpixel method described in:
+//
+// Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua, and Sabine Susstrunk,
+// "SLIC Superpixels",
+// EPFL Technical Report no. 149300, June 2010.
+//===========================================================================
+//	Copyright (c) 2012 Radhakrishna Achanta [EPFL]. All rights reserved.
+//===========================================================================
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(_SLIC_H_INCLUDED_)
+#define _SLIC_H_INCLUDED_
+
+
+#include <vector>
+#include <string>
+#include <algorithm>
+using namespace std;
+
+
+class SLIC  
+{
+public:
+	SLIC();
+	virtual ~SLIC();
+	//============================================================================
+	// Superpixel segmentation for a given step size (superpixel size ~= step*step)
+	//============================================================================
+        void DoSuperpixelSegmentation_ForGivenSuperpixelSize(
+        const unsigned int*                            ubuff,//Each 32 bit unsigned int contains ARGB pixel values.
+		const int					width,
+		const int					height,
+		int*&						klabels,
+		int&						numlabels,
+                const int&					superpixelsize,
+                const double&                                   compactness);
+	//============================================================================
+	// Superpixel segmentation for a given number of superpixels
+	//============================================================================
+        void DoSuperpixelSegmentation_ForGivenNumberOfSuperpixels(
+        const unsigned int*                             ubuff,
+		const int					width,
+		const int					height,
+		int*&						klabels,
+		int&						numlabels,
+                const int&					K,//required number of superpixels
+                const double&                                   compactness);//10-20 is a good value for CIELAB space
+	//============================================================================
+	// Supervoxel segmentation for a given step size (supervoxel size ~= step*step*step)
+	//============================================================================
+	void DoSupervoxelSegmentation(
+		unsigned int**&		ubuffvec,
+		const int&					width,
+		const int&					height,
+		const int&					depth,
+		int**&						klabels,
+		int&						numlabels,
+                const int&					supervoxelsize,
+                const double&                                   compactness);
+	//============================================================================
+	// Save superpixel labels in a text file in raster scan order
+	//============================================================================
+	void SaveSuperpixelLabels(
+		const int*&					labels,
+		const int&					width,
+		const int&					height,
+		const string&				filename,
+		const string&				path);
+	//============================================================================
+	// Save supervoxel labels in a text file in raster scan, depth order
+	//============================================================================
+	void SaveSupervoxelLabels(
+		const int**&				labels,
+		const int&					width,
+		const int&					height,
+		const int&					depth,
+		const string&				filename,
+		const string&				path);
+	//============================================================================
+	// Function to draw boundaries around superpixels of a given 'color'.
+	// Can also be used to draw boundaries around supervoxels, i.e layer by layer.
+	//============================================================================
+	void DrawContoursAroundSegments(
+		unsigned int*&				segmentedImage,
+		int*&						labels,
+		const int&					width,
+		const int&					height,
+		const unsigned int&			color );
+
+private:
+	//============================================================================
+	// The main SLIC algorithm for generating superpixels
+	//============================================================================
+	void PerformSuperpixelSLIC(
+		vector<double>&				kseedsl,
+		vector<double>&				kseedsa,
+		vector<double>&				kseedsb,
+		vector<double>&				kseedsx,
+		vector<double>&				kseedsy,
+		int*&						klabels,
+		const int&					STEP,
+                const vector<double>&		edgemag,
+		const double&				m = 10.0);
+	//============================================================================
+	// The main SLIC algorithm for generating supervoxels
+	//============================================================================
+	void PerformSupervoxelSLIC(
+		vector<double>&				kseedsl,
+		vector<double>&				kseedsa,
+		vector<double>&				kseedsb,
+		vector<double>&				kseedsx,
+		vector<double>&				kseedsy,
+		vector<double>&				kseedsz,
+		int**&						klabels,
+		const int&					STEP,
+		const double&				compactness);
+	//============================================================================
+	// Pick seeds for superpixels when step size of superpixels is given.
+	//============================================================================
+	void GetLABXYSeeds_ForGivenStepSize(
+		vector<double>&				kseedsl,
+		vector<double>&				kseedsa,
+		vector<double>&				kseedsb,
+		vector<double>&				kseedsx,
+		vector<double>&				kseedsy,
+		const int&					STEP,
+		const bool&					perturbseeds,
+		const vector<double>&		edgemag);
+	//============================================================================
+	// Pick seeds for supervoxels
+	//============================================================================
+	void GetKValues_LABXYZ(
+		vector<double>&				kseedsl,
+		vector<double>&				kseedsa,
+		vector<double>&				kseedsb,
+		vector<double>&				kseedsx,
+		vector<double>&				kseedsy,
+		vector<double>&				kseedsz,
+		const int&					STEP);
+	//============================================================================
+	// Move the superpixel seeds to low gradient positions to avoid putting seeds
+	// at region boundaries.
+	//============================================================================
+	void PerturbSeeds(
+		vector<double>&				kseedsl,
+		vector<double>&				kseedsa,
+		vector<double>&				kseedsb,
+		vector<double>&				kseedsx,
+		vector<double>&				kseedsy,
+		const vector<double>&		edges);
+	//============================================================================
+	// Detect color edges, to help PerturbSeeds()
+	//============================================================================
+	void DetectLabEdges(
+		const double*				lvec,
+		const double*				avec,
+		const double*				bvec,
+		const int&					width,
+		const int&					height,
+		vector<double>&				edges);
+	//============================================================================
+	// sRGB to XYZ conversion; helper for RGB2LAB()
+	//============================================================================
+	void RGB2XYZ(
+		const int&					sR,
+		const int&					sG,
+		const int&					sB,
+		double&						X,
+		double&						Y,
+		double&						Z);
+	//============================================================================
+	// sRGB to CIELAB conversion (uses RGB2XYZ function)
+	//============================================================================
+	void RGB2LAB(
+		const int&					sR,
+		const int&					sG,
+		const int&					sB,
+		double&						lval,
+		double&						aval,
+		double&						bval);
+	//============================================================================
+	// sRGB to CIELAB conversion for 2-D images
+	//============================================================================
+	void DoRGBtoLABConversion(
+		const unsigned int*&		ubuff,
+		double*&					lvec,
+		double*&					avec,
+		double*&					bvec);
+	//============================================================================
+	// sRGB to CIELAB conversion for 3-D volumes
+	//============================================================================
+	void DoRGBtoLABConversion(
+		unsigned int**&				ubuff,
+		double**&					lvec,
+		double**&					avec,
+		double**&					bvec);
+	//============================================================================
+	// Post-processing of SLIC segmentation, to avoid stray labels.
+	//============================================================================
+	void EnforceLabelConnectivity(
+		const int*					labels,
+		const int					width,
+		const int					height,
+		int*&						nlabels,//input labels that need to be corrected to remove stray labels
+		int&						numlabels,//the number of labels changes in the end if segments are removed
+		const int&					K); //the number of superpixels desired by the user
+	//============================================================================
+	// Post-processing of SLIC supervoxel segmentation, to avoid stray labels.
+	//============================================================================
+	void EnforceSupervoxelLabelConnectivity(
+		int**&						labels,//input - previous labels, output - new labels
+		const int&					width,
+		const int&					height,
+		const int&					depth,
+		int&						numlabels,
+		const int&					STEP);
+
+private:
+	int										m_width;
+	int										m_height;
+	int										m_depth;
+
+	double*									m_lvec;
+	double*									m_avec;
+	double*									m_bvec;
+
+	double**								m_lvecvec;
+	double**								m_avecvec;
+	double**								m_bvecvec;
+};
+
+#endif // !defined(_SLIC_H_INCLUDED_)

+ 176 - 0
edisonSegm/MSReadme.txt

@@ -0,0 +1,176 @@
+Mean Shift Image Processor Class ver1.0 README
+----------------------------------------------
+
+Class Overview:
+===============
+
+The mean shift image processor class is designed to offer the following functionality:
+
+	(1) Perform image segmentation and edge-preserving filtering using the mean shift algorithm.
+	(2) Perform (1) using a general kernel and/or an arbitrary input data space.
+
+Table of Contents:
+-------------------
+(A) Image Segmentation and Filtering
+(B) Synergistic Image Segmentation
+(C) Using a General Kernel
+(D) Using an Arbitrary Input Data Space
+(E) The Class Error Handler
+(F) Current Version Information
+(G) References
+(H) Contact Information
+
+================================================================================================
+
+(A) Image Segmentation and Filtering
+
+-------------------------------------------------------------------------------------------------
+
+Mean shift based image segmentation and filtering is performed using use the following methods:
+
+	msImageProcess::Filter		- filters the image
+	msImageProcessor::Segment	- segments the image
+
+The input image processed by these methods is defined via the method,
+
+msImageProcessor::DefineImage	- this uploads the RGB data into the msImageProcessor class for processing
+
+To obtain the output call:
+
+	msImageProcessor::GetResults	- returns filtered or segmented image in RGB space
+	msImageProcessor::GetBoundaries	- returns the boundaries of regions resulting from filtering
+					  or segmentation
+	msImageProcessor::GetRegions	- returns the classification structure that maps each
+					  data point in the image to a given mode, and also
+					  the number of points in the image correlating to each mode.
+
+NOTE:
+-----
+
+The modes returned by GetRegions are not in the RGB space. If DefineImage was used, they are in the LUV space. The modes may be converted from LUV to RGB (and visa versa) using the space conversion methods of the msImageProcessor class:
+
+	msImageProcessor::RGBtoLUV	- converts data points from the RGB data space to LUV
+	msImageProcessor::LUVtoRGB	- converts data points from the LUV data space to RGB
+
+Alternatively, mean shift may be applyed to data that lies in a space other than LUV. This may be accomplished through the use of the method MeanShift::DefineLInput (see section D).
+
+================================================================================================
+
+(B) Synergistic Image Segmentation
+
+-------------------------------------------------------------------------------------------------
+
+A weight map may be provided to the mean shift image processor class, used to perform synergistic image segmentation as described in the paper [3]. One may specify a weight map by calling either of the following methods:
+
+	MeanShift::SetWeightMap			- defines the weight map used to specify a weighted kernel during
+						  mean shift; the weight map may only be used for data that lies
+						  on a lattice (e.g. an image)
+	msImageProcessor::SetWeightMap		- specifies a weight map to be used for performing synergistic image
+						  segmentation
+
+Each of the above methods accept a floating point array of size L elements containing the weight map. When using the mean shift base class L is the number of data points in the specified data set; when using the image processor class L = height x width, where height and width are the dimensions of the image. The method msImageProcessor::SetWeightMap accepts an additional parameter, namely t_e, a threshold value used during the transitive closure step of the image segmentation algorithm. See the paper [3] for details.
+
+================================================================================================
+
+(C) Using a General Kernel
+
+-------------------------------------------------------------------------------------------------
+
+A general kernel can be used to perform mean shift filtering and segmentation by calling the inherited method:
+
+	MeanShift::DefineKernel	- defines an N-dimensional kernel having kp subspaces, in which each subspace
+				  can be of one of three types: Uniform, Gaussian, or UserDefined.
+
+DefineImage, used to define the input image when performing image segmentation or filtering, defines a Uniform kernel having two subspaces (one spatial (x,y) and one range (L,U,V)) each subspace having bandwidths sigmaS and sigmaR respectively. By skimming the method definition one may get an idea of how to define a general kernel.
+
+NOTE:
+----
+
+For data that is defined on a lattice, it is always assumed that the spatial domain is treated as a single subspace. Also, DefineKernel() must be called *after* DefineImage() when these methods are used together.
+
+================================================================================================
+
+(D) Using an Arbitrary Input Data Space
+
+-------------------------------------------------------------------------------------------------
+
+Mean shift filtering and segmentation may be performed on an arbitary image data space. Such data is defined through calling the inherited method:
+
+	MeanShift::DefineLInput	- specifies input defined on a lattice
+
+DefineImage() calls this method using the LUV data it generates. Through the use of the above methods, mean shift may be applied to an arbitrary input data space using a general kernel. In doing so, one must ensure that the dimension of the input data space and kernel are the same (N). If their dimensions do not agree an error will be flagged.
+
+================================================================================================
+
+(F) The Class Error Handler
+
+-------------------------------------------------------------------------------------------------
+
+The mean shift image processor class uses an error message string and error-level flag to perform error handling. These two variables, MeanShift::ErrorMessage and MeanShift::ErrorLevel, are public data members of the class.
+
+Upon the occurance of an error,
+
+	* An error message is copied into the error message string.
+	* The error level of the class is set to EL_ERROR.
+
+The following example demonstrates the use of the error handling mechanism described above.
+
+msImageProcessor iProc;
+
+...
+
+iProc.Segment(sigmaS, sigmaR, minRegion, SPEEDUP);
+if(iProc.ErrorLevel == EL_ERROR)
+{
+	fprintf(stderr, iProc.ErrorMessage);	
+	exit(1);
+}
+
+...
+
+================================================================================================
+
+(G) Current Version Information
+
+-------------------------------------------------------------------------------------------------
+
+The current version of the code was tested under both UNIX and Windows environments.
+
+================================================================================================
+
+(H) References
+
+-------------------------------------------------------------------------------------------------
+
+[1] D. Comanicu, P. Meer: "Mean shift: A robust approach toward feature space analysis".
+    IEEE Trans. Pattern Anal. Machine Intell., May 2002.
+
+[2] P. Meer, B. Georgescu: "Edge detection with embedded confidence". IEEE Trans. Pattern Anal.
+    Machine Intell., 28, 2001.
+
+[3] C. Christoudias, B. Georgescu, P. Meer: "Synergism in low level vision". 16th International
+    Conference of Pattern Recognition, Track 1 - Computer Vision and Robotics, Quebec City,
+    Canada, August 2001.
+
+================================================================================================
+
+(I) Contact Information
+
+-------------------------------------------------------------------------------------------------
+
+Personal Contact Information
+----------------------------
+
+Email:
+
+	cmch@caip.rutgers.edu		(Chris Christoudias)
+	georgesc@caip.rutgers.edu	(Bogdan Georgescu)
+
+Laboratory Contact Information
+------------------------------
+
+Laboratory Website:
+
+	www.caip.rutgers.edu/riul/
+
+================================================================================================

+ 103 - 0
edisonSegm/Makefile.inc

@@ -0,0 +1,103 @@
+# LIBRARY-DIRECTORY-MAKEFILE
+# conventions:
+# - all subdirectories containing a "Makefile.inc" are considered sublibraries
+#   exception: "progs/" and "tests/" subdirectories!
+# - all ".C", ".cpp" and ".c" files in the current directory are linked to a
+#   library
+# - the library depends on all sublibraries 
+# - the library name is created with $(LIBNAME), i.e. it will be somehow
+#   related to the directory name and with the extension .a
+#   (e.g. lib1/sublib -> lib1_sublib.a)
+# - the library will be added to the default build list ALL_LIBRARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+ifeq "$(SUBDIR)" "./"
+SUBDIR:=
+endif
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# you can specify libraries needed by the individual objects or by the whole
+# directory. the object specific additional libraries are only considered
+# when compiling the specific object files
+# TODO: update documentation...
+
+-include $(SUBDIR)libdepend.inc
+
+$(foreach d,$(filter-out %progs %tests,$(SUBDIRS_OF_$(SUBDIR))),$(eval $(call PKG_DEPEND_INT,$(d))))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+	  $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+LIBRARY_BASENAME:=$(call LIBNAME,$(SUBDIR))
+ifneq "$(SUBDIR)" ""
+ALL_LIBRARIES+=$(LIBDIR)$(LIBRARY_BASENAME).$(LINK_FILE_EXTENSION)
+endif
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. the current library depends on all sublibraries.
+# all other dependencies have to be added manually by specifying, that the
+# current .pc file depends on some other .pc file. binaries depending on
+# libraries should exclusivelly use the .pc files as well.
+
+ifeq "$(SKIP_BUILD_$(OBJDIR))" "1"
+$(LIBDIR)$(LIBRARY_BASENAME).a:
+else
+$(LIBDIR)$(LIBRARY_BASENAME).a:$(OBJS) \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).a,.$(LINK_FILE_EXTENSION))
+endif
+
+$(PKGDIR)$(LIBRARY_BASENAME).pc: \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).pc,.pc)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 172 - 0
edisonSegm/RAList.cpp

@@ -0,0 +1,172 @@
+/*******************************************************
+
+                 Mean Shift Analysis Library
+	=============================================
+
+	The mean shift library is a collection of routines
+	that use the mean shift algorithm. Using this algorithm,
+	the necessary output will be generated needed
+	to analyze a given input set of data.
+
+  Region Adjacency List:
+  =====================
+
+	The Region Adjacency List class is used by the Image 
+	Processor class in the construction of a Region Adjacency
+	Matrix, used by	this class to applying transitive closure
+	and to prune spurious regions during image segmentation.
+
+	The definition of the RAList class is provided below. Its
+	prototype is provided in "RAList.h".
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+									 space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+//include Region Adjacency List class prototype
+#include	"RAList.h"
+
+//include needed libraries
+#include	<stdio.h>
+#include	<assert.h>
+#include	<stdlib.h>
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@      PUBLIC METHODS     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+	/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+	/* Class Constructor and Destructor */
+	/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Class Constructor                                    */
+/*******************************************************/
+/*Constructs a RAList object.                          */
+/*******************************************************/
+/*Post:                                                */
+/*      - a RAlist object has been properly constru-   */
+/*        cted.                                        */
+/*******************************************************/
+
+RAList::RAList( void )
+{
+	//initialize label and link
+	label			= -1;
+	next			= NULL;
+
+	//initialize edge strenght weight and count
+	edgeStrength	= 0;
+	edgePixelCount	= 0;
+}
+
+/*******************************************************/
+/*Class Destructor                                     */
+/*******************************************************/
+/*Destructrs a RAList object.                          */
+/*******************************************************/
+/*Post:                                                */
+/*      - the RAList object has been properly dest-    */
+/*        ructed.                                      */
+/*******************************************************/
+
+RAList::~RAList( void )
+{
+	//do nothing
+}
+
+/*******************************************************/
+/*Insert                                               */
+/*******************************************************/
+/*Insert a region node into the region adjacency list. */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - entry is a node representing a connected re- */
+/*        gion                                         */
+/*Post:                                                */
+/*      - entry has been inserted into the region adj- */
+/*        acency list if it does not already exist     */
+/*        there.                                       */
+/*      - if the entry already exists in the region    */
+/*        adjacency list 1 is returned otherwise 0 is  */
+/*        returned.                                    */
+/*******************************************************/
+
+int RAList::Insert(RAList *entry)
+{
+
+	//if the list contains only one element
+	//then insert this element into next
+	if(!next)
+	{
+		//insert entry
+		next		= entry;
+		entry->next = NULL;
+
+		//done
+		return 0;
+	}
+
+	//traverse the list until either:
+
+	//(a) entry's label already exists - do nothing
+	//(b) the list ends or the current label is
+	//    greater than entry's label, thus insert the entry
+	//    at this location
+
+	//check first entry
+	if(next->label > entry->label)
+	{
+		//insert entry into the list at this location
+		entry->next	= next;
+		next		= entry;
+
+		//done
+		return 0;
+	}
+
+	//check the rest of the list...
+	exists	= 0;
+	cur		= next;
+	while(cur)
+	{
+		if(entry->label == cur->label)
+		{
+			//node already exists
+			exists = 1;
+			break;
+		}
+		else if((!(cur->next))||(cur->next->label > entry->label))
+		{
+			//insert entry into the list at this location
+			entry->next	= cur->next;
+			cur->next	= entry;
+			break;
+		}
+
+		//traverse the region adjacency list
+		cur = cur->next;
+	}
+
+	//done. Return exists indicating whether or not a new node was
+	//      actually inserted into the region adjacency list.
+	return (int)(exists);
+
+}
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ END OF CLASS DEFINITION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+

+ 92 - 0
edisonSegm/RAList.h

@@ -0,0 +1,92 @@
+/*******************************************************
+
+                 Mean Shift Analysis Library
+	=============================================
+
+	The mean shift library is a collection of routines
+	that use the mean shift algorithm. Using this algorithm,
+	the necessary output will be generated needed
+	to analyze a given input set of data.
+
+  Region Adjacency List:
+  =====================
+
+	The Region Adjacency List class is used by the Image 
+	Processor class in the construction of a Region Adjacency
+	Matrix, used by	this class to applying transitive closure
+	and to prune spurious regions during image segmentation.
+
+	The prototype for the RAList class is provided below. Its
+	defition is provided in "RAList.cc".
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+									 space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+
+#ifndef RALIST_H
+#define RALIST_H
+
+//define Region Adjacency List class prototype
+class RAList {
+
+public:
+
+	//============================
+	// *** Public Data Members ***
+	//============================
+
+	////////////RAM Label//////////
+	int		label;
+
+	////////////RAM Weight/////////
+	float	edgeStrength;
+	int		edgePixelCount;
+
+	////////////RAM Link///////////
+	RAList	*next;
+
+	//=======================
+	// *** Public Methods ***
+	//=======================
+
+	/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+	/* Class Constructor and Destructor */
+	/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+	//***Class Constrcutor***
+	RAList( void );
+
+	//***Class Destructor***
+	~RAList( void );
+
+	/*/\/\/\/\/\/\/\/\/\/\/\/\*/
+	/*  RAM List Manipulation */
+	/*\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+	//Usage: Insert(entry)
+	int Insert(RAList*);		//Insert a region node into the region adjecency list
+
+private:
+
+	//=============================
+	// *** Private Data Members ***
+	//=============================
+
+	///////current and previous pointer/////
+	RAList	*cur, *prev;
+
+	////////flag///////////
+	unsigned char exists;
+
+};
+
+#endif

+ 1 - 0
edisonSegm/libdepend.inc

@@ -0,0 +1 @@
+$(call PKG_DEPEND_EXT,OPENMP)

+ 2467 - 0
edisonSegm/ms.cpp

@@ -0,0 +1,2467 @@
+/*******************************************************
+
+  Mean Shift Analysis Library
+  =============================================
+
+ The mean shift library is a collection of routines
+ that use the mean shift algorithm. Using this algorithm,
+ the necessary output will be generated needed
+ to analyze a given input set of data.
+
+  MeanShift Base Class:
+  ====================
+
+ The mean shift library of routines is realized
+ via the creation of a MeanShift base class. This class
+ provides a mechanism for calculating the mean shift vector
+ at a specified data point, using an arbitrary N-dimensional
+ data set, and a user-defined kernel.
+
+ For image processing the mean shift base class also allows
+ for the definition of a data set that is on a two-dimensional
+ lattice. The amount of time needed to compute the mean shift
+ vector using such a data set is much less than that of an
+ arbitrary one. Because images usually contain many data points,
+ defining the image input data points as being on a lattice
+ greatly improves computation time and makes algorithms such
+ as image filtering practical.
+
+ The definition of the MeanShift class is provided below. Its
+ prototype is provided in 'ms.h'.
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+          space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+
+
+//Include Needed Libraries
+
+#include "ms.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@      PUBLIC METHODS     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*** Constructor/Destructor ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Class Constructor                                    */
+/*******************************************************/
+/*Post:                                                */
+/*      The MeanShift class has been properly          */
+/*      initialized.                                   */
+/*******************************************************/
+
+MeanShift::MeanShift ( void )
+{
+
+  //intialize input data set parameters...
+  P       = NULL;
+  L       = 0;
+  N       = 0;
+  kp       = 0;
+
+  //initialize input data set storage structures...
+  data      = NULL;
+
+  //initialize input data set kd-tree
+  root      = NULL;
+  forest      = NULL;
+  range      = NULL;
+
+  //intialize lattice structure...
+  height      = 0;
+  width      = 0;
+
+  //intialize kernel strucuture...
+  h       = NULL;
+  kernel      = NULL;
+  w       = NULL;
+  offset      = NULL;
+  increment     = NULL;
+  uniformKernel    = false;
+
+  //initialize weight function linked list...
+  head      = cur = NULL;
+
+  //intialize mean shift processing data structures...
+  uv       = NULL;
+
+  //set lattice weight map to null
+  weightMap     = NULL;
+
+  //indicate that the lattice weight map is undefined
+  weightMapDefined   = false;
+
+  //allocate memory for error message buffer...
+  ErrorMessage    = new char [256];
+
+  //initialize error status to OKAY
+  ErrorStatus     = EL_OKAY;
+
+  //Initialize class state...
+  class_state.INPUT_DEFINED = false;
+  class_state.KERNEL_DEFINED = false;
+  class_state.LATTICE_DEFINED = false;
+  class_state.OUTPUT_DEFINED = false;
+
+}
+
+/*******************************************************/
+/*Class Destructor                                     */
+/*******************************************************/
+/*Post:                                                */
+/*      The MeanShift class has been properly          */
+/*      destroyed.                                     */
+/*******************************************************/
+
+MeanShift::~MeanShift ( void )
+{
+  delete [] ErrorMessage;
+  if ( weightMap )
+  {
+    delete [] weightMap;
+  }
+
+  //de-allocate memory used to store
+  //user defined weight functions
+  ClearWeightFunctions();
+
+  //de-allocate memory used for kernel
+  DestroyKernel();
+
+  //de-allocate memory used for input
+  ResetInput();
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*** Creation/Initialization of Mean Shift Kernel ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Define Kernel                                        */
+/*******************************************************/
+/*Creats custom user defined Kernel to be used by the  */
+/*mean shift procedure.                                */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - kernel is an array of kernelTypes specifying */
+/*        the type of kernel to be used on each sub-   */
+/*        space of the input data set x                */
+/*      - h is the set of bandwidths used to define the*/
+/*        the search window                            */
+/*      - P is a one dimensional array of integers of  */
+/*        size kp, that specifies the dimension of each*/
+/*        subspace of the input data set x             */
+/*      - kp is the total number of subspaces used to  */
+/*        the input data set x                         */
+/*Post:                                                */
+/*      - the custom kernel has been created for use   */
+/*        by the mean shift procedure.                 */
+/*******************************************************/
+
+void MeanShift::DefineKernel ( kernelType *kernel_, float *h_, int *P_, int kp_ )
+{
+
+  // Declare variables
+  int i, kN;
+
+  //if a kernel has already been created then destroy it
+  if ( kp )
+    DestroyKernel();
+
+  //Obtain kp...
+  if ( ( kp = kp_ ) <= 0 )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "CreateKernel", ( char * ) "Subspace count (kp) is zero or negative." );
+    return;
+  }
+
+  //Allocate memory for h, P, kernel, offset, and increment
+  if ( ( ! ( P = new int [kp] ) ) || ( ! ( h = new float [kp] ) ) || ( ! ( kernel = new kernelType [kp] ) ) ||
+       ( ! ( offset = new float [kp] ) ) || ( ! ( increment = new double [kp] ) ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "CreateKernel", ( char * ) "Not enough memory available to create kernel." );
+    return;
+  }
+
+  //Populate h, P and kernel, also use P to calculate
+  //the dimension (N_) of the potential input data set x
+  kN = 0;
+  for ( i = 0; i < kp; i++ )
+  {
+    if ( ( h[i] = h_[i] ) <= 0 )
+    {
+      ErrorHandler ( ( char * ) "MeanShift", ( char * ) "CreateKernel", ( char * ) "Negative or zero valued bandwidths are prohibited." );
+      return;
+    }
+    if ( ( P[i] = P_[i] ) <= 0 )
+    {
+      ErrorHandler ( ( char * ) "MeanShift", ( char * ) "CreateKernel", ( char * ) "Negative or zero valued subspace dimensions are prohibited." );
+      return;
+    }
+    kernel[i] = kernel_[i];
+    kN    += P[i];
+  }
+
+  //Allocate memory for range vector and uv using N_
+  if ( ( ! ( range = new float [2*kN] ) ) || ( ! ( uv = new double [kN] ) ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "CreateKernel", ( char * ) "Not enough memory available to create kernel." );
+    return;
+  }
+
+  // Generate weight function lookup table
+  // using above information and user
+  // defined weight function list
+  generateLookupTable();
+
+  //check for errors
+  if ( ErrorStatus == EL_ERROR )
+    return;
+
+  //indicate that the kernel has been defined
+  class_state.KERNEL_DEFINED = true;
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Add Weight Function                                  */
+/*******************************************************/
+/*Adds a weight function to the Mean Shift class to be */
+/*used by the mean shift procedure                     */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - g(u) is the normalized weight function with  */
+/*        respect to u = (norm(x-xi))^2/h^2            */
+/*      - sampleNumber is the number of samples to be  */
+/*        taken of g(u) over halfWindow interval       */
+/*      - halfWindow is the radius of g(u) such that   */
+/*        g(u) is defined for 0 <= u <= halfWindow     */
+/*      - subspace is the subspace number for which    */
+/*        g(u) is to be applied during the mean shift  */
+/*        procedure.                                   */
+/*Post:                                                */
+/*      - g(u) has been added to the Mean Shift class  */
+/*        private data structure to be used by the     */
+/*        mean shift procedure.                        */
+/*      - if a weight function has already been spec-  */
+/*        ified for the specified subspace, the weight */
+/*        function for this subspace has been replaced.*/
+/*******************************************************/
+
+void MeanShift::AddWeightFunction ( double g ( double ), float halfWindow, int sampleNumber, int subspace )
+{
+
+  // Declare Variables
+  int   i;
+  double increment;
+
+  // Search to see if a weight function has already been
+  // defined for specified subspace, if not then insert
+  // into the head of the weight function list, otherwise
+  // replace entry
+
+  // Perform Search
+  cur = head;
+  while ( ( cur ) && ( cur->subspace != subspace ) )
+    cur = cur->next;
+
+  // Entry Exists - Replace It!
+  // Otherwise insert at the head of the the weight functon list
+  if ( cur )
+    delete cur->w;
+  else
+  {
+    cur       = new userWeightFunct;
+    cur->next = head;
+    head      = cur;
+  }
+
+  // Generate lookup table
+  increment = halfWindow / ( double ) ( sampleNumber );
+
+  cur->w = new double [sampleNumber+1];
+  for ( i = 0; i <= sampleNumber; i++ )
+    cur->w[i] = g ( ( double ) ( i * increment ) );
+
+  // Set weight function parameters
+  cur->halfWindow   = halfWindow;
+  cur->sampleNumber = sampleNumber;
+  cur->subspace     = subspace;
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Clear Weight Functions                               */
+/*******************************************************/
+/*Clears user defined weight from the Mean Shift class */
+/*private data structure.                              */
+/*******************************************************/
+/*Post:                                                */
+/*      - all user defined weight functions ahve been  */
+/*        cleared from the private data structure of   */
+/*        the mean shift class.                        */
+/*******************************************************/
+
+void MeanShift::ClearWeightFunctions ( void )
+{
+
+  while ( head )
+  {
+    delete head->w;
+    cur  = head;
+    head = head->next;
+    delete cur;
+  }
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*** Input Data Set Declaration ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Define Input                                         */
+/*******************************************************/
+/*Uploads input data set x into the mean shift class.  */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - x is a one dimensional array of L N-dimen-   */
+/*        ional data points.                           */
+/*Post:                                                */
+/*      - x has been uploaded into the mean shift      */
+/*        class.                                       */
+/*      - the height and width of a previous data set  */
+/*        has been undefined.                          */
+/*******************************************************/
+
+void MeanShift::DefineInput ( float *x, int L_, int N_ )
+{
+
+
+  //if input data is defined de-allocate memory, and
+  //re-initialize the input data structure
+  if ( ( class_state.INPUT_DEFINED ) || ( class_state.LATTICE_DEFINED ) )
+    ResetInput();
+
+  //make sure x is not NULL...
+  if ( !x )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "UploadInput", ( char * ) "Input data set is NULL." );
+    return;
+  }
+
+  //Obtain L and N
+  if ( ( ( L = L_ ) <= 0 ) || ( ( N = N_ ) <= 0 ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "UploadInput", ( char * ) "Input data set has negative or zero length or dimension." );
+    return;
+  }
+
+  //Allocate memory for data
+  if ( ! ( data = new float [L*N] ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "UploadInput", ( char * ) "Not enough memory." );
+    return;
+  }
+
+  //Allocate memory for input data set, and copy
+  //x into the private data members of the mean
+  //shift class
+  InitializeInput ( x );
+
+  //check for errors
+  if ( ErrorStatus == EL_ERROR )
+    return;
+
+  // Load x into the MeanShift object using
+  // using a kd-tree, resulting in better
+  // range searching of the input data points
+  // x - also upload window centers into
+  // msRawData
+  CreateBST();
+
+  //indicate that the input has been recently defined
+  class_state.INPUT_DEFINED = true;
+  class_state.LATTICE_DEFINED = false;
+  class_state.OUTPUT_DEFINED = false;
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Define Lattice                                       */
+/*******************************************************/
+/*Defines the height and width of the input lattice.   */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - ht is the height of the lattice              */
+/*      - wt is the width of the lattice               */
+/*Post:                                                */
+/*      - the height and width of the lattice has been */
+/*        specified.                                   */
+/*      - if a data set is presently loaded into the   */
+/*        mean shift class, an error is flagged if the */
+/*        number of elements in that data set does not */
+/*        equal the product ht*wt.                     */
+/*******************************************************/
+
+void MeanShift::DefineLInput ( float *x, int ht, int wt, int N_ )
+{
+
+  //if input data is defined de-allocate memory, and
+  //re-initialize the input data structure
+  if ( ( class_state.INPUT_DEFINED ) || ( class_state.LATTICE_DEFINED ) )
+    ResetInput();
+
+  //Obtain lattice height and width
+  if ( ( ( height = ht ) <= 0 ) || ( ( width = wt ) <= 0 ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "DefineLInput", ( char * ) "Lattice defined using zero or negative height and/or width." );
+    return;
+  }
+
+  //Obtain input data dimension
+  if ( ( N = N_ ) <= 0 )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "DefineInput", ( char * ) "Input defined using zero or negative dimension." );
+    return;
+  }
+
+  //compute the data length, L, of input data set
+  //using height and width
+  L  = height * width;
+
+  //Allocate memory for input data set, and copy
+  //x into the private data members of the mean
+  //shift class
+  InitializeInput ( x );
+
+  //check for errors
+  if ( ErrorStatus == EL_ERROR )
+    return;
+
+  //allocate memory for weight map
+  if ( ! ( weightMap = new float [L] ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "InitializeInput", ( char * ) "Not enough memory." );
+    return;
+  }
+
+  //initialize weightMap to an array of zeros
+  memset ( weightMap, 0, L* ( sizeof ( float ) ) );
+
+  //Indicate that a lattice input has recently been
+  //defined
+  class_state.LATTICE_DEFINED = true;
+  class_state.INPUT_DEFINED = false;
+  class_state.OUTPUT_DEFINED = false;
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Set Lattice Weight Map                               */
+/*******************************************************/
+/*Populates the lattice weight map with specified      */
+/*weight values.                                       */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - wm is a floating point array of size L       */
+/*        specifying for each data point a weight      */
+/*        value                                        */
+/*Post:                                                */
+/*      - wm has been used to populate the lattice     */
+/*        weight map.                                  */
+/*******************************************************/
+
+void MeanShift::SetLatticeWeightMap ( float *wm )
+{
+  //make sure wm is not NULL
+  if ( !wm )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "SetWeightMap", ( char * ) "Specified weight map is NULL." );
+    return;
+  }
+
+  //populate weightMap using wm
+  int i;
+  for ( i = 0; i < L; i++ )
+    weightMap[i] = wm[i];
+
+  //indicate that a lattice weight map has been specified
+  weightMapDefined = true;
+
+  //done.
+  return;
+
+}
+
+
+/*******************************************************/
+/*Remove Lattice Weight Map                            */
+/*******************************************************/
+/*Removes the lattice weight map.                      */
+/*******************************************************/
+/*Post:                                                */
+/*      - the lattice weight map has been removed.     */
+/*      - if a weight map did not exist NO error is    */
+/*        flagged.                                     */
+/*******************************************************/
+
+void MeanShift::RemoveLatticeWeightMap ( void )
+{
+
+  //only remove weight map if it exists, otherwise
+  //do nothing...
+  if ( weightMapDefined )
+  {
+    //set values of lattice weight map to zero
+    memset ( weightMap, 0, L*sizeof ( float ) );
+
+    //indicate that a lattice weight map is no longer
+    //defined
+    weightMapDefined = false;
+  }
+
+  //done.
+  return;
+
+}
+
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*** Mean Shift Operations  ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Mean Shift Vector                                    */
+/*******************************************************/
+/*Calculates the mean shift vector at a specified data */
+/*point yk.                                            */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - a kernel has been created                    */
+/*      - a data set has been uploaded                 */
+/*      - Mh is an N dimensional mean shift vector     */
+/*      - yk is an N dimensional data point            */
+/*Post:                                                */
+/*      - the mean shift vector at yk has been         */
+/*        calculated and stored in and returned by Mh. */
+/*******************************************************/
+
+void MeanShift::msVector ( double *Mh, double *yk )
+{
+
+  //make sure that Mh and/or yk are not NULL...
+  if ( ( !Mh ) || ( !yk ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "msVector", ( char * ) "Invalid argument(s) passed to this method." );
+    return;
+  }
+
+  //make sure that a kernel has been created, data has
+  //been uploaded, and that they are consistent with one
+  //another...
+  classConsistencyCheck ( N, false );
+
+  //calculate mean shift vector at yk using created kernel
+  //and uploaded data set
+  MSVector ( Mh, yk );
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Lattice Mean Shift Vector                            */
+/*******************************************************/
+/*Calculates the mean shift vector at a specified data */
+/*point yk, assuming that the data set exhists on a    */
+/*height x width two dimensional lattice.              */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - a kernel has been created                    */
+/*      - a data set has been uploaded                 */
+/*      - the height and width of the lattice has been */
+/*        specified using method DefineLattice()       */
+/*      - Mh is an N dimensional mean shift vector     */
+/*      - yk is an N dimensional data point            */
+/*Post:                                                */
+/*      - the mean shift vector at yk has been         */
+/*        calculated and stored in and returned by Mh. */
+/*      - Mh was calculated using the defined input    */
+/*        lattice.                                     */
+/*******************************************************/
+
+void MeanShift::latticeMSVector ( double *Mh, double *yk )
+{
+
+  //make sure that Mh and/or yk are not NULL...
+  if ( ( !Mh ) || ( !yk ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "lmsVector", ( char * ) "Invalid argument(s) passed to this method." );
+    return;
+  }
+
+  //make sure that a kernel has been created, data has
+  //been uploaded, and that they are consistent with one
+  //another...
+  classConsistencyCheck ( N + 2, true );
+
+  //calculate mean shift vector at yk using created kernel
+  //and uploaded data set
+  LatticeMSVector ( Mh, yk );
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Find Mode                                            */
+/*******************************************************/
+/*Calculates the mode of a specified data point yk.    */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - a kernel has been created                    */
+/*      - a data set has been uploaded                 */
+/*      - mode is the N dimensional mode of the N-dim- */
+/*        ensional data point yk                       */
+/*Post:                                                */
+/*      - the mode of yk has been calculated and       */
+/*        stored in mode.                              */
+/*******************************************************/
+
+void MeanShift::FindMode ( double *mode, double *yk )
+{
+
+  //make sure that mode and/or yk are not NULL...
+  if ( ( !mode ) || ( !yk ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "FindMode", ( char * ) "Invalid argument(s) passed to this method." );
+    return;
+  }
+
+  //make sure that a kernel has been created, data has
+  //been uploaded, and that they are consistent with one
+  //another...
+  classConsistencyCheck ( N, false );
+
+  //allocate memory for Mh
+  double *Mh = new double [N];
+
+  //copy yk into mode
+  int i;
+  for ( i = 0; i < N; i++ )
+    mode[i] = yk[i];
+
+  //calculate mean shift vector at yk
+  MSVector ( Mh, yk );
+
+  //calculate mvAbs = |Mh|^2
+  double mvAbs = 0;
+  for ( i = 0; i < N; i++ )
+    mvAbs += Mh[i] * Mh[i];
+
+  //shift mode until convergence (mvAbs = 0)...
+  int iterationCount = 1;
+  while ( ( mvAbs >= EPSILON2 ) && ( iterationCount < LIMIT ) )
+  {
+    //shift mode...
+    for ( i = 0; i < N; i++ )
+      mode[i] += Mh[i];
+
+    //re-calculate mean shift vector at new
+    //window location have center defined by
+    //mode
+    MSVector ( Mh, mode );
+
+    //calculate mvAbs = |Mh|^2
+    mvAbs = 0;
+    for ( i = 0; i < N; i++ )
+      mvAbs += Mh[i] * Mh[i];
+
+    //increment interation count...
+    iterationCount++;
+
+  }
+
+  //shift mode...
+  for ( i = 0; i < N; i++ )
+    mode[i] += Mh[i];
+
+  //de-allocate memory
+  delete [] Mh;
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Find Lattice Mode                                    */
+/*******************************************************/
+/*Calculates the mode of a specified data point yk,    */
+/*assuming that the data set exhists on a height x     */
+/*width two dimensional lattice.                       */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - a kernel has been created                    */
+/*      - a data set has been uploaded                 */
+/*      - the height and width of the lattice has been */
+/*        specified using method DefineLattice()       */
+/*      - mode is the N dimensional mode of the N-dim- */
+/*        ensional data point yk                       */
+/*Post:                                                */
+/*      - the mode of yk has been calculated and       */
+/*        stored in mode.                              */
+/*      - mode was calculated using the defined input  */
+/*        lattice.                                     */
+/*******************************************************/
+
+void MeanShift::FindLMode ( double *mode, double *yk )
+{
+
+  //make sure that mode and/or yk are not NULL...
+  if ( ( !mode ) || ( !yk ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "FindLMode", ( char * ) "Invalid argument(s) passed to this method." );
+    return;
+  }
+
+  //make sure the lattice height and width have been defined...
+  if ( !height )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "FindLMode", ( char * ) "Lattice height and width is undefined." );
+    return;
+  }
+
+  //make sure that a kernel has been created, data has
+  //been uploaded, and that they are consistent with one
+  //another...
+  classConsistencyCheck ( N + 2, true );
+
+  //define gridN
+  int gridN = N + 2;
+
+  //allocate memory for Mh
+  double *Mh = new double [gridN];
+
+  //copy yk into mode
+  int i;
+  for ( i = 0; i < gridN; i++ )
+    mode[i] = yk[i];
+
+  //calculate mean shift vector at yk
+  LatticeMSVector ( Mh, mode );
+
+  //calculate mvAbs = |Mh|^2
+  double mvAbs = 0;
+  for ( i = 0; i < gridN; i++ )
+    mvAbs += Mh[i] * Mh[i];
+
+  //shift mode until convergence (mvAbs = 0)...
+  int iterationCount = 1;
+  while ( ( mvAbs >= EPSILON2 ) && ( iterationCount < LIMIT ) )
+  {
+    //shift mode...
+    for ( i = 0; i < gridN; i++ )
+      mode[i] += Mh[i];
+
+    //re-calculate mean shift vector at new
+    //window location have center defined by
+    //mode
+    LatticeMSVector ( Mh, mode );
+
+    //calculate mvAbs = |Mh|^2
+    mvAbs = 0;
+    for ( i = 0; i < gridN; i++ )
+      mvAbs += Mh[i] * Mh[i];
+
+    //increment interation count...
+    iterationCount++;
+
+  }
+
+  //shift mode...
+  for ( i = 0; i < gridN; i++ )
+    mode[i] += Mh[i];
+
+  //de-allocate memory
+  delete [] Mh;
+
+  //done.
+  return;
+
+}
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    PROTECTED METHODS    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/* Mean Shift: Using kd-Tree  */
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Mean Shift Vector                                    */
+/*******************************************************/
+/*Computes the mean shift vector at a window location  */
+/*yk using input data set x using a custom, user defin-*/
+/*ed kernel.                                           */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - input data has been uploaded into the private*/
+/*        data members of the MeanShift class          */
+/*      - a window center yk has been defined          */
+/*      - uniformKernel indicates the which type of    */
+/*        kernel to be used by this procedure: uniform */
+/*        or general                                   */
+/*Post:                                                */
+/*      - the mean shift vector calculated at yk       */
+/*        using a either a custom, user defined kernel */
+/*        or a uniform kernel is returned              */
+/*******************************************************/
+
+void MeanShift::MSVector ( double *Mh_ptr, double *yk_ptr )
+{
+
+  // Declare Variables
+  int i, j;
+
+  // Initialize mean shift vector
+  for ( i = 0; i < N; i++ )
+    Mh_ptr[i] = 0;
+
+  // Initialize wsum to zero, the sum of the weights of each
+  // data point found to lie within the search window (sphere)
+  wsum = 0;
+
+  // Build Range Vector using h[i] and yk
+
+  int s = 0;
+
+  // The flag uniformKernel is used to determine which
+  // kernel function is to be used in the calculation
+  // of the mean shift vector
+  if ( uniformKernel )
+  {
+    for ( i = 0; i < kp; i++ )
+    {
+      for ( j = 0; j < P[i]; j++ )
+      {
+        range[2* ( s+j ) ] = ( float ) ( yk_ptr[s+j] - h[i] );
+        range[2* ( s+j ) +1] = ( float ) ( yk_ptr[s+j] + h[i] );
+      }
+      s += P[i];
+    }
+  }
+  else
+  {
+    for ( i = 0; i < kp; i++ )
+    {
+      for ( j = 0; j < P[i]; j++ )
+      {
+        range[2* ( s+j ) ] = ( float ) ( yk_ptr[s+j] - h[i] * float ( sqrt ( offset[i] ) ) );
+        range[2* ( s+j ) +1] = ( float ) ( yk_ptr[s+j] + h[i] * float ( sqrt ( offset[i] ) ) );
+      }
+      s += P[i];
+    }
+  }
+
+  // Traverse through the data set x, performing the
+  // weighted sum of each point xi that lies within
+  // the search window (sphere) using a general,
+  // user defined kernel or uniform kernel depending
+  // on the uniformKernel flag
+  if ( uniformKernel )
+    uniformSearch ( root, 0, Mh_ptr, yk_ptr );
+  else
+    generalSearch ( root, 0, Mh_ptr, yk_ptr );
+
+  // Calculate the mean shift vector using Mh and wsum
+  for ( i = 0; i < N; i++ )
+  {
+
+    // Divide Sum by wsum
+    Mh_ptr[i] /= wsum;
+
+    // Calculate mean shift vector: Mh(yk) = y(k+1) - y(k)
+    Mh_ptr[i] -= yk_ptr[i];
+
+  }
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*  Mean Shift: Using Lattice */
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Lattice Mean Shift Vector                            */
+/*******************************************************/
+/*Computes the mean shift vector at a specfied window  */
+/*yk using the lattice data structure.                 */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - Mh_ptr and yh_ptr are arrays of doubles con- */
+/*        aining N+2 elements                          */
+/*      - Mh_ptr is the mean shift vector calculated   */
+/*        at window center yk_ptr                      */
+/*Post:                                                */
+/*      - the mean shift vector at the window center   */
+/*        pointed to by yk_ptr has been calculated and */
+/*        stored in the memory location pointed to by  */
+/*        Mh_ptr                                       */
+/*******************************************************/
+
+void MeanShift::LatticeMSVector ( double *Mh_ptr, double *yk_ptr )
+{
+
+  // Initialize mean shift vector
+  register int i;
+  for ( i = 0; i < N + 2; i++ )
+    Mh_ptr[i] = 0;
+
+  // Initialize wsum
+  wsum = 0;
+
+  // Perform lattice search summing
+  // all the points that lie within the search
+  // window defined using the kernel specified
+  //by uniformKernel
+  if ( uniformKernel )
+    uniformLSearch ( Mh_ptr, yk_ptr );
+  else
+    generalLSearch ( Mh_ptr, yk_ptr );
+
+  // Compute mean shift vector using sum computed
+  // by lattice search, wsum, and yk_ptr:
+  // Mh = Mh/wsum - yk_ptr
+
+  if ( wsum > 0 )
+  {
+    for ( i = 0; i < N + 2; i++ )
+      Mh_ptr[i] = Mh_ptr[i] / wsum - yk_ptr[i];
+  }
+  else
+  {
+    for ( i = 0; i < N + 2; i++ )
+      Mh_ptr[i] = 0;
+  }
+
+  // done.
+  return;
+
+}
+
+/*******************************************************/
+/*Optimized Lattice Mean Shift Vector                  */
+/*******************************************************/
+/*Computes the mean shift vector at a specfied window  */
+/*yk using the lattice data structure. Also the points */
+/*that lie within the window are stored into the basin */
+/*of attraction structure used by the optimized mean   */
+/*shift algorithms.            */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - Mh_ptr and yh_ptr are arrays of doubles con- */
+/*        aining N+2 elements                          */
+/*      - Mh_ptr is the mean shift vector calculated   */
+/*        at window center yk_ptr                      */
+/*Post:                                                */
+/*      - the mean shift vector at the window center   */
+/*        pointed to by yk_ptr has been calculated and */
+/*        stored in the memory location pointed to by  */
+/*        Mh_ptr                                       */
+/*      - the data points lying within h of of yk_ptr  */
+/*        have been stored into the basin of attract-  */
+/*        ion data structure.                          */
+/*******************************************************/
+
+void MeanShift::OptLatticeMSVector ( double *Mh_ptr, double *yk_ptr )
+{
+
+  // Initialize mean shift vector
+  register int i;
+  for ( i = 0; i < N + 2; i++ )
+    Mh_ptr[i] = 0;
+
+  // Initialize wsum
+  wsum = 0;
+
+  // Perform lattice search summing
+  // all the points that lie within the search
+  // window defined using the kernel specified
+  //by uniformKernel
+  if ( uniformKernel )
+    optUniformLSearch ( Mh_ptr, yk_ptr );
+  else
+    optGeneralLSearch ( Mh_ptr, yk_ptr );
+
+  // Compute mean shift vector using sum computed
+  // by lattice search, wsum, and yk_ptr:
+  // Mh = Mh/wsum - yk_ptr
+
+  if ( wsum > 0 )
+  {
+    for ( i = 0; i < N + 2; i++ )
+      Mh_ptr[i] = Mh_ptr[i] / wsum - yk_ptr[i];
+  } else
+  {
+    for ( i = 0; i < N + 2; i++ )
+      Mh_ptr[i] = 0;
+  }
+
+  // done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*** Kernel-Input Data Consistency  ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Class Consistency Check                              */
+/*******************************************************/
+/*Checks the state of the class prior to the applicat- */
+/*ion of mean shift.                                   */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - iN is the specified dimension of the input,  */
+/*        iN = N for a general input data set, iN = N  */
+/*        + 2 for a input set defined using a lattice  */
+/*Post:                                                */
+/*      - if the kernel has not been created, an input */
+/*        has not been defined and/or the specified    */
+/*        input dimension (iN) does not match that of  */
+/*        the kernel a fatal error is flagged.         */
+/*******************************************************/
+
+void MeanShift::classConsistencyCheck ( int iN, bool usingLattice )
+{
+
+  //make sure that kernel has been created...
+  if ( class_state.KERNEL_DEFINED == false )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "classConsistencyCheck", ( char * ) "Kernel not created." );
+    return;
+  }
+
+  //make sure input data set has been loaded into mean shift object...
+  if ( ( class_state.INPUT_DEFINED == false ) && ( !usingLattice ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "classConsistencyCheck", ( char * ) "No input data specified." );
+    return;
+  }
+
+  //make sure that the lattice is defined if it is being used
+  if ( ( class_state.LATTICE_DEFINED == false ) && ( usingLattice ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "classConsistencyCheck", ( char * ) "Latice not created." );
+    return;
+  }
+
+  //make sure that dimension of the kernel and the input data set
+  //agree
+
+  //calculate dimension of kernel (kN)
+  int i, kN = 0;
+  for ( i = 0; i < kp; i++ )
+    kN += P[i];
+
+  //perform comparison...
+  if ( iN != kN )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "classConsitencyCheck", ( char * ) "Kernel dimension does not match defined input data dimension." );
+    return;
+  }
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*** Class Error Handler  ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Error Handler                                        */
+/*******************************************************/
+/*Class error handler.                                 */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - className is the name of the class that fl-  */
+/*        agged an error                               */
+/*      - methodName is the name of the method that    */
+/*        flagged an error                             */
+/*      - errmsg is the error message given by the     */
+/*        calling function                             */
+/*Post:                                                */
+/*      - the error message errmsg is flagged on beh-  */
+/*        ave of method methodName belonging to class  */
+/*        className:                                   */
+/*                                                     */
+/*        (1) ErrorMessage has been updated with the   */
+/*            appropriate error message using the arg- */
+/*            ments passed to this method.             */
+/*        (2) ErrorStatus is set to ERROR              */
+/*            (ErrorStatus = 1)                        */
+/*******************************************************/
+
+void MeanShift::ErrorHandler ( char *className, char *methodName, char* errmsg )
+{
+
+  //store trace into error message
+  strcpy ( ErrorMessage, className );
+  strcat ( ErrorMessage, ( char * ) "::" );
+  strcat ( ErrorMessage, methodName );
+  strcat ( ErrorMessage, ( char * ) " Error: (char *)" );
+
+  //store message into error message
+  strcat ( ErrorMessage, errmsg );
+
+  //set error status to ERROR
+  ErrorStatus = EL_ERROR;
+
+
+}
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     PRIVATE METHODS     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*** Kernel Creation/Manipulation ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Generate Lookup Table                                */
+/*******************************************************/
+/*A weight function look up table is generated.        */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - kernel is an array of kernelTypes specifying */
+/*        the type of kernel to be used on each sub-   */
+/*        space of the input data set x                */
+/*      - kp is the total number of subspaces used to  */
+/*        the input data set x                         */
+/*      - the above information has been pre-loaded    */
+/*        into the MeanShift class private members     */
+/*Post:                                                */
+/*      - a lookup table is generated for the weight   */
+/*        function of the resulting kernel             */
+/*      - uniformKernel is set to true if the kernel   */
+/*        to be used is uniform, false is returned     */
+/*        otherwise                                    */
+/*      - if a user defined weight function is requred */
+/*        for a given subspace but not defined in the  */
+/*        user defined weight function list, an error  */
+/*        is flagged and the program is halted         */
+/*******************************************************/
+
+void MeanShift::generateLookupTable ( void )
+{
+
+  // Declare Variables
+  int i, j;
+
+  // Allocate memory for lookup table w
+  w = new double*[kp];
+
+  // Traverse through kernel generating weight function
+  // lookup table w
+
+  // Assume kernel is uniform
+  uniformKernel = true;
+
+  for ( i = 0; i < kp; i++ )
+  {
+    switch ( kernel[i] )
+    {
+        // *Uniform Kernel* has weight funciton w(u) = 1
+        // therefore, a weight funciton lookup table is
+        // not needed for this kernel --> w[i] = NULL indicates
+        // this
+      case Uniform:
+
+        w        [i] = NULL;  //weight function not needed for this kernel
+        offset   [i] =    1;  //uniform kernel has u < 1.0
+        increment[i] =    1;  //has no meaning
+        break;
+
+        // *Gaussian Kernel* has weight function w(u) = constant*exp(-u^2/[2h[i]^2])
+      case Gaussian:
+
+        // Set uniformKernel to false
+        uniformKernel = false;
+
+        // generate weight function using expression,
+        // exp(-u/2), where u = norm(xi - x)^2/h^2
+
+        // Allocate memory for weight table
+        w[i] = new double [GAUSS_NUM_ELS+1];
+
+        for ( j = 0; j <= GAUSS_NUM_ELS; j++ )
+          w[i][j] = exp ( -j * GAUSS_INCREMENT / 2 );
+
+        // Set offset = offset^2, and set increment
+        offset   [i] = ( float ) ( GAUSS_LIMIT * GAUSS_LIMIT );
+        increment[i] = GAUSS_INCREMENT;
+
+        // done
+        break;
+
+        // *User Define Kernel* uses the weight function wf(u)
+      case UserDefined:
+
+        // Set uniformKernel to false
+        uniformKernel = false;
+
+        // Search for user defined weight function
+        // defined for subspace (i+1)
+        cur = head;
+        while ( ( cur ) && ( cur->subspace != ( i + 1 ) ) )
+          cur = cur->next;
+
+        // If a user defined subspace has not been found
+        // for this subspace, flag an error
+        if ( cur == NULL )
+        {
+          fprintf ( stderr, ( char * ) "\ngenerateLookupTable Fatal Error: User defined kernel for subspace %d undefined.\n\nAborting Program.\n\n", i + 1 );
+          exit ( 1 );
+        }
+
+        // Otherwise, copy weight function lookup table to w[i]
+        w[i] = new double [cur->sampleNumber+1];
+        for ( j = 0; j <= cur->sampleNumber; j++ )
+          w[i][j] = cur->w[j];
+
+        // Set offset and increment accordingly
+        offset   [i] = ( float ) ( cur->halfWindow );
+        increment[i] = cur->halfWindow / ( float ) ( cur->sampleNumber );
+
+        // done
+        break;
+
+      default:
+
+        ErrorHandler ( ( char * ) "MeanShift", ( char * ) "generateLookupTable", ( char * ) "Unknown kernel type." );
+
+    }
+
+  }
+}
+
+/*******************************************************/
+/*Destroy Kernel                                       */
+/*******************************************************/
+/*Destroys and initializes kernel.                     */
+/*******************************************************/
+/*Post:                                                */
+/*      - memory for the kernel private data members   */
+/*        have been destroyed and the kernel has been  */
+/*        initialized for re-use.                      */
+/*******************************************************/
+
+void MeanShift::DestroyKernel ( void )
+{
+
+  //de-allocate memory...
+  if ( kernel ) delete [] kernel;
+  if ( h ) delete [] h;
+  if ( P ) delete [] P;
+  if ( range ) delete [] range;
+
+  if ( uv ) delete [] uv;
+  if ( increment ) delete [] increment;
+  if ( offset ) delete [] offset;
+
+  if ( kp > 0 )
+  {
+    if ( w )
+    {
+      int i;
+      for ( i = 0; i < kp; i++ )
+        delete [] w[i];
+      delete [] w;
+    }
+    w = NULL;
+  }
+
+  //intialize kernel for re-use...
+  kp  = 0;
+  kernel = NULL;
+  h  = NULL;
+  P  = NULL;
+  range = NULL;
+
+  increment = NULL;
+  uv = NULL;
+  offset = NULL;
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*** Input Data Initialization/Destruction  ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Create Binary Search Tree                            */
+/*******************************************************/
+/*Uploads input data set x into a kd-BST.              */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - x is a one dimensional array of L N-dimensi- */
+/*        onal data points                             */
+/*Post:                                                */
+/*      - x has been uploaded into a balanced kd-BST   */
+/*        data structure for use by the mean shift     */
+/*        procedure                                    */
+/*******************************************************/
+
+void MeanShift::CreateBST ( void )
+{
+
+  // Create BST using data....
+
+  // Allocate memory for tree
+  forest = new tree[L];
+
+  // Populate 'forest' of tree's with
+  // the values stored in x
+  int i;
+  for ( i = 0; i < L; i++ )
+  {
+    forest[i].x      = &data[i*N];
+    forest[i].right  = NULL;
+    forest[i].left   = NULL;
+    forest[i].parent = NULL;
+  }
+
+  // Build balanced Nd-tree from the
+  // forest of trees generated above
+  // retaining the root of this tree
+
+  root = BuildKDTree ( forest, L, 0, NULL );
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Initialize Input                                     */
+/*******************************************************/
+/*Allocates memory for and initializes the input data  */
+/*structure.                                           */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - x is a floating point array of L, N dimens-  */
+/*        ional input data points                      */
+/*Post:                                                */
+/*      - memory has been allocated for the input data */
+/*        structure and x has been stored using into   */
+/*        the mean shift class using the resulting     */
+/*        structure.                                   */
+/*******************************************************/
+
+void MeanShift::InitializeInput ( float *x )
+{
+
+  //allocate memory for input data set
+  if ( ! ( data = new float [L*N] ) )
+  {
+    ErrorHandler ( ( char * ) "MeanShift", ( char * ) "InitializeInput", ( char * ) "Not enough memory." );
+    return;
+  }
+
+  //copy x into data
+  int i;
+  for ( i = 0; i < L*N; i++ )
+    data[i] = x[i];
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Reset Input                                          */
+/*******************************************************/
+/*De-allocates memory for and re-intializes input data */
+/*structure.                                           */
+/*******************************************************/
+/*Post:                                                */
+/*      - the memory of the input data structure has   */
+/*        been de-allocated and this strucuture has    */
+/*        been initialized for re-use.                 */
+/*******************************************************/
+
+void MeanShift::ResetInput ( void )
+{
+
+  //de-allocate memory of input data structure (BST)
+  if ( data ) delete [] data;
+  if ( forest ) delete [] forest;
+
+  //initialize input data structure for re-use
+  data = NULL;
+  forest = NULL;
+  root = NULL;
+  L  = 0;
+  N  = 0;
+  width = 0;
+  height = 0;
+
+  //re-set class input to indicate that
+  //an input is not longer stored by
+  //the private data members of this class
+  class_state.INPUT_DEFINED = class_state.LATTICE_DEFINED = false;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*** k-dimensional Binary Search Tree ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Build KD Tree (for Tree Structure)                   */
+/*******************************************************/
+/*Builds a KD Tree given a forest of tree's.           */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - subset is a subset of L un-ordered tree nodes*/
+/*        each containing an N-dimensional data point  */
+/*      - d is the depth of the subset, used to specify*/
+/*        the dimension used to construct the tree at  */
+/*        the given depth                              */
+/*      - parent is the parent tree of subset          */
+/*Post:                                                */
+/*      - a balanced KD tree has been constructed using*/
+/*        the forest subset, the root of this tree has */
+/*        been returned                                */
+/*******************************************************/
+
+tree *MeanShift::BuildKDTree ( tree *subset, int length, int d, tree* parent )
+{
+
+  // If the subset is a single tree
+  // then return this tree otherwise
+  // partition the subset and place
+  // these subsets recursively into
+  // the left and right sub-trees having
+  // their root specified by the median
+  // of this subset in dimension d
+  if ( length == 1 )
+  {
+    subset->parent = parent;
+    return subset;
+  }
+  else if ( length > 1 )
+  {
+
+    // Sort Subset
+    QuickMedian ( subset, 0, length - 1, d );
+
+    // Get Median of Subset and Partition
+    // it into two sub-trees - create
+    // a tree with its root being the median
+    // of the subset and its left and right
+    // children being the medians of the subsets
+    int median            = length / 2;
+    subset[median].parent = parent;
+    subset[median].left   = BuildKDTree ( subset           , median         , ( d + 1 ) % N, &subset[median] );
+    subset[median].right  = BuildKDTree ( &subset[median+1], length - median - 1, ( d + 1 ) % N, &subset[median] );
+
+    // Output tree structure
+    return &subset[median];
+
+  }
+  else
+    return NULL;
+
+  //done.
+
+}
+
+/*******************************************************/
+/*Quick Median (for Tree Structure)                    */
+/*******************************************************/
+/*Finds the median element in an un-ordered set, re-   */
+/*structuring the set such that points less than the   */
+/*median point are located to the left of the median   */
+/*and points greater than the median point are located */
+/*to the right.                                        */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - arr is a subset of tree nodes whose leftmost */
+/*        element is specified by left and rightmost   */
+/*        element is specified by left                 */
+/*      - d is the dimension of the data set stored by */
+/*        the tree structure that is used to find      */
+/*        the median                                   */
+/*Post:                                                */
+/*      - the median point is found and the subset     */
+/*        of trees is re-ordered such that all trees   */
+/*        whose data points with d dimensional value   */
+/*        less than that of the median tree node are   */
+/*        located to the left of the median tree node, */
+/*        otherwise they are located to the right      */
+/*******************************************************/
+
+void MeanShift::QuickMedian ( tree *arr, int left, int right, int d )
+{
+  unsigned long k;
+  unsigned long n;
+  float* a;
+  float* temp;
+  n = right - left + 1;
+  k = n / 2 + 1;
+  unsigned long i, ir, j, l, mid;
+
+  l = 1;
+  ir = n;
+  for ( ;; )
+  {
+    if ( ir <= l + 1 )
+    {
+      if ( ir == l + 1 && arr[ir-1].x[d] < arr[l-1].x[d] )
+      {
+        SWAP ( arr[l-1].x, arr[ir-1].x )
+      }
+      return;
+    } else
+    {
+      mid = ( l + ir ) >> 1;
+      SWAP ( arr[mid-1].x, arr[l+1-1].x )
+      if ( arr[l-1].x[d] > arr[ir-1].x[d] )
+      {
+        SWAP ( arr[l-1].x, arr[ir-1].x )
+      }
+      if ( arr[l+1-1].x[d] > arr[ir-1].x[d] )
+      {
+        SWAP ( arr[l+1-1].x, arr[ir-1].x )
+      }
+      if ( arr[l-1].x[d] > arr[l+1-1].x[d] )
+      {
+        SWAP ( arr[l-1].x, arr[l+1-1].x )
+      }
+      i = l + 1;
+      j = ir;
+      a = arr[l+1-1].x;
+      for ( ;; ) {
+        do i++;
+        while ( arr[i-1].x[d] < a[d] );
+        do j--;
+        while ( arr[j-1].x[d] > a[d] );
+        if ( j < i ) break;
+        SWAP ( arr[i-1].x, arr[j-1].x )
+      }
+      arr[l+1-1].x = arr[j-1].x;
+      arr[j-1].x = a;
+      if ( j >= k ) ir = j - 1;
+      if ( j <= k ) l = i;
+    }
+  }
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*** Mean Shift: Using kd-Tree  ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Uniform Search                                       */
+/*******************************************************/
+/*Searches the input data using a kd-tree, performs the*/
+/*sum on the data within the Hypercube defined by the  */
+/*tree using a uniform kernel.                         */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - gt is a possibly NULL pointer to a kd tree   */
+/*      - Mh_ptr is a pointer to the mean shift vector */
+/*        being calculated                             */
+/*      - yk_ptr is a pointer to the current window    */
+/*        center location                              */
+/*      - gd is the depth of the current subtree       */
+/*Post:                                                */
+/*      - the mean of the points within the Hypercube  */
+/*        of the kd tree is computed using a uniform   */
+/*        kernel                                       */
+/*******************************************************/
+
+void MeanShift::uniformSearch ( tree *gt, int gd, double *Mh_ptr, double *yk_ptr )
+{
+  tree* c_t;
+  int c_d;
+  int i;
+  int actionType;
+
+  c_t = gt;
+  c_d = gd;
+  actionType = 0;
+
+  double el, diff;
+  int k, j, s;
+
+  while ( c_t != NULL )
+  {
+    switch ( actionType ) {
+      case 0: // forward
+        if ( ( c_t->x[c_d] > range[2*c_d] ) && ( ( c_t->left ) != NULL ) )
+        {
+          c_t = c_t->left;
+          c_d = ( c_d + 1 ) % N;
+        } else
+        {
+          actionType = 1;
+        }
+        break;
+      case 1: // backleft
+
+        for ( i = 0; i < N; i++ )
+        {
+          if ( ( c_t->x[i] < range[2*i] ) || ( c_t->x[i] > range[2*i+1] ) )
+            break;
+        }
+
+        if ( i == N )
+        {
+
+          // ***     Visit Tree       ***
+
+          // Check if xi is in the window centered about yk_ptr
+          // If so - use it to compute y(k+1)
+          diff = 0;
+          j = 0;
+          s = 0;
+          while ( ( diff < 1.0 ) && ( j < kp ) ) // Partial Distortion Search (PDS)
+          {
+
+            // test each sub-dimension independently
+            diff  = 0;
+            for ( k = 0; k < P[j]; k++ )
+            {
+              el = ( c_t->x[s+k] - yk_ptr[s+k] ) / h[j];
+              diff += el * el;
+            }
+
+            s += P[j];                        // next subspace
+            j++;
+
+          }
+
+          if ( diff < 1.0 )
+          {
+            wsum += 1;
+            for ( j = 0; j < N; j++ )
+              Mh_ptr[j] += c_t->x[j];
+          }
+
+        }
+        if ( ( c_t->x[c_d] < range[2*c_d+1] ) && ( ( c_t->right ) != NULL ) )
+        {
+          c_t = c_t->right;
+          c_d = ( c_d + 1 ) % N;
+          actionType = 0;
+        } else
+        {
+          actionType = 2;
+        }
+        break;
+      case 2: // backright
+        c_d = ( c_d + N - 1 ) % N;
+
+        if ( c_t->parent == NULL )
+        {
+          c_t = NULL;
+          break;
+        }
+
+        if ( c_t->parent->left == c_t )
+          actionType = 1;
+        else
+          actionType = 2;
+        c_t = c_t->parent;
+        break;
+    }
+  }
+}
+
+/*******************************************************/
+/*General Search                                       */
+/*******************************************************/
+/*Searches the input data using a kd tree, performs the*/
+/*sum on the data within the Hypercube defined by the  */
+/*tree using a general kernel.                         */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - gt is a possibly NULL pointer to a kd tree   */
+/*      - Mh_ptr is a pointer to the mean shift vector */
+/*        being calculated                             */
+/*      - yk_ptr is a pointer to the current window    */
+/*        center location                              */
+/*      - gd is the depth of the current subtree       */
+/*Post:                                                */
+/*      - the mean of the points within the Hypercube  */
+/*        of the kd tree is computed using a general   */
+/*        kernel                                       */
+/*******************************************************/
+
+void MeanShift::generalSearch ( tree *gt, int gd, double *Mh_ptr, double *yk_ptr )
+{
+  tree* c_t;
+  int c_d;
+  int i;
+  int actionType;
+
+  c_t = gt;
+  c_d = gd;
+  actionType = 0;
+
+  double el, diff, u, tw, y0, y1;
+  int k, j, s, x0, x1;
+
+  while ( c_t != NULL )
+  {
+    switch ( actionType ) {
+      case 0: // forward
+        if ( ( c_t->x[c_d] > range[2*c_d] ) && ( ( c_t->left ) != NULL ) )
+        {
+          c_t = c_t->left;
+          c_d = ( c_d + 1 ) % N;
+        } else
+        {
+          actionType = 1;
+        }
+        break;
+      case 1: // backleft
+
+        for ( i = 0; i < N; i++ )
+        {
+          if ( ( c_t->x[i] < range[2*i] ) || ( c_t->x[i] > range[2*i+1] ) )
+            break;
+        }
+
+        if ( i == N )
+        {
+
+          // ***      Visit Tree      ***
+
+          // Check if xi is in the window centered about yk_ptr
+          // If so - use it to compute y(k+1)
+          s = 0;
+          for ( j = 0; j < kp; j++ )
+          {
+
+            // test each sub-dimension independently
+            diff  = 0;
+            for ( k = 0; k < P[j]; k++ )
+            {
+              el = ( c_t->x[s+k] - yk_ptr[s+k] ) / h[j];
+              diff += uv[s+k] = el * el;    // Update uv and diff
+              if ( diff >= offset[j] )      // Partial Distortion Search (PDS)
+                break;
+            }
+
+            if ( diff >= offset[j] )          // PDS
+              break;
+
+            s += P[j];                        // next subspace
+
+          }
+
+          // j == kp indicates that all subspaces passed the test:
+          // the data point is within the search window
+          if ( j == kp ) j--;
+          if ( diff < offset[j] )
+          {
+
+            // Initialize total weight to 1
+            tw = 1;
+
+            // Calculate weight factor using weight function
+            // lookup tables and uv
+            s = 0;
+            for ( j = 0; j < kp; j++ )
+            {
+              if ( kernel[j] ) // not uniform kernel
+              {
+                // Compute u[i]
+                u = 0;
+                for ( k = 0; k < P[j]; k++ )
+                  u += uv[s+k];
+
+                // Accumulate tw using calculated u
+                // and weight function lookup table
+
+                // Linear interpolate values given by
+                // lookup table
+
+                // Calculate x0 and x1, the points surounding
+                // u
+                x0 = ( int ) ( u / increment[j] );
+                x1 = x0 + 1;
+
+                // Get y0 and y1 from the lookup table
+                y0 = w[j][x0];
+                y1 = w[j][x1];
+
+                // Accumulate tw using linear interpolation
+                tw *= ( ( ( double ) ( x1 ) * increment[j] - u ) * y0 + ( u - ( double ) ( x0 ) * increment[j] ) * y1 ) / ( double ) ( x1 * increment[j] - x0 * increment[j] );
+
+              }
+              s += P[j];                               // next subspace
+            }
+
+            // Perform weighted sum using xi
+            for ( j = 0; j < N; j++ )
+              Mh_ptr[j] += tw * c_t->x[j];
+
+            // Increment wsum by tw
+            wsum += tw;
+
+          }
+        }
+        if ( ( c_t->x[c_d] < range[2*c_d+1] ) && ( ( c_t->right ) != NULL ) )
+        {
+          c_t = c_t->right;
+          c_d = ( c_d + 1 ) % N;
+          actionType = 0;
+        } else
+        {
+          actionType = 2;
+        }
+        break;
+      case 2: // backright
+        c_d = ( c_d + N - 1 ) % N;
+
+        if ( c_t->parent == NULL )
+        {
+          c_t = NULL;
+          break;
+        }
+
+        if ( c_t->parent->left == c_t )
+          actionType = 1;
+        else
+          actionType = 2;
+        c_t = c_t->parent;
+        break;
+    }
+  }
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/***  Mean Shift: Using Lattice ***/
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Uniform Lattice Search                               */
+/*******************************************************/
+/*Performs search on data set for all points lying     */
+/*within the search window defined using a uniform     */
+/*kernel. Their point-wise sum and count is computed   */
+/*and returned.                                        */
+/*                                                     */
+/*NOTE: This method is the only method in the          */
+/*      MeanShift class that uses the weight           */
+/*      map asside from optUniformLSearch.             */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - Mh_ptr is a length N array of doubles        */
+/*      - yk_ptr is a length N array of doubles        */
+/*      - Mh_ptr is the sum of the data points found   */
+/*        within search window having center yk_ptr    */
+/*Post:                                                */
+/*      - a search on the data set using the lattice   */
+/*        has been performed, and all points found to  */
+/*        lie within the search window defined using   */
+/*        a uniform kernel are summed and counted.     */
+/*      - their point wise sum is pointed to by Mh_ptr */
+/*        and their count is stored by wsum.           */
+/*******************************************************/
+
+void MeanShift::uniformLSearch ( double *Mh_ptr, double *yk_ptr )
+{
+
+  //Declare variables
+  register int i, j, k;
+  int    s, p, dataPoint, lN;
+  double   diff, el, dx, dy, tx, weight;
+
+  //Define lattice data dimension...
+  lN = N + 2;
+
+  //Define bounds of lattice...
+
+  //the lattice is a 2dimensional subspace whose
+  //search window bandwidth is specified by
+  //h[0]:
+  tx = yk_ptr[0] - h[0] + DELTA + 0.99;
+  if ( tx < 0 )
+    LowerBoundX = 0;
+  else
+    LowerBoundX = ( int ) tx;
+  tx = yk_ptr[1] - h[0] + DELTA + 0.99;
+  if ( tx < 0 )
+    LowerBoundY = 0;
+  else
+    LowerBoundY = ( int ) tx;
+  tx = yk_ptr[0] + h[0] - DELTA;
+  if ( tx >= width )
+    UpperBoundX = width - 1;
+  else
+    UpperBoundX = ( int ) tx;
+  tx = yk_ptr[1] + h[0] - DELTA;
+  if ( tx >= height )
+    UpperBoundY = height - 1;
+  else
+    UpperBoundY = ( int ) tx;
+
+  //Perform search using lattice
+  for ( i = LowerBoundY; i <= UpperBoundY; i++ )
+    for ( j = LowerBoundX; j <= UpperBoundX; j++ )
+    {
+
+      //get index into data array
+      dataPoint = N * ( i * width + j );
+
+      //Determine if inside search window
+      k  = 1;
+      s  = 0;
+      dx      = j - yk_ptr[0];
+      dy      = i - yk_ptr[1];
+      diff = ( dx * dx + dy * dy ) / ( h[0] * h[0] );
+      while ( ( diff < 1.0 ) && ( k != kp ) ) // Partial Distortion Search
+      {
+        //Calculate distance squared of sub-space s
+        diff = 0;
+        for ( p = 0; p < P[k]; p++ )
+        {
+          el    = ( data[dataPoint+p+s] - yk_ptr[p+s+2] ) / h[k];
+          if ( ( !p ) && ( yk_ptr[2] > 80 ) )
+            diff += 4 * el * el;
+          else
+            diff += el * el;
+        }
+
+        //next subspace
+        s += P[k];
+        k++;
+      }
+
+      //if its inside search window perform sum and count
+      if ( diff < 1.0 )
+      {
+        weight = 1 - weightMap[i*width+j];
+        Mh_ptr[0] += weight * j;
+        Mh_ptr[1] += weight * i;
+        for ( k = 2; k < lN; k++ )
+          Mh_ptr[k] += weight * data[dataPoint+k-2];
+        wsum += weight;
+      }
+      //done.
+    }
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Optimized Uniform Latice Search                      */
+/*******************************************************/
+/*Performs search on data set for all points lying     */
+/*within the search window defined using a uniform     */
+/*kernel. Their point-wise sum and count is computed   */
+/*and returned. Also the points that lie within the    */
+/*window are stored into the basin of attraction stru- */
+/*cture used by the optimized mean shift algorithms.   */
+/*                                                     */
+/*NOTE: This method is the only method in the          */
+/*      MeanShift class that uses the weight           */
+/*      map asside from uniformLSearch.                */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - Mh_ptr is a length N array of doubles        */
+/*      - yk_ptr is a length N array of doubles        */
+/*      - Mh_ptr is the sum of the data points found   */
+/*        within search window having center yk_ptr    */
+/*Post:                                                */
+/*      - a search on the data set using the latice    */
+/*        has been performed, and all points found to  */
+/*        lie within the search window defined using   */
+/*        a uniform kernel are summed and counted.     */
+/*      - their point wise sum is pointed to by Mh_ptr */
+/*        and their count is stored by wsum.           */
+/*      - the data points lying within h of of yk_ptr  */
+/*        have been stored into the basin of attract-  */
+/*        ion data structure.                          */
+/*******************************************************/
+
+void MeanShift::optUniformLSearch ( double *Mh_ptr, double *yk_ptr )
+{
+
+  //Declare variables
+  register int i, j, k;
+  int    s, p, dataPoint, pointIndx, lN;
+  double   diff, el, dx, dy, tx, weight;
+
+  //Define latice data dimension...
+  lN = N + 2;
+
+  //Define bounds of latice...
+
+  //the latice is a 2dimensional subspace whose
+  //search window bandwidth is specified by
+  //h[0]:
+  tx = yk_ptr[0] - h[0] + DELTA + 0.99;
+  if ( tx < 0 )
+    LowerBoundX = 0;
+  else
+    LowerBoundX = ( int ) tx;
+  tx = yk_ptr[1] - h[0] + DELTA + 0.99;
+  if ( tx < 0 )
+    LowerBoundY = 0;
+  else
+    LowerBoundY = ( int ) tx;
+  tx = yk_ptr[0] + h[0] - DELTA;
+  if ( tx >= width )
+    UpperBoundX = width - 1;
+  else
+    UpperBoundX = ( int ) tx;
+  tx = yk_ptr[1] + h[0] - DELTA;
+  if ( tx >= height )
+    UpperBoundY = height - 1;
+  else
+    UpperBoundY = ( int ) tx;
+
+  //Perform search using latice
+  for ( i = LowerBoundY; i <= UpperBoundY; i++ )
+    for ( j = LowerBoundX; j <= UpperBoundX; j++ )
+    {
+
+      //get index into data array
+      pointIndx = i * width + j;
+      dataPoint = N * ( pointIndx );
+
+      //Determine if inside search window
+      k  = 1;
+      s  = 0;
+      dx      = j - yk_ptr[0];
+      dy      = i - yk_ptr[1];
+      diff = ( dx * dx + dy * dy ) / ( h[0] * h[0] );
+      while ( ( diff < 1.0 ) && ( k != kp ) ) // Partial Distortion Search
+      {
+        //Calculate distance squared of sub-space s
+        diff = 0;
+        for ( p = 0; p < P[k]; p++ )
+        {
+          el    = ( data[dataPoint+p+s] - yk_ptr[p+s+2] ) / h[k];
+          if ( ( !p ) && ( yk_ptr[2] > 80 ) )
+            diff += 4 * el * el;
+          else
+            diff += el * el;
+        }
+
+        //next subspace
+        s += P[k];
+        k++;
+      }
+
+      //if its inside search window perform sum and count
+      if ( diff < 1.0 )
+      {
+        weight = 1 - weightMap[i*width+j];
+        Mh_ptr[0] += weight * j;
+        Mh_ptr[1] += weight * i;
+        for ( k = 2; k < lN; k++ )
+          Mh_ptr[k] += weight * data[dataPoint+k-2];
+        wsum += weight;
+
+        //set basin of attraction mode table
+        if ( diff < 0.5 )
+        {
+          if ( modeTable[pointIndx] == 0 )
+          {
+            pointList[pointCount++] = pointIndx;
+            modeTable[pointIndx] = 2;
+          }
+        }
+
+      }
+
+      //done.
+
+    }
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*General Lattice Search                               */
+/*******************************************************/
+/*Performs search on data set for all points lying     */
+/*within the search window defined using a general     */
+/*kernel. Their point-wise sum and count is computed   */
+/*and returned.                                        */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - Mh_ptr is a length N array of doubles        */
+/*      - yk_ptr is a length N array of doubles        */
+/*      - Mh_ptr is the sum of the data points found   */
+/*        within search window having center yk_ptr    */
+/*Post:                                                */
+/*      - a search on the data set using the lattice   */
+/*        has been performed, and all points found to  */
+/*        lie within the search window defined using   */
+/*        a general kernel are summed and counted      */
+/*      - their point wise sum is pointed to by Mh_ptr */
+/*        and their count is stored by wsum            */
+/*******************************************************/
+
+void MeanShift::generalLSearch ( double *Mh_ptr, double *yk_ptr )
+{
+
+  //Declare variables
+  register int i, j, k;
+  int    s, p, dataPoint, lN, x0, x1;
+  double   diff, el, dx, dy, tw, u, y0, y1, tx;
+
+  //Define lattice data dimension...
+  lN = N + 2;
+
+  //Define bounds of lattice...
+
+  //the lattice is a 2dimensional subspace whose
+  //search window bandwidth is specified by
+  //h[0]:
+  tx = yk_ptr[0] - h[0] + DELTA + 0.99;
+  if ( tx < 0 )
+    LowerBoundX = 0;
+  else
+    LowerBoundX = ( int ) tx;
+  tx = yk_ptr[1] - h[0] + DELTA + 0.99;
+  if ( tx < 0 )
+    LowerBoundY = 0;
+  else
+    LowerBoundY = ( int ) tx;
+  tx = yk_ptr[0] + h[0] - DELTA;
+  if ( tx >= width )
+    UpperBoundX = width - 1;
+  else
+    UpperBoundX = ( int ) tx;
+  tx = yk_ptr[1] + h[0] - DELTA;
+  if ( tx >= height )
+    UpperBoundY = height - 1;
+  else
+    UpperBoundY = ( int ) tx;
+
+  //Perform search using lattice
+  for ( i = LowerBoundY; i <= UpperBoundY; i++ )
+    for ( j = LowerBoundX; j <= UpperBoundX; j++ )
+    {
+
+      //get index into data array
+      dataPoint = N * ( i * width + j );
+
+      //Determine if inside search window
+      k  = 1;
+      s  = 0;
+      dx      = j - yk_ptr[0];
+      dy      = i - yk_ptr[1];
+      uv[0] = ( dx * dx ) / ( h[0] * h[0] );
+      uv[1] = ( dy * dy ) / ( h[0] * h[0] );
+      diff = uv[0] + uv[1];
+      while ( ( diff < offset[k-1] ) && ( k != kp ) ) // Partial Distortion Search
+      {
+        //Calculate distance squared of sub-space s
+        diff = 0;
+        for ( p = 0; p < P[k]; p++ )
+        {
+          el    = ( data[dataPoint+p+s] - yk_ptr[p+s+2] ) / h[k];
+          diff += uv[p+s+2] = el * el;
+        }
+
+        //next subspace
+        s += P[k];
+        k++;
+      }
+
+      //if its inside search window perform weighted sum and count
+      if ( diff < offset[k-1] )
+      {
+
+        // Initialize total weight to 1
+        tw = 1;
+
+        // Calculate weight factor using weight function
+        // lookup tables and uv
+        s = 0;
+        for ( k = 0; k < kp; k++ )
+        {
+          if ( kernel[k] ) // not uniform kernel
+          {
+            // Compute u[i]
+            u = 0;
+            for ( p = 0; p < P[k]; p++ )
+              u += uv[s+p];
+
+            // Accumulate tw using calculated u
+            // and weight function lookup table
+
+            // Linear interpolate values given by
+            // lookup table
+
+            // Calculate x0 and x1, the points surounding
+            // u
+            x0 = ( int ) ( u / increment[k] );
+            x1 = x0 + 1;
+
+            // Get y0 and y1 from the lookup table
+            y0 = w[k][x0];
+            y1 = w[k][x1];
+
+            // Accumulate tw using linear interpolation
+            tw *= ( ( ( double ) ( x1 ) * increment[k] - u ) * y0 + ( u - ( double ) ( x0 ) * increment[k] ) * y1 ) / ( double ) ( x1 * increment[k] - x0 * increment[k] );
+
+          }
+          s += P[k];                               // next subspace
+        }
+
+        // Perform weighted sum using xi
+        Mh_ptr[0] += tw * j;
+        Mh_ptr[1] += tw * i;
+        for ( k = 0; k < N; k++ )
+          Mh_ptr[k+2] += tw * data[dataPoint+k];
+
+        // Increment wsum by tw
+        wsum += tw;
+
+      }
+
+      //done.
+
+    }
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Optimized General Lattice Search                     */
+/*******************************************************/
+/*Performs search on data set for all points lying     */
+/*within the search window defined using a general     */
+/*kernel. Their point-wise sum and count is computed   */
+/*and returned. Also the points that lie within the    */
+/*window are stored into the basin of attraction stru- */
+/*cture used by the optimized mean shift algorithms.   */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - Mh_ptr is a length N array of doubles        */
+/*      - yk_ptr is a length N array of doubles        */
+/*      - Mh_ptr is the sum of the data points found   */
+/*        within search window having center yk_ptr    */
+/*Post:                                                */
+/*      - a search on the data set using the lattice   */
+/*        has been performed, and all points found to  */
+/*        lie within the search window defined using   */
+/*        a general kernel are summed and counted      */
+/*      - their point wise sum is pointed to by Mh_ptr */
+/*        and their count is stored by wsum            */
+/*      - the data points lying within h*offset of     */
+/*        yk_ptr have been stored into the basin of    */
+/*        attraction data structure.                   */
+/*******************************************************/
+
+void MeanShift::optGeneralLSearch ( double *Mh_ptr, double *yk_ptr )
+{
+
+  //Declare variables
+  register int i, j, k;
+  int    s, p, dataPoint, pointIndx, lN, x0, x1;
+  double   diff, el, dx, dy, tw, u, y0, y1, tx;
+
+  //Define lattice data dimension...
+  lN = N + 2;
+
+  //Define bounds of lattice...
+
+  //the lattice is a 2dimensional subspace whose
+  //search window bandwidth is specified by
+  //h[0]:
+  tx = yk_ptr[0] - h[0] + DELTA + 0.99;
+  if ( tx < 0 )
+    LowerBoundX = 0;
+  else
+    LowerBoundX = ( int ) tx;
+  tx = yk_ptr[1] - h[0] + DELTA + 0.99;
+  if ( tx < 0 )
+    LowerBoundY = 0;
+  else
+    LowerBoundY = ( int ) tx;
+  tx = yk_ptr[0] + h[0] - DELTA;
+  if ( tx >= width )
+    UpperBoundX = width - 1;
+  else
+    UpperBoundX = ( int ) tx;
+  tx = yk_ptr[1] + h[0] - DELTA;
+  if ( tx >= height )
+    UpperBoundY = height - 1;
+  else
+    UpperBoundY = ( int ) tx;
+
+  //Perform search using lattice
+  for ( i = LowerBoundY; i <= UpperBoundY; i++ )
+    for ( j = LowerBoundX; j <= UpperBoundX; j++ )
+    {
+
+      //get index into data array
+      pointIndx = i * width + j;
+      dataPoint = N * ( i * width + j );
+
+      //Determine if inside search window
+      k  = 1;
+      s  = 0;
+      dx      = j - yk_ptr[0];
+      dy      = i - yk_ptr[1];
+      uv[0] = ( dx * dx ) / ( h[0] * h[0] );
+      uv[1] = ( dy * dy ) / ( h[0] * h[0] );
+      diff = uv[0] + uv[1];
+      while ( ( diff < offset[k-1] ) && ( k != kp ) ) // Partial Distortion Search
+      {
+        //Calculate distance squared of sub-space s
+        diff = 0;
+        for ( p = 0; p < P[k]; p++ )
+        {
+          el    = ( data[dataPoint+p+s] - yk_ptr[p+s+2] ) / h[k];
+          diff += uv[p+s+2] = el * el;
+        }
+
+        //next subspace
+        s += P[k];
+        k++;
+      }
+
+      //if its inside search window perform weighted sum and count
+      if ( diff < offset[k-1] )
+      {
+
+        // Initialize total weight to 1
+        tw = 1;
+
+        // Calculate weight factor using weight function
+        // lookup tables and uv
+        s = 0;
+        for ( k = 0; k < kp; k++ )
+        {
+          if ( kernel[k] ) // not uniform kernel
+          {
+            // Compute u[i]
+            u = 0;
+            for ( p = 0; p < P[k]; p++ )
+              u += uv[s+p];
+
+            // Accumulate tw using calculated u
+            // and weight function lookup table
+
+            // Linear interpolate values given by
+            // lookup table
+
+            // Calculate x0 and x1, the points surounding
+            // u
+            x0 = ( int ) ( u / increment[k] );
+            x1 = x0 + 1;
+
+            // Get y0 and y1 from the lookup table
+            y0 = w[k][x0];
+            y1 = w[k][x1];
+
+            // Accumulate tw using linear interpolation
+            tw *= ( ( ( double ) ( x1 ) * increment[k] - u ) * y0 + ( u - ( double ) ( x0 ) * increment[k] ) * y1 ) / ( double ) ( x1 * increment[k] - x0 * increment[k] );
+
+          }
+          s += P[k];                               // next subspace
+        }
+
+        // Perform weighted sum using xi
+        Mh_ptr[0] += tw * j;
+        Mh_ptr[1] += tw * i;
+        for ( k = 0; k < N; k++ )
+          Mh_ptr[k+2] += tw * data[dataPoint+k];
+
+        // Increment wsum by tw
+        wsum += tw;
+
+        //set basin of attraction mode table
+        if ( modeTable[pointIndx] == 0 )
+        {
+          pointList[pointCount++] = pointIndx;
+          modeTable[pointIndx] = 2;
+        }
+
+      }
+
+      //done.
+
+    }
+
+  //done.
+  return;
+
+}
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ END OF CLASS DEFINITION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+

+ 926 - 0
edisonSegm/ms.h

@@ -0,0 +1,926 @@
+/*******************************************************
+
+                 Mean Shift Analysis Library
+ =============================================
+
+ The mean shift library is a collection of routines
+ that use the mean shift algorithm. Using this algorithm,
+ the necessary output will be generated needed
+ to analyze a given input set of data.
+
+  MeanShift Base Class:
+  ====================
+
+ The mean shift library of routines is realized
+ via the creation of a MeanShift base class. This class
+ provides a mechanism for calculating the mean shift vector
+ at a specified data point, using an arbitrary N-dimensional
+ data set, and a user-defined kernel.
+
+ For image processing the mean shift base class also allows
+ for the definition of a data set that is on a two-dimensional
+ lattice. The amount of time needed to compute the mean shift
+ vector using such a data set is much less than that of an
+ arbitrary one. Because images usually contain many data points,
+ defining the image input data points as being on a lattice
+ greatly improves computation time and makes algorithms such
+ as image filtering practical.
+
+ The MeanShift class prototype is provided below. Its
+ definition is provided in 'ms.cc'.
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+          space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+
+#ifndef MS_H
+#define MS_H
+
+//Included needed libraries
+
+//Include type definitions
+#include "tdef.h"
+
+//include mean shift system used
+//for function timing and system output
+#include "msSys.h"
+
+//Include Debugging Constant
+//#define DEBUG
+
+//Define Prompt - Prompts user on progress of Mean Shift algorithm
+#undef PROMPT
+
+//Define Show Progress - Prompts user on percent complete of a given
+//                       mean shift algorithm
+#undef SHOW_PROGRESS
+
+//Define Progress Rate - Indicates the number of convergences before
+//       checking progress
+#define PROGRESS_RATE 100
+
+// Define Macros
+#define SWAP(d_a, d_b) temp=(d_a);(d_a)=(d_b);(d_b)=temp;
+
+// Define Structures
+
+//k-Dimensional Binary Search Tree
+struct tree {
+  float *x;
+  tree  *right;
+  tree  *left;
+  tree  *parent;
+};
+
+// User Defined Weight Function
+struct userWeightFunct {
+
+  double   *w;
+  double   halfWindow;
+  int    sampleNumber;
+  int    subspace;
+  userWeightFunct *next;
+
+};
+
+//Define class state structure
+struct ClassStateStruct {
+  bool KERNEL_DEFINED;
+  bool INPUT_DEFINED;
+  bool LATTICE_DEFINED;
+  bool OUTPUT_DEFINED;
+};
+
+// Define Constants
+
+// Threshold
+const double EPSILON2  = 0.01;   // define threshold (approx. Value of Mh at a peak or plateau)
+const double MU    = 0.05;  // define threshold required that window is near convergence
+const double TC_DIST_FACTOR = 0.5;  // cluster search windows near convergence that are a distance
+// h[i]*TC_DIST_FACTOR of one another (transitive closure)
+const double SQ_TC_DFACTOR = 0.0625; // (TC_DIST_FACTOR)^2
+const int  LIMIT           = 100;  // define max. # of iterations to find mode
+
+// Gaussian Lookup Table
+const int  GAUSS_NUM_ELS   = 16;  // take 16 samples of exp(-u/2)
+const double GAUSS_LIMIT     = 2.9;  // GAUSS_LIMIT     = c
+const double GAUSS_INCREMENT = GAUSS_LIMIT * GAUSS_LIMIT / GAUSS_NUM_ELS;
+// GAUSS_INCREMENT = (c^2)/(# of samples)
+
+// Numerical Analysis
+const double DELTA           = 0.00001; // used for floating point to integer conversion
+
+//MeanShift Prototype
+class MeanShift {
+
+  public:
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /* Class Constructor and Destructor */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    MeanShift( void ); //Default Constructor
+    ~MeanShift( void ); //Class Destructor
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /* Creation/Initialization of Mean Shift Kernel */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|      *  Define Kernel  *                |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   Uploads a custom kernel into the private data    |//
+    //|   members of the mean shift class. This kernel is  |//
+    //|   used by the mean shift class to perform mean     |//
+    //|   shift.                                           |//
+    //|                                                    |//
+    //|   In order to create a valid kernel the following  |//
+    //|   argumens must be provided this method:           |//
+    //|                                                    |//
+    //|   <* kernel *>                                     |//
+    //|   A one dimensional array of type kernelType used  |//
+    //|   to specify the kernel type (Uniform, Gaussian,   |//
+    //|   or User Defined) of a given subspace of the input|//
+    //|   set. Entry i of kernel correlates to the i-th    |//
+    //|   subspace of the input data set.                  |//
+    //|                                                    |//
+    //|   <* h *>                                          |//
+    //|   A one dimensional array of floating point numb-  |//
+    //|   ers that are used to normalize the input data    |//
+    //|   set, each bandwidth specifying the relative imp- |//
+    //|   ortance of a subspace of the input data set.     |//
+    //|                                                    |//
+    //|   <* kp *>                                         |//
+    //|   An integer that specifies the number of sub-     |//
+    //|   contained by the input data set. Both P and h    |//
+    //|   therefore consist of kp entries.                 |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Usage:                   |//
+    //|   ======                   |//
+    //|  DefineKernel(kernel, h, P, kp)               |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void  DefineKernel(kernelType*, float*, int*, int);
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|               * Add Weight Function *              |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   Each subspace specified as User Defined is un-   |//
+    //|   quely defined by a correlating weight function   |//
+    //|   which is user defined.                           |//
+    //|                                                    |//
+    //|   A weight function w(u) exhibits the following    |//
+    //|   properties:                                      |//
+    //|                                                    |//
+    //|   (1) w(u) = w(-u)                                 |//
+    //|   (2) u = ((x_i-y_k)^2)/(h^2) (see docs)           |//
+    //|   (3) w(u) = 0, for |u| >= halfWindow              |//
+    //|                                                    |//
+    //|   To add a weight function to the mean shift class |//
+    //|   the following must be specified:                 |//
+    //|                                                    |//
+    //|   <* g() *>                                        |//
+    //|   A pointer the weight function w(u) exhibiting    |//
+    //|   the above properties.                            |//
+    //|                                                    |//
+    //|   <* halfWindow *>                                 |//
+    //|   A floating point number specifying where w(u)    |//
+    //|   exists (is non zero). [See Property 3 Above]     |//
+    //|                                                    |//
+    //|   <* sampleNumber *>                               |//
+    //|   An integer used to specify the number of samples |//
+    //|   used to describe w(u). Linear interpolation is   |//
+    //|   used during the mean shift calculation using the |//
+    //|   the samples of w(u) to determine the value of w  |//
+    //|   at a location |u| < halfWindow.                  |//
+    //|                                                    |//
+    //|   <* subspace *>                                   |//
+    //|   An integer specifying which kernel w(u) defines. |//
+    //|                                                    |//
+    //|   Weight functions are accounted for every time    |//
+    //|   a new kernel is created.                         |//
+    //|                                                    |//
+    //|   If a weight function is added to non-existing    |//
+    //|   subspace of the input data set  (example: the    |//
+    //|   input data set containes 3 subspaces and this    |//
+    //|   method is given subspace = 4) then the weight    |//
+    //|   defintion will simply be ignored by the mean     |//
+    //|   shift class.                                     |//
+    //|                                                    |//
+    //|   If a subspace is declared as kernel type User    |//
+    //|   Defined and a weight function is not defined     |//
+    //|   for that subspace a fatal error will occur.      |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Usage:                   |//
+    //|   ======                   |//
+    //|   AddWeightFunction(g(u)        , halfWindow,      |//
+    //|                     sampleNumber, subspace);       |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void AddWeightFunction(double g(double), float, int, int);
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|           *  Clear Weight Functions  *             |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   Removes all user defined weight functions added  |//
+    //|   using method AddWeightFunction() from the        |//
+    //|   private data members of the mean shift class.    |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void ClearWeightFunctions( void );
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /* Input Data Set Declaration */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|               * Define Input *                     |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   Uploads a one dimensional array containing L     |//
+    //|   N-dimensional data points into the mean shift    |//
+    //|   class.                                           |//
+    //|                                                    |//
+    //|   An input data set is specified by:               |//
+    //|                                                    |//
+    //|   <* x *>                                          |//
+    //|   A pointer to a floating point array.             |//
+    //|                                                    |//
+    //|   <* L *>                                          |//
+    //|   The number of data points stored by x.           |//
+    //|                                                    |//
+    //|   <* N *>                                          |//
+    //|   The dimension of the data points stored by x.    |//
+    //|                                                    |//
+    //|   The input x has the following format:            |//
+    //|                                                    |//
+    //|   x = <x11, x12,..., x1N,..., xL1, xL2,..., xLN>   |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Usage:                   |//
+    //|   ======                   |//
+    //|       DefineInput(x, L, N)                         |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void DefineInput(float*, int, int);
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|            * Define Lattice Input *                |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   Use this method to specify define an input data  |//
+    //|   set defined on a lattice.                        |//
+    //|                                                    |//
+    //|   The arguments of this method are:                |//
+    //|                                                    |//
+    //|   <* x *>                                          |//
+    //|   A pointer to a floating point array containing   |//
+    //|   height*width, N-dimensional data points.         |//
+    //|                                                    |//
+    //|   <* height *>                                     |//
+    //|   An integer specifying the height of the lattice. |//
+    //|                                                    |//
+    //|   <* width *>                                      |//
+    //|   An integer specifying the width of the lattice.  |//
+    //|                                                    |//
+    //|   <* N *>                                          |//
+    //|   The dimension of the data points stored by x.    |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Usage:                   |//
+    //|   ======                   |//
+    //|       DefineLInput(x, height, width, N)            |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void DefineLInput(float*, int, int, int);
+
+    /*/\/\/\/\/\/\/\/\/\/\/\*/
+    /*  Lattice Weight Map  */
+    /*\/\/\/\/\/\/\/\/\/\/\/*/
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|     * Set Lattice Weight Map *             |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   Uploads weight map specifying for each data      |//
+    //|   point a value used to weight the uniform kernel  |//
+    //|   when computing mean shift.                       |//
+    //|                                                    |//
+    //|   The arguments to this method are:                |//
+    //|                                                    |//
+    //|   <* weightMap *>                                  |//
+    //|   A floating point array of size L specifying for  |//
+    //|   each data point a weight.                        |//
+    //|                                                    |//
+    //|   Note: DefineLInput must be called prior to call- |//
+    //|         ing this method. DefineLInput is used to   |//
+    //|         define the dimensions of the input data    |//
+    //|         set.                                       |//
+    //|                                                    |//
+    //|                                                    |//
+    //|  The weight map is used to weight the uniform      |//
+    //|  kernel used to computing meanshift on a data      |//
+    //|  point situated on a lattice. Alternatively, a     |//
+    //|  weight function may defined, however, if speed    |//
+    //|  is an issue, the lattice may be exploited to      |//
+    //|  result in a faster implementation of a weighted   |//
+    //|  kernel.                                           |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Usage:                   |//
+    //|   ======                   |//
+    //|  SetLatticeWeightMap(weightMap)               |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void SetLatticeWeightMap(float*);
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|   * Remove Lattice Weight Map *            |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   Removes lattice weight map. An error is NOT      |//
+    //|   flagged if a weight map was not defined prior    |//
+    //|   to calling this method.                          |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Usage:                   |//
+    //|   ======                   |//
+    //|  RemoveLatticeWeightMap(weightMap)            |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void RemoveLatticeWeightMap(void);
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /* Mean Shift Operations  */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|               *  Mean Shift Vector  *              |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   If a kernel is created and input is uploaded,    |//
+    //|   this method calcualtes the mean shift vector,    |//
+    //|   Mh, at specific data point yk.                   |//
+    //|                                                    |//
+    //|   The arguments of this method are:                |//
+    //|                                                    |//
+    //|   <* Mh *>                                         |//
+    //|   An array of N doubles storing the N dimensional  |//
+    //|   mean shift vector.                               |//
+    //|                                                    |//
+    //|   <* yk *>                                         |//
+    //|   An array of N doubles storing the N dimensional  |//
+    //|   data point where the mean shift vector is to be  |//
+    //|   calculate.                                       |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Usage:                   |//
+    //|   ======                   |//
+    //|       msVector(Mh, yk)                             |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void msVector(double*, double*);
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|          *  Lattice Mean Shift Vector  *           |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   If a kernel is created and input is uploaded,    |//
+    //|   this method calcualtes the mean shift vector,    |//
+    //|   Mh, at specific data point yk, assuming that the |//
+    //|   data set exhists on a height x width two dim-    |//
+    //|   ensional lattice.                                |//
+    //|                                                    |//
+    //|   The arguments of this method are:                |//
+    //|                                                    |//
+    //|   <* Mh *>                                         |//
+    //|   An array of N doubles storing the N dimensional  |//
+    //|   mean shift vector.                               |//
+    //|                                                    |//
+    //|   <* yk *>                                         |//
+    //|   An array of N doubles storing the N dimensional  |//
+    //|   data point where the mean shift vector is to be  |//
+    //|   calculate.                                       |//
+    //|                                                    |//
+    //|   The height and width of the lattice must be      |//
+    //|   specified using DefineLattice() method. If this  |//
+    //|   is not performed prior to calling this method a  |//
+    //|   fatal error will be flagged.                     |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Usage:                   |//
+    //|   ======                   |//
+    //|        latticeMSVector(Mh, yk)                     |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void latticeMSVector(double*, double*);
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|                 *  Find Mode  *                    |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   If a kernel is created and input is uploaded,    |//
+    //|   this method calcualtes the mode of a specified   |//
+    //|   data point yk.                                   |//
+    //|                                                    |//
+    //|   The arguments of this method are:                |//
+    //|                                                    |//
+    //|   <* mode *>                                       |//
+    //|   An array of N doubles storing the N dimensional  |//
+    //|   mode of yk.                                      |//
+    //|                                                    |//
+    //|   <* yk *>                                         |//
+    //|   An array of N doubles storing the N dimensional  |//
+    //|   data point where the mean shift vector is to be  |//
+    //|   calculate.                                       |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Usage:                   |//
+    //|   ======                   |//
+    //|       FindMode(mode, yk)                           |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void FindMode(double*, double*);
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Method Name:             |//
+    //|   ============             |//
+    //|              *  Find Lattice Mode  *               |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   If a kernel is created and input is uploaded,    |//
+    //|   this method calcualtes the mode of a specified   |//
+    //|   data point yk, assuming that the data set        |//
+    //|   exhists on a height x width two dimensional      |//
+    //|   lattice.                                         |//
+    //|                                                    |//
+    //|   The arguments of this method are:                |//
+    //|                                                    |//
+    //|   <* mode *>                                       |//
+    //|   An array of N doubles storing the N dimensional  |//
+    //|   mode of yk.                                      |//
+    //|                                                    |//
+    //|   <* yk *>                                         |//
+    //|   An array of N doubles storing the N dimensional  |//
+    //|   data point where the mean shift vector is to be  |//
+    //|   calculate.                                       |//
+    //|                                                    |//
+    //|   The height and width of the lattice must be      |//
+    //|   specified using DefineLattice() method. If this  |//
+    //|   is not performed prior to calling this method a  |//
+    //|   fatal error will be flagged.                     |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Usage:                   |//
+    //|   ======                   |//
+    //|       FindLMode(mode, yk)                          |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    void FindLMode(double*, double*);
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /*  Error Handler Mechanism */
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   ErrorMessage is an error message that is set by  |//
+    //|   a mean shift library class when an error occurs. |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    char   *ErrorMessage;
+
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+    //<--------------------------------------------------->|//
+    //|                                                    |//
+    //| Description:             |//
+    //| ============             |//
+    //|                                                    |//
+    //|   ErrorStatus indicates if an error has occured as |//
+    //|   a result of improper use of a mean shift library |//
+    //|   class method or because of insufficient resour-  |//
+    //|   ces. ErrorStatus is set to EL_ERROR (ErrorStatus |//
+    //|   = 1) if an error has occured. If no error occur- |//
+    //|   ed when calling a particular method ErrorStatus  |//
+    //|   is set to EL_OKAY (ErrorStatus = 0).             |//
+    //|                                                    |//
+    //<--------------------------------------------------->|//
+    //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+    ErrorLevel ErrorStatus;
+
+  protected:
+
+    //==========================
+    // *** Protected Methods ***
+    //==========================
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /* Mean Shift: Using kd-Tree  */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    /////////////////////////////////////////
+    // <<*>> Usage: MSVector(Mh, yk) <<*>> //
+    /////////////////////////////////////////
+
+    void MSVector      (double*, double*);               // Computes the mean shift vector at a specified
+    // window location yk in the data set x given
+    // the vector yk
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /*  Mean Shift: Using Lattice */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    ////////////////////////////////////////////////
+    // <<*>> Usage: LatticeMSVector(Mh, yk) <<*>> //
+    ////////////////////////////////////////////////
+
+    void LatticeMSVector     (double*, double*);   // Uses the lattice defined by DefineLattice to compute the
+    // mean shift vector at a specified window location yk
+
+    ///////////////////////////////////////////////////
+    // <<*>> Usage: OptLatticeMSVector(Mh, yk) <<*>> //
+    ///////////////////////////////////////////////////
+
+    void OptLatticeMSVector     (double*, double*);      // Uses the lattice defined by DefineLattice to compute the
+    // mean shift vector at a specified window location yk using
+    // the basin of attraction optimization for better performace
+    // during mean shift filtering - used by a derived class
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /* Kernel-Input Data Consistency  */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    /////////////////////////////////////////////////
+    // <<*>> Usage: classConsistencyCheck(N) <<*>> //
+    /////////////////////////////////////////////////
+
+    void classConsistencyCheck(int, bool);    // checks to see that a kernel is created and input defined, as
+    // well as the specified dimension of the data set matches that of
+    // the kernel, if not an error is flagged and the program is halted
+
+    /*/\/\/\/\/\/\/\/\/\/\/\*/
+    /* Class Error Handler  */
+    /*\/\/\/\/\/\/\/\/\/\/\/*/
+
+    /////////////////////////////////////////////////////
+    // <<*>> Usage: ErrorHandler(                <<*>> //
+    //   className, functName, errMessage)     //
+    /////////////////////////////////////////////////////
+
+    void ErrorHandler(char*, char*, char*);    // flags an error and halts the system
+
+
+    //===============================
+    // *** Protected Data Members ***
+    //===============================
+
+    //##########################################
+    //#########   MEAN SHIFT SYSTEM   ##########
+    //##########################################
+
+    msSystem  msSys;        // used for function timing and system output
+
+    //##########################################
+    //######### INPUT DATA PARAMETERS ##########
+    //##########################################
+
+    int    L, N, kp, *P;      // length, dimension, subspace number, and subspace dimensions
+
+
+    //##########################################
+    //######### INPUT DATA STORAGE    ##########
+    //##########################################
+
+    ////////Linear Storage (used by lattice and bst)////////
+    float   *data;        // memory allocated for data points stored by tree nodes
+    // when used by the lattice data structure data does not store
+    // the lattice information; format of data:
+    // data = <x11, x12, ..., x1N,...,xL1, xL2, ..., xLN>
+    // in the case of the lattice the i in data(i,j) corresponds
+
+    //##########################################
+    //######## LATTICE DATA STRUCTURE ##########
+    //##########################################
+
+    ////////Lattice Data Structure////////
+    int    height, width;      // Height and width of lattice
+
+    //##########################################
+    //######### KERNEL DATA STRUCTURE ##########
+    //##########################################
+
+    float   *h;         // bandwidth vector
+
+    float   *offset;       // defines bandwidth offset caused by the use of a Gaussian kernel
+    // (for example)
+
+    //##########################################
+    //#########  BASIN OF ATTRACTION  ##########
+    //##########################################
+
+    unsigned char *modeTable;       // Assigns a marking to each data point specifying whether
+    // or not it has been assigned a mode. These labels are:
+    // modeTable[i] = 0 - data point i is not associated with a mode
+    // modeTable[i] = 1 - data point i is associated with a mode
+    // modeTable[i] = 2 - data point i is associated with a mode
+    //                    however its mode is yet to be determined
+
+    int    *pointList;       // a list of data points that due to basin of attraction will
+    // converge to the same mode as the mode that mean shift is
+    // currently being applied to
+
+    int    pointCount;       // the number of points stored by the point list
+
+
+    //##########################################
+    //#########  WEIGHT MAP USED      ##########
+    //#########  WHEN COMPUTING MEAN  ##########
+    //#########  SHIFT ON A LATTICE   ##########
+    //##########################################
+
+    float   *weightMap;       // weight map that may be used to weight the kernel
+    // upon performing mean shift on a lattice
+
+    bool   weightMapDefined;     // used to indicate if a lattice weight map has been
+    // defined
+
+    //##########################################
+    //#######        CLASS STATE        ########
+    //##########################################
+
+    ClassStateStruct class_state;     //specifies the state of the class(i.e if data has been loaded into
+    //the class, if a kernel has been defined, etc.)
+
+  private:
+
+    //========================
+    // *** Private Methods ***
+    //========================
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /* Kernel Creation/Manipulation */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    void generateLookupTable ( void );                  // Generates Weight Function Lookup Table
+
+    void DestroyKernel       ( void );                  // Destroys mean shift kernel, re-initializes kernel
+
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /* Input Data Initialization/Destruction  */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    void CreateBST  ( void );      // Upload input into a kd-BST
+
+    void InitializeInput (float*);      // Allocates memory for and initializes the input data structure
+
+    void ResetInput  ( void );      // de-allocate memory for and re-initialize input data structure
+    // and mode structure
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /* k-dimensional Binary Search Tree */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    ////////Data Search Tree/////////
+    tree  *BuildKDTree (tree*,  int, int, tree* );       // Builds a kd tree given a subset of points initialized
+    // at depth 0 (dimension 0) (for Tree Structure)
+
+    void  QuickMedian (tree*, int, int, int );           // Finds the median tree in a forest of trees using
+    // dimension d, placing the median tree in the array of tree
+    // nodes at L/2, in which all trees to the left of the median tree
+    // have values less than that of the median tree in dimension d
+    // and all trees having values greater than that of the median tree
+    // in dimension d are placd to the right of this tree -
+    // This algorithm is used by BuildKDTree to construct a balanced tree
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /* Mean Shift: Using kd-Tree  */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    void uniformSearch (tree*, int, double*, double*);     // uses kdbst to perform range search on input data,
+    // computing the weighted sum of these points using
+    // a uniform kernel and storing the result into Mh
+    // (called by uniformMSVector)
+
+    void generalSearch (tree*, int, double*, double*);     // uses kdbst to perform range search on input data,
+    // computing the weighted sum of these points using
+    // a general kernel and storing the result into Mh
+    // (called by generalMSVector)
+
+    /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+    /*  Mean Shift: Using Lattice */
+    /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+    void uniformLSearch  (double *, double *);   // given a center location and mean shift vector, a lattice
+    // search is performed to compute the mean shift vector
+    // using a uniform kernel
+
+    void optUniformLSearch(double *, double *);   // given a center location and mean shift vector, a lattice
+    // search is performed to compute the mean shift vector
+    // using a uniform kernel and the basin of attraction
+    // optimization for better performance
+
+    void generalLSearch  (double *, double *);   // given a center location and mean shift vector, a lattice
+    // search is performed to compute the mean shift vector
+    // using a general kernel
+
+    void optGeneralLSearch(double *, double *);   // given a center location and mean shift vector, a lattice
+    // search is performed to compute the mean shift vector
+    // using a general kernel and the basin of attraction
+    // optimization for better performance
+
+
+    //=============================
+    // *** Private Data Members ***
+    //=============================
+
+    //##########################################
+    //######### KERNEL DATA STRUCTURE ##########
+    //##########################################
+
+    kernelType  *kernel;       // kernel types for each subspace S[i]
+
+    double   **w;        // weight function lookup table
+
+    double   *increment;       // increment used by weight hashing function
+
+    bool   uniformKernel;      // flag used to indicate if the kernel is uniform or not
+
+    userWeightFunct *head, *cur;      // user defined weight function linked list
+
+
+    //##########################################
+    //######### INPUT DATA STORAGE    ##########
+    //##########################################
+
+    ////////Range Searching on General Input Data Set////////
+    tree   *root;        // root of kdBST used to store input
+
+    tree   *forest;       // memory allocated for tree nodes
+
+    float   *range;        // range vector used to perform range search on kd tree, indexed
+    // by dimension of input - format:
+    // range = {Lower_Limit_1, Upper_Limit_1, ..., Lower_Limit_N, Upper_Limit_N}
+
+    //##########################################
+    //######### MEAN SHIFT PROCESSING ##########
+    //######### DATA STRUCTURES       ##########
+    //##########################################
+
+    double   *uv;        // stores normalized distance vector between
+    // yk and xi
+
+    double   wsum;        // sum of weights calculated at data points within the sphere
+
+    //##########################################
+    //######### LATTICE DATA STRUCTURE #########
+    //##########################################
+
+    ////////Lattice Data Structure////////
+    int    LowerBoundX, UpperBoundX;   // Upper and lower bounds for lattice search window
+    // in the x dimension
+
+    int    LowerBoundY, UpperBoundY;   // Upper and lower bounds for lattice search window
+    // in the y dimension
+
+};
+
+#endif

+ 4711 - 0
edisonSegm/msImageProcessor.cpp

@@ -0,0 +1,4711 @@
+/*******************************************************
+
+                 Mean Shift Analysis Library
+ =============================================
+
+
+ The mean shift library is a collection of routines
+ that use the mean shift algorithm. Using this algorithm,
+ the necessary output will be generated needed
+ to analyze a given input set of data.
+
+  Mean Shift Image Processor Class:
+  ================================
+
+ The following class inherits from the mean shift library
+ in order to perform the specialized tasks of image
+ segmentation and filtering.
+
+ The definition of the Mean Shift Image Processor Class
+ is provided below. Its prototype is provided in
+ 'msImageProcessor.h'.
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+          space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+#ifdef NICE_USELIB_OPENMP
+#include <omp.h>
+#endif
+
+//include image processor class prototype
+#include "msImageProcessor.h"
+
+//include needed libraries
+#include <math.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <iostream>
+using namespace std;
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@      PUBLIC METHODS     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\*/
+/* Constructor/Destructor */
+/*\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Class Constructor                                    */
+/*******************************************************/
+/*Post:                                                */
+/*      The msImageProcessor class has been properly   */
+/*      initialized.                                   */
+/*******************************************************/
+
+msImageProcessor::msImageProcessor ( void )
+{
+  clog << "[log] msImageProcessor::msImageProcessor: use Edison ";
+#ifdef NICE_USELIB_OPENMP
+  clog << "parallel!" << endl;
+  omp_set_dynamic ( 0 );
+#else
+  clog << "seriell!" << endl;
+#endif
+
+  //intialize basin of attraction structure
+  //used by the filtering algorithm
+  modeTable   = NULL;
+  pointList   = NULL;
+  pointCount   = 0;
+
+  //initialize region list
+  regionList   = NULL;
+
+  //initialize output structures...
+  msRawData   = NULL;
+  labels    = NULL;
+  modes    = NULL;
+  modePointCounts   = NULL;
+  regionCount   = 0;
+
+  //intialize temporary buffers used for
+  //performing connected components
+  indexTable   = NULL;
+  LUV_data   = NULL;
+
+  //initialize region adjacency matrix
+  raList    = NULL;
+  freeRAList   = NULL;
+  raPool    = NULL;
+
+  //intialize visit table to having NULL entries
+  visitTable   = NULL;
+
+  //initialize epsilon such that transitive closure
+  //does not take edge strength into consideration when
+  //fusing regions of similar color
+  epsilon    = 1.0;
+
+  //initialize class state to indicate that
+  //an output data structure has not yet been
+  //created...
+  class_state.OUTPUT_DEFINED = false;
+
+//Changed by Sushil from 1.0 to 0.1, 11/11/2008
+  LUV_treshold = 0.1;
+}
+
+/*******************************************************/
+/*Class Destructor                                     */
+/*******************************************************/
+/*Post:                                                */
+/*      The msImageProcessor class has been properly   */
+/*      destroyed.                                     */
+/*******************************************************/
+
+msImageProcessor::~msImageProcessor ( void )
+{
+
+  //de-allocate memory
+  if ( class_state.OUTPUT_DEFINED ) DestroyOutput();
+  if ( regionList )     delete regionList;
+  regionList = NULL;
+
+  //done.
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*  Input Image Declaration */
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Define Image                                         */
+/*******************************************************/
+/*Uploads an image into the image segmenter class to   */
+/*be segmented.                                        */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - data_ is a one dimensional array of unsigned */
+/*        char RGB vectors                             */
+/*      - type is the type of the image: COLOR or      */
+/*        GREYSCALE                                    */
+/*      - height_ and width_ define the dimension of   */
+/*        the image                                    */
+/*      - if the image is of type GREYSCALE then       */
+/*        data containes only one number per pixel     */
+/*        location, where a pixel location is defined  */
+/*        by the index into the data array             */
+/*Post:                                                */
+/*      - the image specified has been uploaded into   */
+/*        the image segmenter class to be segmented.   */
+/*******************************************************/
+
+void msImageProcessor::DefineImage ( byte *data_, imageType type, int height_, int width_ )
+{
+  /* Ein neuer LUV-Vektor wird angelegt. In diesen wird der Inhalt von data_ gespeichert. Kann data_ auch mit 'const' Qualifier definiert werden ?
+
+  */
+
+  //obtain image dimension from image type
+  int dim;
+  if ( type == COLOR )
+    dim = 3;
+  else
+    dim = 1;
+
+  //perfor rgb to luv conversion
+  int  i;
+  float *luv = new float [height_*width_*dim];
+  if ( dim == 1 )
+  {
+    for ( i = 0; i < height_*width_; i++ )
+      luv[i] = ( float ) ( data_[i] );
+  }
+  else
+  {
+    for ( i = 0; i < height_*width_; i++ )
+    {
+      RGBtoLUV ( &data_[dim*i], &luv[dim*i] );
+    }
+  }
+
+  //define input defined on a lattice using mean shift base class
+  DefineLInput ( luv, height_, width_, dim );
+
+  //Define a default kernel if it has not been already
+  //defined by user
+  if ( !h )
+  {
+    //define default kernel paramerters...
+    kernelType k[2]  = {Uniform, Uniform};
+    int   P[2]  = {2, N};
+    float  tempH[2] = {1.0 , 1.0};
+
+    //define default kernel in mean shift base class
+    DefineKernel ( k, tempH, P, 2 );
+  }
+
+  //de-allocate memory
+  delete [] luv;
+
+  //done.
+  return;
+
+}
+
+void msImageProcessor::DefineBgImage ( byte* data_, imageType type, int height_, int width_ )
+{
+
+  //obtain image dimension from image type
+  int dim;
+  if ( type == COLOR )
+    dim = 3;
+  else
+    dim = 1;
+
+  //perform texton classification
+  int  i;
+
+  float *luv = new float [height_*width_*dim];
+
+  if ( dim == 1 )
+  {
+    for ( i = 0; i < height_*width_; i++ )
+      luv[i] = ( float ) ( data_[i] );
+  }
+  else
+  {
+    for ( i = 0; i < height_*width_; i++ )
+      RGBtoLUV ( &data_[dim*i], &luv[dim*i] );
+
+  }
+
+  //define input defined on a lattice using mean shift base class
+  DefineLInput ( luv, height_, width_, dim );
+
+
+  //Define a default kernel if it has not been already
+  //defined by user
+  if ( !h )
+  {
+    //define default kernel paramerters...
+    kernelType k[2]  = {Uniform, Uniform};
+    int   P[2]  = {2, N};
+    float  tempH[2] = {1.0 , 1.0};
+
+    //define default kernel in mean shift base class
+    DefineKernel ( k, tempH, P, 2 );
+  }
+
+  //de-allocate memory
+  delete [] luv;
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\*/
+/*   Weight Map   */
+/*\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Set Weight Map                                       */
+/*******************************************************/
+/*Populates the weight map with specified edge         */
+/*strengths.                                           */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - wm is a floating point array of size         */
+/*        (height x width) specifying for each pixel   */
+/*        edge strength.                               */
+/*      - eps is a threshold used to fuse similar      */
+/*        regions during transitive closure.           */
+/*Post:                                                */
+/*      - wm has been used to populate the weight      */
+/*        map.                                         */
+/*      - the threshold used during transitive closure */
+/*        is taken as eps.                             */
+/*******************************************************/
+
+void msImageProcessor::SetWeightMap ( float *wm, float eps )
+{
+
+  //initlaize confmap using wm
+  SetLatticeWeightMap ( wm );
+
+  //set threshold value
+  if ( ( epsilon = eps ) < 0 )
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "SetWeightMap", ( char* ) "Threshold is negative." );
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Remove Weight Map                                    */
+/*******************************************************/
+/*Removes the weight map.                              */
+/*******************************************************/
+/*Post:                                                */
+/*      - the weight map has been removed.             */
+/*      - if a weight map did not exist NO error       */
+/*        is flagged.                                  */
+/*******************************************************/
+
+void msImageProcessor::RemoveWeightMap ( void )
+{
+
+  //remove confmap
+  RemoveLatticeWeightMap();
+
+  //set threshold value to zero
+  epsilon = 0;
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\*/
+/* Image Filtering  */
+/*\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Filter                                               */
+/*******************************************************/
+/*Performs mean shift filtering on the specified input */
+/*image using a user defined kernel.                   */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - the user defined kernel used to apply mean   */
+/*        shift filtering to the defined input image   */
+/*        has spatial bandwidth sigmaS and range band- */
+/*        width sigmaR                                 */
+/*      - speedUpLevel determines whether or not the   */
+/*        filtering should be optimized for faster     */
+/*        execution: a value of NO_SPEEDUP turns this  */
+/*        optimization off and a value SPEEDUP turns   */
+/*        this optimization on                         */
+/*      - a data set has been defined                  */
+/*      - the height and width of the lattice has been */
+/*        specified using method DefineLattice()       */
+/*Post:                                                */
+/*      - mean shift filtering has been applied to the */
+/*        input image using a user defined kernel      */
+/*      - the filtered image is stored in the private  */
+/*        data members of the msImageProcessor class.  */
+/*******************************************************/
+
+void msImageProcessor::Filter ( int sigmaS, float sigmaR, SpeedUpLevel speedUpLevel )
+{
+
+  //Check Class consistency...
+
+  //check:
+  // (1) if this operation is consistent
+  // (2) if kernel was created
+  // (3) if data set is defined
+  // (4) if the dimension of the kernel agrees with that
+  //     of the defined data set
+  // if not ... flag an error!
+  classConsistencyCheck ( N + 2, true );
+  if ( ErrorStatus == EL_ERROR )
+    return;
+
+  //If the algorithm has been halted, then exit
+  if ( ( ErrorStatus = msSys.Progress ( ( float ) ( 0.0 ) ) ) == EL_HALT )
+  {
+    return;
+  }
+
+  //If the image has just been read then allocate memory
+  //for and initialize output data structure used to store
+  //image modes and their corresponding regions...
+  if ( class_state.OUTPUT_DEFINED == false )
+  {
+    InitializeOutput();
+
+    //check for errors...
+    if ( ErrorStatus == EL_ERROR )
+      return;
+  }
+
+  //****************** Allocate Memory ******************
+
+  //Allocate memory for basin of attraction mode structure...
+  if ( ( ! ( modeTable = new unsigned char [L] ) ) || ( ! ( pointList = new int [L] ) ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Allocate", ( char* ) "Not enough memory." );
+    return;
+  }
+
+  //start timer
+#ifdef PROMPT
+  double timer;
+  msSys.StartTimer();
+#endif
+
+  //*****************************************************
+
+// Parallelisieren !!!
+
+  //filter image according to speedup level...
+  switch ( speedUpLevel )
+  {
+      //no speedup...
+    case NO_SPEEDUP:
+      //NonOptimizedFilter((float)(sigmaS), sigmaR); break;
+      NewNonOptimizedFilter ( ( float ) ( sigmaS ), sigmaR );
+      break;
+      //medium speedup
+    case MED_SPEEDUP:
+      //OptimizedFilter1((float)(sigmaS), sigmaR);  break;
+      NewOptimizedFilter1 ( ( float ) ( sigmaS ), sigmaR );
+      break;
+      //high speedup
+    case HIGH_SPEEDUP:
+      //OptimizedFilter2((float)(sigmaS), sigmaR);  break;
+      NewOptimizedFilter2 ( ( float ) ( sigmaS ), sigmaR );
+      break;
+      // new speedup
+  }
+
+  //****************** Deallocate Memory ******************
+
+  //de-allocate memory used by basin of attraction mode structure
+  delete [] modeTable;
+  delete [] pointList;
+
+  //re-initialize structure
+  modeTable = NULL;
+  pointList = NULL;
+  pointCount = 0;
+
+  //*******************************************************
+
+  //If the algorithm has been halted, then de-allocate the output
+  //and exit
+  if ( ( ErrorStatus = msSys.Progress ( ( float ) ( 0.8 ) ) ) == EL_HALT )
+  {
+    DestroyOutput();
+    return;
+  }
+
+  //Label image regions, also if segmentation is not to be
+  //performed use the resulting classification structure to
+  //calculate the image boundaries...
+
+  /*
+  //copy msRawData into LUV_data, rounding each component of each
+  //LUV value stored by msRawData to the nearest integer
+  int i;
+  for(i = 0; i < L*N; i++)
+  {
+  if(msRawData[i] < 0)
+  LUV_data[i] = (int)(msRawData[i] - 0.5);
+  else
+  LUV_data[i] = (int)(msRawData[i] + 0.5);
+  }
+  */
+// Parallelisieren !!!
+  int i;
+  for ( i = 0; i < L*N; i++ )
+  {
+    LUV_data[i] = msRawData[i];
+  }
+
+
+#ifdef PROMPT
+  timer = msSys.ElapsedTime();
+  printf ( ( char* ) "(%6.2f sec)\nConnecting regions         ...", timer );
+  msSys.StartTimer();
+#endif
+
+  //Perform connecting (label image regions) using LUV_data
+  Connect();
+
+#ifdef PROMPT
+  timer = msSys.ElapsedTime();
+  printf ( ( char* ) "done. (%6.2f seconds, numRegions = %6d)\n", timer, regionCount );
+  msSys.StartTimer();
+#endif
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\*/
+/* Image Region Fusing  */
+/*\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Fuse Regions                                         */
+/*******************************************************/
+/*Fuses the regions of a filtered image.               */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - the range radius is specified by sigmaR      */
+/*      - minRegion is the minimum point density that  */
+/*        a region may have in the resulting segment-  */
+/*        ed image                                     */
+/*      - a data set has been defined                  */
+/*      - the height and width of the lattice has been */
+/*        specified using method DefineLattice()       */
+/*Post:                                                */
+/*      - the image regions have been fused.           */
+/*      - if an result is stored by this class then    */
+/*        this result is used as input to this method. */
+/*      - if no result is stored by this class,        */
+/*        the input image defined by calling the       */
+/*        method DefineImage is used.                  */
+/*******************************************************/
+
+void msImageProcessor::FuseRegions ( float sigmaS, int minRegion )
+{
+
+  //Check Class consistency...
+
+  //check:
+  // (1) if this operation is consistent
+  // (2) if kernel was created
+  // (3) if data set is defined
+  // (4) if the dimension of the kernel agrees with that
+  //     of the defined data set
+  // if not ... flag an error!
+  classConsistencyCheck ( N + 2, true );
+  if ( ErrorStatus == EL_ERROR )
+    return;
+
+  //Check to see if the algorithm is to be halted, if so then
+  //destroy output and exit
+  if ( ( ErrorStatus = msSys.Progress ( ( float ) ( 0.8 ) ) ) == EL_HALT )
+  {
+    if ( class_state.OUTPUT_DEFINED ) DestroyOutput();
+    return;
+  }
+
+  //obtain sigmaS (make sure it is not zero or negative, if not
+  //flag an error)
+  if ( ( h[1] = sigmaS ) <= 0 )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "FuseRegions", ( char* ) "The feature radius must be greater than or equal to zero." );
+    return;
+  }
+
+  //if output has not yet been generated then classify the input
+  //image regions to be fused...
+  if ( ! ( class_state.OUTPUT_DEFINED ) )
+  {
+
+    //Initialize output data structure used to store
+    //image modes and their corresponding regions...
+    InitializeOutput();
+
+    //check for errors...
+    if ( ErrorStatus == EL_ERROR )
+      return;
+
+    //copy data into LUV_data used to classify
+    //image regions
+    /*
+    int i;
+    for(i = 0; i < L*N; i++)
+    {
+    if(data[i] < 0)
+    LUV_data[i] = (int)(data[i] - 0.5);
+    else
+    LUV_data[i] = (int)(data[i] + 0.5);
+    }
+    */
+    int i;
+    for ( i = 0; i < L*N; i++ )
+    {
+      LUV_data[i] = data[i];
+    }
+
+#ifdef PROMPT
+    printf ( ( char* ) "Connecting regions         ..." );
+    msSys.StartTimer();
+#endif
+
+    //Perform connecting (label image regions) using LUV_data
+    Connect();
+
+    //check for errors
+    if ( ErrorStatus == EL_ERROR )
+      return;
+
+#ifdef PROMPT
+    double timer = msSys.ElapsedTime();
+    printf ( ( char* ) "done. (%6.2f seconds, numRegions = %6d)\n", timer, regionCount );
+#endif
+
+  }
+
+  //Check to see if the algorithm is to be halted, if so then
+  //destroy output and exit
+  if ( ( ErrorStatus = msSys.Progress ( ( float ) ( 0.85 ) ) ) == EL_HALT )
+  {
+    DestroyOutput();
+    return;
+  }
+
+#ifdef PROMPT
+  printf ( ( char* ) "Applying transitive closure..." );
+  msSys.StartTimer();
+#endif
+
+  //allocate memory visit table
+  visitTable = new unsigned char [L];
+
+  //Apply transitive closure iteratively to the regions classified
+  //by the RAM updating labels and modes until the color of each neighboring
+  //region is within sqrt(rR2) of one another.
+  rR2 = ( float ) ( h[1] * h[1] * 0.25 );
+  TransitiveClosure();
+  int oldRC = regionCount;
+  int deltaRC, counter = 0;
+  do {
+    TransitiveClosure();
+    deltaRC = oldRC - regionCount;
+    oldRC = regionCount;
+    counter++;
+  } while ( ( deltaRC <= 0 ) && ( counter < 10 ) );
+
+  //de-allocate memory for visit table
+  delete [] visitTable;
+  visitTable = NULL;
+
+  //Check to see if the algorithm is to be halted, if so then
+  //destroy output and region adjacency matrix and exit
+  if ( ( ErrorStatus = msSys.Progress ( ( float ) ( 1.0 ) ) ) == EL_HALT )
+  {
+    DestroyRAM();
+    DestroyOutput();
+    return;
+  }
+
+#ifdef PROMPT
+  double timer = msSys.ElapsedTime();
+  printf ( ( char* ) "done. (%6.2f seconds, numRegions = %6d)\nPruning spurious regions   ...", timer, regionCount );
+  msSys.StartTimer();
+#endif
+
+  //Prune spurious regions (regions whose area is under
+  //minRegion) using RAM
+  Prune ( minRegion );
+
+#ifdef PROMPT
+  timer = msSys.ElapsedTime();
+  printf ( ( char* ) "done. (%6.2f seconds, numRegions = %6d)\n", timer, regionCount );
+  msSys.StartTimer();
+#endif
+
+  //Check to see if the algorithm is to be halted, if so then
+  //destroy output and region adjacency matrix and exit
+  if ( ( ErrorStatus = msSys.Progress ( ( float ) ( 1.0 ) ) ) == EL_HALT )
+  {
+    DestroyRAM();
+    DestroyOutput();
+    return;
+  }
+
+  //de-allocate memory for region adjacency matrix
+  DestroyRAM();
+
+  //output to msRawData
+  int i, j, label;
+  for ( i = 0; i < L; i++ )
+  {
+    label = labels[i];
+    for ( j = 0; j < N; j++ )
+    {
+      msRawData[N*i+j] = modes[N*label+j];
+    }
+  }
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\*/
+/* Image Segmentation */
+/*\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Segment                                              */
+/*******************************************************/
+/*Segments the defined image.                          */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - sigmaS and sigmaR are the spatial and range  */
+/*        radii of the search window respectively      */
+/*      - minRegion is the minimum point density that  */
+/*        a region may have in the resulting segment-  */
+/*        ed image                                     */
+/*      - speedUpLevel determines whether or not the   */
+/*        filtering should be optimized for faster     */
+/*        execution: a value of NO_SPEEDUP turns this  */
+/*        optimization off and a value SPEEDUP turns   */
+/*        this optimization on                         */
+/*Post:                                                */
+/*      - the defined image is segmented and the       */
+/*        resulting segmented image is stored in the   */
+/*        private data members of the image segmenter  */
+/*        class.                                       */
+/*      - any regions whose point densities are less   */
+/*        than or equal to minRegion have been pruned  */
+/*        from the segmented image.                    */
+/*******************************************************/
+
+void msImageProcessor::Segment ( int sigmaS, float sigmaR, int minRegion, SpeedUpLevel speedUpLevel )
+{
+
+  //make sure kernel is properly defined...
+  if ( ( !h ) || ( kp < 2 ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Segment", ( char* ) "Kernel corrupt or undefined." );
+    return;
+  }
+
+  //Apply mean shift to data set using sigmaS and sigmaR...
+  Filter ( sigmaS, sigmaR, speedUpLevel );
+
+  //check for errors
+  if ( ErrorStatus == EL_ERROR )
+    return;
+
+  //check to see if the system has been halted, if so exit
+  if ( ErrorStatus == EL_HALT )
+    return;
+
+  //Check to see if the algorithm is to be halted, if so then
+  //destroy output and exit
+  if ( ( ErrorStatus = msSys.Progress ( ( float ) ( 0.85 ) ) ) == EL_HALT )
+  {
+    DestroyOutput();
+    return;
+  }
+
+#ifdef PROMPT
+  printf ( ( char* ) "Applying transitive closure..." );
+  msSys.StartTimer();
+#endif
+
+  //allocate memory visit table
+  visitTable = new unsigned char [L];
+
+  //Apply transitive closure iteratively to the regions classified
+  //by the RAM updating labels and modes until the color of each neighboring
+  //region is within sqrt(rR2) of one another.
+  rR2 = ( float ) ( h[1] * h[1] * 0.25 );
+  TransitiveClosure();
+  int oldRC = regionCount;
+  int deltaRC, counter = 0;
+  do {
+    TransitiveClosure();
+    deltaRC = oldRC - regionCount;
+    oldRC = regionCount;
+    counter++;
+  } while ( ( deltaRC <= 0 ) && ( counter < 10 ) );
+
+  //de-allocate memory for visit table
+  delete [] visitTable;
+  visitTable = NULL;
+
+  //Check to see if the algorithm is to be halted, if so then
+  //destroy output and regions adjacency matrix and exit
+  if ( ( ErrorStatus = msSys.Progress ( ( float ) ( 0.95 ) ) ) == EL_HALT )
+  {
+    DestroyRAM();
+    DestroyOutput();
+    return;
+  }
+
+#ifdef PROMPT
+  double timer = msSys.ElapsedTime();
+  printf ( ( char* ) "done. (%6.2f seconds, numRegions = %6d).\nPruning spurious regions\t... ", timer, regionCount );
+  msSys.StartTimer();
+#endif
+
+  //Prune spurious regions (regions whose area is under
+  //minRegion) using RAM
+  Prune ( minRegion );
+
+#ifdef PROMPT
+  timer = msSys.ElapsedTime();
+  printf ( ( char* ) "done. (%6.2f seconds, numRegions = %6d)\nPruning spurious regions    ...", timer, regionCount );
+  msSys.StartTimer();
+#endif
+
+  //Check to see if the algorithm is to be halted, if so then
+  //destroy output and regions adjacency matrix and exit
+  if ( ( ErrorStatus = msSys.Progress ( 1.0 ) ) == EL_HALT )
+  {
+    DestroyRAM();
+    DestroyOutput();
+    return;
+  }
+
+  //de-allocate memory for region adjacency matrix
+  DestroyRAM();
+
+// Parallelisieren !!!
+
+  //output to msRawData
+  int j, i, label;
+
+  for ( i = 0; i < L; i++ )
+  {
+    label = labels[i];
+    for ( j = 0; j < N; j++ )
+    {
+      msRawData[N*i+j] = modes[N*label+j];
+    }
+  }
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*  Data Space Conversion */
+/*\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*RGB To LUV                                           */
+/*******************************************************/
+/*Converts an RGB vector to LUV.                       */
+/*                                                     */
+/*See:                                                 */
+/*   G. Wyszecki and W.S. Stiles: Color Science:       */
+/*   Concepts and Methods, Quantitative Data and       */
+/*   Formulae, Wiley, New York, 1982.                  */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - rgbVal is an unsigned char array containing  */
+/*        the RGB vector                               */
+/*      - luvVal is a floating point array containing  */
+/*        the resulting LUV vector                     */
+/*Post:                                                */
+/*      - rgbVal has been converted to LUV and the     */
+/*        result has been stored in luvVal.            */
+/*******************************************************/
+
+void msImageProcessor::RGBtoLUV ( byte *rgbVal, float *luvVal )
+{
+
+  //delcare variables
+  double x, y, z, L0, u_prime, v_prime, constant;
+
+  //convert RGB to XYZ...
+  x  = XYZ[0][0] * rgbVal[0] + XYZ[0][1] * rgbVal[1] + XYZ[0][2] * rgbVal[2];
+  y  = XYZ[1][0] * rgbVal[0] + XYZ[1][1] * rgbVal[1] + XYZ[1][2] * rgbVal[2];
+  z  = XYZ[2][0] * rgbVal[0] + XYZ[2][1] * rgbVal[1] + XYZ[2][2] * rgbVal[2];
+
+  //convert XYZ to LUV...
+
+  //compute L*
+  L0  = y / ( 255.0 * Yn );
+  if ( L0 > Lt )
+    luvVal[0] = ( float ) ( 116.0 * ( pow ( L0, 1.0 / 3.0 ) ) - 16.0 );
+  else
+    luvVal[0] = ( float ) ( 903.3 * L0 );
+
+  //compute u_prime and v_prime
+  constant = x + 15 * y + 3 * z;
+  if ( constant != 0 )
+  {
+    u_prime = ( 4 * x ) / constant;
+    v_prime = ( 9 * y ) / constant;
+  }
+  else
+  {
+    u_prime = 4.0;
+    v_prime = 9.0 / 15.0;
+  }
+
+  //compute u* and v*
+  luvVal[1] = ( float ) ( 13 * luvVal[0] * ( u_prime - Un_prime ) );
+  luvVal[2] = ( float ) ( 13 * luvVal[0] * ( v_prime - Vn_prime ) );
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*LUV To RGB                                           */
+/*******************************************************/
+/*Converts an LUV vector to RGB.                       */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - luvVal is a floating point array containing  */
+/*        the LUV vector                               */
+/*      - rgbVal is an unsigned char array containing  */
+/*        the resulting RGB vector                     */
+/*Post:                                                */
+/*      - luvVal has been converted to RGB and the     */
+/*        result has been stored in rgbVal.            */
+/*******************************************************/
+
+//define inline rounding function...
+inline int my_round ( double in_x )
+{
+  if ( in_x < 0 )
+    return ( int ) ( in_x - 0.5 );
+  else
+    return ( int ) ( in_x + 0.5 );
+}
+
+void msImageProcessor::LUVtoRGB ( float *luvVal, byte *rgbVal )
+{
+
+  //declare variables...
+  int  r, g, b;
+  double x, y, z, u_prime, v_prime;
+
+  //perform conversion
+  if ( luvVal[0] < 0.1 )
+    r = g = b = 0;
+  else
+  {
+    //convert luv to xyz...
+    if ( luvVal[0] < 8.0 )
+      y = Yn * luvVal[0] / 903.3;
+    else
+    {
+      y = ( luvVal[0] + 16.0 ) / 116.0;
+      y  *= Yn * y * y;
+    }
+
+    u_prime = luvVal[1] / ( 13 * luvVal[0] ) + Un_prime;
+    v_prime = luvVal[2] / ( 13 * luvVal[0] ) + Vn_prime;
+
+    x  = 9 * u_prime * y / ( 4 * v_prime );
+    z  = ( 12 - 3 * u_prime - 20 * v_prime ) * y / ( 4 * v_prime );
+
+    //convert xyz to rgb...
+    //[r, g, b] = RGB*[x, y, z]*255.0
+    r  = my_round ( ( RGB[0][0] * x + RGB[0][1] * y + RGB[0][2] * z ) * 255.0 );
+    g  = my_round ( ( RGB[1][0] * x + RGB[1][1] * y + RGB[1][2] * z ) * 255.0 );
+    b  = my_round ( ( RGB[2][0] * x + RGB[2][1] * y + RGB[2][2] * z ) * 255.0 );
+
+    //check bounds...
+    if ( r < 0 ) r = 0;
+    if ( r > 255 ) r = 255;
+    if ( g < 0 ) g = 0;
+    if ( g > 255 ) g = 255;
+    if ( b < 0 ) b = 0;
+    if ( b > 255 ) b = 255;
+
+  }
+
+  //assign rgb values to rgb vector rgbVal
+  rgbVal[0] = r;
+  rgbVal[1] = g;
+  rgbVal[2] = b;
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*  Filtered and Segmented Image Output */
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Get Raw Data                                         */
+/*******************************************************/
+/*The output image data is returned.                   */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - outputImageData is a pre-allocated floating  */
+/*        point array used to store the filtered or    */
+/*        segmented image pixels.                      */
+/*Post:                                                */
+/*      - the filtered or segmented image data is      */
+/*        stored by outputImageData.                   */
+/*******************************************************/
+
+void msImageProcessor::GetRawData ( float *outputImageData )
+{
+  //make sure that outputImageData is not NULL
+  if ( !outputImageData )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "GetRawData", ( char* ) "Output image data buffer is NULL." );
+    return;
+  }
+
+  //copy msRawData to outputImageData
+  int i;
+  for ( i = 0; i < L*N; i++ )
+    outputImageData[i] = msRawData[i];
+
+  //done.
+  return;
+}
+
+/*******************************************************/
+/*Get Results                                          */
+/*******************************************************/
+/*The output image is returned.                        */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - outputImage is a pre-allocated unsinged char */
+/*        array used to store the filtered or segment- */
+/*        ed image pixels                              */
+/*Post:                                                */
+/*      - the filtered or segmented image is stored by */
+/*        outputImage.                                 */
+/*******************************************************/
+
+void msImageProcessor::GetResults ( byte *outputImage )
+{
+
+  //make sure that outpuImage is not NULL
+  if ( !outputImage )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "GetResults", ( char* ) "Output image buffer is NULL." );
+    return;
+  }
+
+  //if the image type is GREYSCALE simply
+  //copy it over to the segmentedImage
+  if ( N == 1 )
+  {
+    //copy over msRawData to segmentedImage checking
+    //bounds
+    int i, pxValue;
+    for ( i = 0; i < L; i++ )
+    {
+
+      //get value
+      pxValue = ( int ) ( msRawData[i] + 0.5 );
+
+      //store into segmented image checking bounds...
+      if ( pxValue < 0 )
+        outputImage[i] = ( byte ) ( 0 );
+      else if ( pxValue > 255 )
+        outputImage[i] = ( byte ) ( 255 );
+      else
+        outputImage[i] = ( byte ) ( pxValue );
+
+    }
+
+  }
+  else if ( N == 3 )
+  {
+
+    //otherwise convert msRawData from LUV to RGB
+    //storing the result in segmentedImage
+    int i;
+    for ( i = 0; i < L; i++ )
+      LUVtoRGB ( &msRawData[N*i], &outputImage[N*i] );
+
+  }
+  else
+    //Unknown image type: should use MeanShift::GetRawData()...
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "GetResults", ( char* ) "Unknown image type. Try using MeanShift::GetRawData()." );
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Get Boundaries                                       */
+/*******************************************************/
+/*A region list containing the boundary locations for  */
+/*each region is returned.                             */
+/*******************************************************/
+/*Post:                                                */
+/*      - a region list object containing the boundary */
+/*        locations for each region is constructed     */
+/*      - the region list is returned                  */
+/*      - NULL is returned if the image has not been   */
+/*        filtered or segmented                        */
+/*******************************************************/
+
+RegionList *msImageProcessor::GetBoundaries ( void )
+{
+
+  //define bounds using label information
+  if ( class_state.OUTPUT_DEFINED )
+    DefineBoundaries();
+
+  //return region list structure
+  return regionList;
+
+}
+
+/*******************************************************/
+/*Get Regions                                          */
+/*******************************************************/
+/*Returns the regions of the processed image.          */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - labels_out is an integer array of size       */
+/*        height*width that stores for each pixel a    */
+/*        label relating that pixel to a corresponding */
+/*        region in the image                          */
+/*      - modes_out is floating point array of size    */
+/*        regionCount*N storing the feature component  */
+/*        of each region, and indexed by region label  */
+/*      - modePointCounts is an integer array of size  */
+/*        regionCount, indexed by region label, that   */
+/*        stores the area of each region in pixels.    */
+/*Post:                                                */
+/*      If an input image was defined and processed,   */
+/*      - memory has been allocated for labels_out,    */
+/*        modes_out and MPC_out.                       */
+/*      - labels_out, modes_out, and MPC_out have been */
+/*        populated.                                   */
+/*      - the number of regions contained by the segm- */
+/*        ented image has been returned.               */
+/*      If the image has not been defined or processed */
+/*      or if there is in-sufficient memory,           */
+/*      - no memory has been allocated for labels_out, */
+/*        modes_out, and MPC_out.                      */
+/*      - -1 is returned for regionCount.              */
+/*******************************************************/
+
+int msImageProcessor::GetRegions ( int **labels_out, float **modes_out, int **MPC_out )
+{
+  //check to see if output has been defined for the given input image...
+  if ( class_state.OUTPUT_DEFINED == false )
+    return -1;
+
+  //allocate memory for labels_out, modes_out and MPC_out based
+  //on output storage structure
+  int  *labels_ = *labels_out, *MPC_out_ = *MPC_out;
+  float *modes_  = *modes_out;
+  if ( ! ( labels_ = new int [L] ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "GetRegions", ( char* ) "Not enough memory." );
+    return -1;
+  }
+  if ( ! ( modes_ = new float [regionCount*N] ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "GetRegions", ( char* ) "Not enough memory." );
+    return -1;
+  }
+  if ( ! ( MPC_out_ = new int [regionCount] ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "GetRegions", ( char* ) "Not enough memory." );
+    return -1;
+  }
+
+  //populate labels_out with image labels
+  int i;
+  for ( i = 0; i < L; i++ )
+    labels_[i] = labels[i];
+
+  //populate modes_out and MPC_out with the color and point
+  //count of each region
+  for ( i = 0; i < regionCount*N; i++ )
+    modes_[i] = modes[i];
+  for ( i = 0; i < regionCount; i++ )
+    MPC_out_[i] = modePointCounts[i];
+
+  //done. Return the number of regions resulting from filtering or segmentation.
+  return regionCount;
+}
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     PRIVATE METHODS     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+/*/\/\/\/\/\/\/\/\/\*/
+/*  Image Filtering */
+/*\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Non Optimized Filter                                 */
+/*******************************************************/
+/*Performs mean shift filtering on the specified input */
+/*image using a user defined kernel.                   */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - the user defined kernel used to apply mean   */
+/*        shift filtering to the defined input image   */
+/*        has spatial bandwidth sigmaS and range band- */
+/*        width sigmaR                                 */
+/*      - a data set has been defined                  */
+/*      - the height and width of the lattice has been */
+/*        specified using method DefineLattice()       */
+/*Post:                                                */
+/*      - mean shift filtering has been applied to the */
+/*        input image using a user defined kernel      */
+/*      - the filtered image is stored in the private  */
+/*        data members of the msImageProcessor class.  */
+/*******************************************************/
+
+void msImageProcessor::NonOptimizedFilter ( float sigmaS, float sigmaR )
+{
+
+  // Declare Variables
+  int   iterationCount, i, j;
+  double mvAbs;
+
+  //make sure that a lattice height and width have
+  //been defined...
+  if ( !height )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "LFilter", ( char* ) "Lattice height and width are undefined." );
+    return;
+  }
+
+  //re-assign bandwidths to sigmaS and sigmaR
+  if ( ( ( h[0] = sigmaS ) <= 0 ) || ( ( h[1] = sigmaR ) <= 0 ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Segment", ( char* ) "sigmaS and/or sigmaR is zero or negative." );
+    return;
+  }
+
+  //define input data dimension with lattice
+  int lN = N + 2;
+
+  // Traverse each data point applying mean shift
+  // to each data point
+
+  // Allcocate memory for yk
+  double *yk  = new double [lN];
+
+  // Allocate memory for Mh
+  double *Mh  = new double [lN];
+
+  // proceed ...
+#ifdef PROMPT
+  printf ( ( char* ) "done.\nApplying mean shift (Using Lattice)... " );
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\n 0%%" );
+#endif
+#endif
+
+// Parallelisieren !!!
+
+  for ( i = 0; i < L; i++ )
+  {
+
+    // Assign window center (window centers are
+    // initialized by createLattice to be the point
+    // data[i])
+    yk[0] = i % width;
+    yk[1] = i / width;
+    for ( j = 0; j < N; j++ )
+      yk[j+2] = data[N*i+j];
+
+    // Calculate the mean shift vector using the lattice
+    LatticeMSVector ( Mh, yk );
+
+    // Calculate its magnitude squared
+    mvAbs = 0;
+    for ( j = 0; j < lN; j++ )
+      mvAbs += Mh[j] * Mh[j];
+
+    // Keep shifting window center until the magnitude squared of the
+    // mean shift vector calculated at the window center location is
+    // under a specified threshold (Epsilon)
+
+    // NOTE: iteration count is for speed up purposes only - it
+    //       does not have any theoretical importance
+    iterationCount = 1;
+    while ( ( mvAbs >= EPSILON2 ) && ( iterationCount < LIMIT ) )
+    {
+
+      // Shift window location
+      for ( j = 0; j < lN; j++ )
+        yk[j] += Mh[j];
+
+      // Calculate the mean shift vector at the new
+      // window location using lattice
+      LatticeMSVector ( Mh, yk );
+
+      // Calculate its magnitude squared
+      mvAbs = 0;
+      for ( j = 0; j < lN; j++ )
+        mvAbs += Mh[j] * Mh[j];
+
+      // Increment interation count
+      iterationCount++;
+
+    }
+
+    // Shift window location
+    for ( j = 0; j < lN; j++ )
+      yk[j] += Mh[j];
+
+    //store result into msRawData...
+    for ( j = 0; j < N; j++ )
+      msRawData[N*i+j] = ( float ) ( yk[j+2] );
+
+    // Prompt user on progress
+#ifdef SHOW_PROGRESS
+    percent_complete = ( float ) ( i / ( float ) ( L ) ) * 100;
+    printf ( ( char* ) "\r%2d%%", ( int ) ( percent_complete + 0.5 ) );
+#endif
+
+    // Check to see if the algorithm has been halted
+    if ( ( i % PROGRESS_RATE == 0 ) && ( ( ErrorStatus = msSys.Progress ( ( float ) ( i / ( float ) ( L ) ) * ( float ) ( 0.8 ) ) ) ) == EL_HALT )
+      break;
+  }
+
+  // Prompt user that filtering is completed
+#ifdef PROMPT
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\r" );
+#endif
+  printf ( ( char* ) "done." );
+#endif
+
+  // de-allocate memory
+  delete [] yk;
+  delete [] Mh;
+
+  // done.
+  return;
+
+}
+
+
+
+/*******************************************************/
+/*Optimized Filter 1                                   */
+/*******************************************************/
+/*Performs mean shift filtering on the specified input */
+/*image using a user defined kernel. Previous mode     */
+/*information is used to avoid re-applying mean shift  */
+/*on certain data points to improve performance.       */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - the user defined kernel used to apply mean   */
+/*        shift filtering to the defined input image   */
+/*        has spatial bandwidth sigmaS and range band- */
+/*        width sigmaR                                 */
+/*      - a data set has been defined                  */
+/*      - the height and width of the lattice has been */
+/*        specified using method DefineLattice()       */
+/*Post:                                                */
+/*      - mean shift filtering has been applied to the */
+/*        input image using a user defined kernel      */
+/*      - the filtered image is stored in the private  */
+/*        data members of the msImageProcessor class.  */
+/*******************************************************/
+
+void msImageProcessor::OptimizedFilter1 ( float sigmaS, float sigmaR )
+{
+
+  // Declare Variables
+  int  iterationCount, i, j, k, s, p, modeCandidateX, modeCandidateY, modeCandidate_i;
+  float *modeCandidatePoint;
+  double mvAbs, diff, el;
+
+  //make sure that a lattice height and width have
+  //been defined...
+  if ( !height )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "LFilter", ( char* ) "Lattice height and width are undefined." );
+    return;
+  }
+
+  //re-assign bandwidths to sigmaS and sigmaR
+  if ( ( ( h[0] = sigmaS ) <= 0 ) || ( ( h[1] = sigmaR ) <= 0 ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Segment", ( char* ) "sigmaS and/or sigmaR is zero or negative." );
+    return;
+  }
+
+  //define input data dimension with lattice
+  int lN = N + 2;
+
+  // Traverse each data point applying mean shift
+  // to each data point
+
+  // Allcocate memory for yk
+  double *yk  = new double [lN];
+
+  // Allocate memory for Mh
+  double *Mh  = new double [lN];
+
+  // Initialize mode table used for basin of attraction
+  memset ( modeTable, 0, width*height );
+
+  // Allocate memory mode candidate data point...
+  //floating point version
+  modeCandidatePoint = new float [N];
+
+  // proceed ...
+#ifdef PROMPT
+  printf ( ( char* ) "done.\nApplying mean shift (Using Lattice) ... " );
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\n 0%%" );
+#endif
+#endif
+
+// Parallelisieren !!!
+
+  for ( i = 0; i < L; i++ )
+  {
+    // if a mode was already assigned to this data point
+    // then skip this point, otherwise proceed to
+    // find its mode by applying mean shift...
+    if ( modeTable[i] == 1 )
+      continue;
+
+    // initialize point list...
+    pointCount = 0;
+
+    // Assign window center (window centers are
+    // initialized by createLattice to be the point
+    // data[i])
+    yk[0] = i % width;
+    yk[1] = i / width;
+    for ( j = 0; j < N; j++ )
+      yk[j+2] = data[N*i+j];
+
+    // Calculate the mean shift vector using the lattice
+    LatticeMSVector ( Mh, yk );
+
+    // Calculate its magnitude squared
+    mvAbs = 0;
+    for ( j = 0; j < lN; j++ )
+      mvAbs += Mh[j] * Mh[j];
+
+    // Keep shifting window center until the magnitude squared of the
+    // mean shift vector calculated at the window center location is
+    // under a specified threshold (Epsilon)
+
+    // NOTE: iteration count is for speed up purposes only - it
+    //       does not have any theoretical importance
+    iterationCount = 1;
+    while ( ( mvAbs >= EPSILON2 ) && ( iterationCount < LIMIT ) )
+    {
+
+      // Shift window location
+      for ( j = 0; j < lN; j++ )
+        yk[j] += Mh[j];
+
+      // check to see if the current mode location is in the
+      // basin of attraction...
+
+      // calculate the location of yk on the lattice
+      modeCandidateX = ( int ) ( yk[0] + 0.5 );
+      modeCandidateY = ( int ) ( yk[1] + 0.5 );
+      modeCandidate_i = modeCandidateY * width + modeCandidateX;
+
+      // if mvAbs != 0 (yk did indeed move) then check
+      // location basin_i in the mode table to see if
+      // this data point either:
+
+      // (1) has not been associated with a mode yet
+      //     (modeTable[basin_i] = 0), so associate
+      //     it with this one
+      //
+      // (2) it has been associated with a mode other
+      //     than the one that this data point is converging
+      //     to (modeTable[basin_i] = 1), so assign to
+      //     this data point the same mode as that of basin_i
+
+      if ( ( modeTable[modeCandidate_i] != 2 ) && ( modeCandidate_i != i ) )
+      {
+        // obtain the data point at basin_i to
+        // see if it is within h*TC_DIST_FACTOR of
+        // of yk
+        for ( j = 0; j < N; j++ )
+          modeCandidatePoint[j] = data[N*modeCandidate_i + j];
+
+        // check basin on non-spatial data spaces only
+        k = 1;
+        s = 0;
+        diff = 0;
+        while ( ( diff < TC_DIST_FACTOR ) && ( k < kp ) )
+        {
+          diff = 0;
+          for ( p = 0; p < P[k]; p++ )
+          {
+            el = ( modeCandidatePoint[p+s] - yk[p+s+2] ) / h[k];
+            diff += el * el;
+          }
+          s += P[k];
+          k++;
+        }
+
+        // if the data point at basin_i is within
+        // a distance of h*TC_DIST_FACTOR of yk
+        // then depending on modeTable[basin_i] perform
+        // either (1) or (2)
+        if ( diff < TC_DIST_FACTOR )
+        {
+          // if the data point at basin_i has not
+          // been associated to a mode then associate
+          // it with the mode that this one will converge
+          // to
+          if ( modeTable[modeCandidate_i] == 0 )
+          {
+            // no mode associated yet so associate
+            // it with this one...
+            pointList[pointCount++]  = modeCandidate_i;
+            modeTable[modeCandidate_i] = 2;
+
+          } else
+          {
+
+            // the mode has already been associated with
+            // another mode, thererfore associate this one
+            // mode and the modes in the point list with
+            // the mode associated with data[basin_i]...
+
+            // store the mode info into yk using msRawData...
+            for ( j = 0; j < N; j++ )
+              yk[j+2] = msRawData[modeCandidate_i*N+j];
+
+            // update mode table for this data point
+            // indicating that a mode has been associated
+            // with it
+            modeTable[i] = 1;
+
+            // indicate that a mode has been associated
+            // to this data point (data[i])
+            mvAbs = -1;
+
+            // stop mean shift calculation...
+            break;
+          }
+        }
+      }
+
+      // Calculate the mean shift vector at the new
+      // window location using lattice
+      LatticeMSVector ( Mh, yk );
+
+      // Calculate its magnitude squared
+      mvAbs = 0;
+      for ( j = 0; j < lN; j++ )
+        mvAbs += Mh[j] * Mh[j];
+
+      // Increment iteration count
+      iterationCount++;
+
+    }
+
+    // if a mode was not associated with this data point
+    // yet associate it with yk...
+    if ( mvAbs >= 0 )
+    {
+      // Shift window location
+      for ( j = 0; j < lN; j++ )
+        yk[j] += Mh[j];
+
+      // update mode table for this data point
+      // indicating that a mode has been associated
+      // with it
+      modeTable[i] = 1;
+    }
+
+    // associate the data point indexed by
+    // the point list with the mode stored
+    // by yk
+    for ( j = 0; j < pointCount; j++ )
+    {
+      // obtain the point location from the
+      // point list
+      modeCandidate_i = pointList[j];
+
+      // update the mode table for this point
+      modeTable[modeCandidate_i] = 1;
+
+      //store result into msRawData...
+      for ( k = 0; k < N; k++ )
+        msRawData[N*modeCandidate_i+k] = ( float ) ( yk[k+2] );
+    }
+
+
+    //store result into msRawData...
+    for ( j = 0; j < N; j++ )
+      msRawData[N*i+j] = ( float ) ( yk[j+2] );
+
+    // Prompt user on progress
+#ifdef SHOW_PROGRESS
+    percent_complete = ( float ) ( i / ( float ) ( L ) ) * 100;
+    printf ( ( char* ) "\r%2d%%", ( int ) ( percent_complete + 0.5 ) );
+#endif
+
+    // Check to see if the algorithm has been halted
+    if ( ( i % PROGRESS_RATE == 0 ) && ( ( ErrorStatus = msSys.Progress ( ( float ) ( i / ( float ) ( L ) ) * ( float ) ( 0.8 ) ) ) ) == EL_HALT )
+      break;
+  }
+
+  // Prompt user that filtering is completed
+#ifdef PROMPT
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\r" );
+#endif
+  printf ( ( char* ) "done." );
+#endif
+
+  // de-allocate memory
+  delete [] modeCandidatePoint;
+  delete [] yk;
+  delete [] Mh;
+
+  // done.
+  return;
+
+}
+
+/*******************************************************/
+/*Optimized Filter 2                                   */
+/*******************************************************/
+/*Performs mean shift filtering on the specified input */
+/*image using a user defined kernel. Previous mode     */
+/*information is used to avoid re-applying mean shift  */
+/*on certain data points to improve performance. To    */
+/*further improve perfmance (during segmentation) poi- */
+/*nts within h of a window center during the window    */
+/*center's traversal to a mode are associated with the */
+/*mode that the window converges to.                   */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - the user defined kernel used to apply mean   */
+/*        shift filtering to the defined input image   */
+/*        has spatial bandwidth sigmaS and range band- */
+/*        width sigmaR                                 */
+/*      - a data set has been defined                  */
+/*      - the height and width of the lattice has been */
+/*        specified using method DefineLattice()       */
+/*Post:                                                */
+/*      - mean shift filtering has been applied to the */
+/*        input image using a user defined kernel      */
+/*      - the filtered image is stored in the private  */
+/*        data members of the msImageProcessor class.  */
+/*******************************************************/
+
+void msImageProcessor::OptimizedFilter2 ( float sigmaS, float sigmaR )
+{
+
+  //if confidence map is null set it to zero
+  if ( !weightMap )
+  {
+    weightMap = new float [L];
+    int i;
+    for ( i = 0; i < L; i++ )
+      weightMap[i] = 0;
+  }
+
+  // Declare Variables
+  int  iterationCount, i, j, k, s, p, modeCandidateX, modeCandidateY, modeCandidate_i;
+  float *modeCandidatePoint;
+  double mvAbs, diff, el;
+
+  //make sure that a lattice height and width have
+  //been defined...
+  if ( !height )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "LFilter", ( char* ) "Lattice height and width are undefined." );
+    return;
+  }
+
+  //re-assign bandwidths to sigmaS and sigmaR
+  if ( ( ( h[0] = sigmaS ) <= 0 ) || ( ( h[1] = sigmaR ) <= 0 ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Segment", ( char* ) "sigmaS and/or sigmaR is zero or negative." );
+    return;
+  }
+
+  //define input data dimension with lattice
+  int lN = N + 2;
+
+  // Traverse each data point applying mean shift
+  // to each data point
+
+  // Allcocate memory for yk
+  double *yk  = new double [lN];
+
+  // Allocate memory for Mh
+  double *Mh  = new double [lN];
+
+  // Initialize mode table used for basin of attraction
+  memset ( modeTable, 0, width*height );
+
+  // Allocate memory mode candidate data point...
+  //floating point version
+  modeCandidatePoint = new float [N];
+
+  // proceed ...
+#ifdef PROMPT
+  printf ( ( char* ) "done.\nApplying mean shift (Using Lattice)... " );
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\n 0%%" );
+#endif
+#endif
+
+// Parallelisieren !!!
+
+  for ( i = 0; i < L; i++ )
+  {
+    // if a mode was already assigned to this data point
+    // then skip this point, otherwise proceed to
+    // find its mode by applying mean shift...
+    if ( modeTable[i] == 1 )
+      continue;
+
+    // initialize point list...
+    pointCount = 0;
+
+    // Assign window center (window centers are
+    // initialized by createLattice to be the point
+    // data[i])
+    yk[0] = i % width;
+    yk[1] = i / width;
+    for ( j = 0; j < N; j++ )
+      yk[j+2] = data[N*i+j];
+
+    // Calculate the mean shift vector using the lattice
+    OptLatticeMSVector ( Mh, yk );
+
+    // Calculate its magnitude squared
+    mvAbs = 0;
+    for ( j = 0; j < lN; j++ )
+      mvAbs += Mh[j] * Mh[j];
+
+    // Keep shifting window center until the magnitude squared of the
+    // mean shift vector calculated at the window center location is
+    // under a specified threshold (Epsilon)
+
+    // NOTE: iteration count is for speed up purposes only - it
+    //       does not have any theoretical importance
+    iterationCount = 1;
+    while ( ( mvAbs >= EPSILON2 ) && ( iterationCount < LIMIT ) )
+    {
+
+      // Shift window location
+      for ( j = 0; j < lN; j++ )
+        yk[j] += Mh[j];
+
+      // check to see if the current mode location is in the
+      // basin of attraction...
+
+      // calculate the location of yk on the lattice
+      modeCandidateX = ( int ) ( yk[0] + 0.5 );
+      modeCandidateY = ( int ) ( yk[1] + 0.5 );
+      modeCandidate_i = modeCandidateY * width + modeCandidateX;
+
+      // if mvAbs != 0 (yk did indeed move) then check
+      // location basin_i in the mode table to see if
+      // this data point either:
+
+      // (1) has not been associated with a mode yet
+      //     (modeTable[basin_i] = 0), so associate
+      //     it with this one
+      //
+      // (2) it has been associated with a mode other
+      //     than the one that this data point is converging
+      //     to (modeTable[basin_i] = 1), so assign to
+      //     this data point the same mode as that of basin_i
+
+      if ( ( modeTable[modeCandidate_i] != 2 ) && ( modeCandidate_i != i ) )
+      {
+        // obtain the data point at basin_i to
+        // see if it is within h*TC_DIST_FACTOR of
+        // of yk
+        for ( j = 0; j < N; j++ )
+          modeCandidatePoint[j] = data[N*modeCandidate_i + j];
+
+        // check basin on non-spatial data spaces only
+        k = 1;
+        s = 0;
+        diff = 0;
+        while ( ( diff < TC_DIST_FACTOR ) && ( k < kp ) )
+        {
+          diff = 0;
+          for ( p = 0; p < P[k]; p++ )
+          {
+            el = ( modeCandidatePoint[p+s] - yk[p+s+2] ) / h[k];
+            diff += el * el;
+          }
+          s += P[k];
+          k++;
+        }
+
+        // if the data point at basin_i is within
+        // a distance of h*TC_DIST_FACTOR of yk
+        // then depending on modeTable[basin_i] perform
+        // either (1) or (2)
+        if ( diff < TC_DIST_FACTOR )
+        {
+          // if the data point at basin_i has not
+          // been associated to a mode then associate
+          // it with the mode that this one will converge
+          // to
+          if ( modeTable[modeCandidate_i] == 0 )
+          {
+            // no mode associated yet so associate
+            // it with this one...
+            pointList[pointCount++]  = modeCandidate_i;
+            modeTable[modeCandidate_i] = 2;
+
+          } else
+          {
+
+            // the mode has already been associated with
+            // another mode, thererfore associate this one
+            // mode and the modes in the point list with
+            // the mode associated with data[basin_i]...
+
+            // store the mode infor int yk using msRawData...
+            for ( j = 0; j < N; j++ )
+              yk[j+2] = msRawData[modeCandidate_i*N+j];
+
+            // update mode table for this data point
+            // indicating that a mode has been associated
+            // with it
+            modeTable[i] = 1;
+
+            // indicate that a mode has been associated
+            // to this data point (data[i])
+            mvAbs = -1;
+
+            // stop mean shift calculation...
+            break;
+          }
+        }
+      }
+
+      // Calculate the mean shift vector at the new
+      // window location using lattice
+      OptLatticeMSVector ( Mh, yk );
+
+      // Calculate its magnitude squared
+      mvAbs = 0;
+      for ( j = 0; j < lN; j++ )
+        mvAbs += Mh[j] * Mh[j];
+
+      // Increment interation count
+      iterationCount++;
+
+    }
+
+    // if a mode was not associated with this data point
+    // yet then perform a shift the window center yk one
+    // last time using the mean shift vector...
+    if ( mvAbs >= 0 )
+    {
+      // Shift window location
+      for ( j = 0; j < lN; j++ )
+        yk[j] += Mh[j];
+
+      // update mode table for this data point
+      // indicating that a mode has been associated
+      // with it
+      modeTable[i] = 1;
+    }
+
+    // associate the data point indexed by
+    // the point list with the mode stored
+    // by yk
+    for ( j = 0; j < pointCount; j++ )
+    {
+      // obtain the point location from the
+      // point list
+      modeCandidate_i = pointList[j];
+
+      // update the mode table for this point
+      modeTable[modeCandidate_i] = 1;
+
+      //store result into msRawData...
+      for ( k = 0; k < N; k++ )
+        msRawData[N*modeCandidate_i+k] = ( float ) ( yk[k+2] );
+    }
+
+
+    //store result into msRawData...
+    for ( j = 0; j < N; j++ )
+      msRawData[N*i+j] = ( float ) ( yk[j+2] );
+
+    // Prompt user on progress
+#ifdef SHOW_PROGRESS
+    percent_complete = ( float ) ( i / ( float ) ( L ) ) * 100;
+    printf ( ( char* ) "\r%2d%%", ( int ) ( percent_complete + 0.5 ) );
+#endif
+
+    // Check to see if the algorithm has been halted
+    if ( ( i % PROGRESS_RATE == 0 ) && ( ( ErrorStatus = msSys.Progress ( ( float ) ( i / ( float ) ( L ) ) * ( float ) ( 0.8 ) ) ) ) == EL_HALT )
+      break;
+
+  }
+
+  // Prompt user that filtering is completed
+#ifdef PROMPT
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\r" );
+#endif
+  printf ( ( char* ) "done." );
+#endif
+
+  // de-allocate memory
+  delete [] modeCandidatePoint;
+  delete [] yk;
+  delete [] Mh;
+
+  // done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\*/
+/* Image Classification */
+/*\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Connect                                              */
+/*******************************************************/
+/*Classifies the regions of the mean shift filtered    */
+/*image.                                               */
+/*******************************************************/
+/*Post:                                                */
+/*      - the regions of the mean shift image have been*/
+/*        classified using the private classification  */
+/*        structure of the msImageProcessor Class.     */
+/*        Namely, each region uniquely identified by   */
+/*        its LUV color  (stored by LUV_data) and loc- */
+/*        ation has been labeled and its area computed */
+/*        via an eight-connected fill.                 */
+/*******************************************************/
+
+void msImageProcessor::Connect ( void )
+{
+
+  //define eight connected neighbors
+  neigh[0] = 1;
+  neigh[1] = 1 - width;
+  neigh[2] = -width;
+  neigh[3] = - ( 1 + width );
+  neigh[4] = -1;
+  neigh[5] = width - 1;
+  neigh[6] = width;
+  neigh[7] = width + 1;
+
+  //initialize labels and modePointCounts
+  int i;
+  for ( i = 0; i < width*height; i++ )
+  {
+    labels[i]   = -1;
+    modePointCounts[i] =  0;
+  }
+
+  //Traverse the image labeling each new region encountered
+  int k, label = -1;
+  for ( i = 0; i < height*width; i++ )
+  {
+    //if this region has not yet been labeled - label it
+    if ( labels[i] < 0 )
+    {
+      //assign new label to this region
+      labels[i] = ++label;
+
+      //copy region color into modes
+      for ( k = 0; k < N; k++ )
+        modes[ ( N*label ) +k] = LUV_data[ ( N*i ) +k];
+//    modes[(N*label)+k] = (float)(LUV_data[(N*i)+k]);
+
+      //populate labels with label for this specified region
+      //calculating modePointCounts[label]...
+      Fill ( i, label );
+    }
+  }
+
+  //calculate region count using label
+  regionCount = label + 1;
+
+  //done.
+  return;
+}
+
+/*******************************************************/
+/*Fill                                                 */
+/*******************************************************/
+/*Given a region seed and a region label, Fill uses    */
+/*the region seed to perform an eight-connected fill   */
+/*for the specified region, labeling all pixels con-   */
+/*tained by the region with the specified label:       */
+/*label.                                               */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - regionLoc is a region seed - a pixel that is */
+/*        identified as being part of the region       */
+/*        labled using the label, label.               */
+/*Post:                                                */
+/*      - all pixels belonging to the region specified */
+/*        by regionLoc (having the same integer LUV    */
+/*        value specified by LUV_data) are classified  */
+/*        as one region by labeling each pixel in the  */
+/*        image clasification structure using label    */
+/*        via an eight-connected fill.                 */
+/*******************************************************/
+
+void msImageProcessor::Fill ( int regionLoc, int label )
+{
+
+  //declare variables
+  int i, k, neighLoc, neighborsFound, imageSize = width * height;
+
+  //Fill region starting at region location
+  //using labels...
+
+  //initialzie indexTable
+  int index  = 0;
+  indexTable[0] = regionLoc;
+
+  //increment mode point counts for this region to
+  //indicate that one pixel belongs to this region
+  modePointCounts[label]++;
+
+  while ( true )
+  {
+
+    //assume no neighbors will be found
+    neighborsFound = 0;
+
+    //check the eight connected neighbors at regionLoc -
+    //if a pixel has similar color to that located at
+    //regionLoc then declare it as part of this region
+    for ( i = 0; i < 8; i++ )
+    {
+      // no need
+      /*
+      //if at boundary do not check certain neighbors because
+      //they do not exist...
+      if((regionLoc%width == 0)&&((i == 3)||(i == 4)||(i == 5)))
+      continue;
+      if((regionLoc%(width-1) == 0)&&((i == 0)||(i == 1)||(i == 7)))
+      continue;
+      */
+
+      //check bounds and if neighbor has been already labeled
+      neighLoc   = regionLoc + neigh[i];
+      if ( ( neighLoc >= 0 ) && ( neighLoc < imageSize ) && ( labels[neighLoc] < 0 ) )
+      {
+        for ( k = 0; k < N; k++ )
+        {
+//     if(LUV_data[(regionLoc*N)+k] != LUV_data[(neighLoc*N)+k])
+          if ( fabs ( LUV_data[ ( regionLoc*N ) +k] - LUV_data[ ( neighLoc*N ) +k] ) >= LUV_treshold )
+            break;
+        }
+
+        //neighbor i belongs to this region so label it and
+        //place it onto the index table buffer for further
+        //processing
+        if ( k == N )
+        {
+          //assign label to neighbor i
+          labels[neighLoc] = label;
+
+          //increment region point count
+          modePointCounts[label]++;
+
+          //place index of neighbor i onto the index tabel buffer
+          indexTable[++index] = neighLoc;
+
+          //indicate that a neighboring region pixel was
+          //identified
+          neighborsFound = 1;
+        }
+      }
+    }
+
+    //check the indexTable to see if there are any more
+    //entries to be explored - if so explore them, otherwise
+    //exit the loop - we are finished
+    if ( neighborsFound )
+      regionLoc = indexTable[index];
+    else if ( index > 1 )
+      regionLoc = indexTable[--index];
+    else
+      break; //fill complete
+  }
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\*/
+/*  Image Pruning */
+/*\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Build Region Adjacency Matrix                        */
+/*******************************************************/
+/*Constructs a region adjacency matrix.                */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - the classification data structure has been   */
+/*        constructed.                                 */
+/*Post:                                                */
+/*      - a region adjacency matrix has been built     */
+/*        using the classification data structure.     */
+/*******************************************************/
+
+void msImageProcessor::BuildRAM ( void )
+{
+
+  //Allocate memory for region adjacency matrix if it hasn't already been allocated
+  if ( ( !raList ) && ( ( ! ( raList = new RAList [regionCount] ) ) || ( ! ( raPool = new RAList [NODE_MULTIPLE*regionCount] ) ) ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Allocate", ( char* ) "Not enough memory." );
+    return;
+  }
+
+  //initialize the region adjacency list
+  int i;
+  for ( i = 0; i < regionCount; i++ )
+  {
+    raList[i].edgeStrength  = 0;
+    raList[i].edgePixelCount = 0;
+    raList[i].label    = i;
+    raList[i].next    = NULL;
+  }
+
+  //initialize RAM free list
+  freeRAList = raPool;
+  for ( i = 0; i < NODE_MULTIPLE*regionCount - 1; i++ )
+  {
+    raPool[i].edgeStrength  = 0;
+    raPool[i].edgePixelCount = 0;
+    raPool[i].next = &raPool[i+1];
+  }
+  raPool[NODE_MULTIPLE*regionCount-1].next = NULL;
+
+  //traverse the labeled image building
+  //the RAM by looking to the right of
+  //and below the current pixel location thus
+  //determining if a given region is adjacent
+  //to another
+  int  j, curLabel, rightLabel, bottomLabel, exists;
+  RAList *raNode1, *raNode2, *oldRAFreeList;
+  for ( i = 0; i < height - 1; i++ )
+  {
+    //check the right and below neighbors
+    //for pixel locations whose x < width - 1
+    for ( j = 0; j < width - 1; j++ )
+    {
+      //calculate pixel labels
+      curLabel = labels[i*width+j    ]; //current pixel
+      rightLabel = labels[i*width+j+1  ]; //right   pixel
+      bottomLabel = labels[ ( i+1 ) *width+j]; //bottom  pixel
+
+      //check to the right, if the label of
+      //the right pixel is not the same as that
+      //of the current one then region[j] and region[j+1]
+      //are adjacent to one another - update the RAM
+      if ( curLabel != rightLabel )
+      {
+        //obtain RAList object from region adjacency free
+        //list
+        raNode1   = freeRAList;
+        raNode2   = freeRAList->next;
+
+        //keep a pointer to the old region adj. free
+        //list just in case nodes already exist in respective
+        //region lists
+        oldRAFreeList = freeRAList;
+
+        //update region adjacency free list
+        freeRAList  = freeRAList->next->next;
+
+        //populate RAList nodes
+        raNode1->label = curLabel;
+        raNode2->label = rightLabel;
+
+        //insert nodes into the RAM
+        exists   = 0;
+        raList[curLabel  ].Insert ( raNode2 );
+        exists   = raList[rightLabel].Insert ( raNode1 );
+
+        //if the node already exists then place
+        //nodes back onto the region adjacency
+        //free list
+        if ( exists )
+          freeRAList = oldRAFreeList;
+
+      }
+
+      //check below, if the label of
+      //the bottom pixel is not the same as that
+      //of the current one then region[j] and region[j+width]
+      //are adjacent to one another - update the RAM
+      if ( curLabel != bottomLabel )
+      {
+        //obtain RAList object from region adjacency free
+        //list
+        raNode1   = freeRAList;
+        raNode2   = freeRAList->next;
+
+        //keep a pointer to the old region adj. free
+        //list just in case nodes already exist in respective
+        //region lists
+        oldRAFreeList = freeRAList;
+
+        //update region adjacency free list
+        freeRAList  = freeRAList->next->next;
+
+        //populate RAList nodes
+        raNode1->label = curLabel;
+        raNode2->label = bottomLabel;
+
+        //insert nodes into the RAM
+        exists   = 0;
+        raList[curLabel  ].Insert ( raNode2 );
+        exists   = raList[bottomLabel].Insert ( raNode1 );
+
+        //if the node already exists then place
+        //nodes back onto the region adjacency
+        //free list
+        if ( exists )
+          freeRAList = oldRAFreeList;
+
+      }
+
+    }
+
+    //check only to the bottom neighbors of the right boundary
+    //pixels...
+
+    //calculate pixel locations (j = width-1)
+    curLabel = labels[i*width+j    ]; //current pixel
+    bottomLabel = labels[ ( i+1 ) *width+j]; //bottom  pixel
+
+    //check below, if the label of
+    //the bottom pixel is not the same as that
+    //of the current one then region[j] and region[j+width]
+    //are adjacent to one another - update the RAM
+    if ( curLabel != bottomLabel )
+    {
+      //obtain RAList object from region adjacency free
+      //list
+      raNode1   = freeRAList;
+      raNode2   = freeRAList->next;
+
+      //keep a pointer to the old region adj. free
+      //list just in case nodes already exist in respective
+      //region lists
+      oldRAFreeList = freeRAList;
+
+      //update region adjacency free list
+      freeRAList  = freeRAList->next->next;
+
+      //populate RAList nodes
+      raNode1->label = curLabel;
+      raNode2->label = bottomLabel;
+
+      //insert nodes into the RAM
+      exists   = 0;
+      raList[curLabel  ].Insert ( raNode2 );
+      exists   = raList[bottomLabel].Insert ( raNode1 );
+
+      //if the node already exists then place
+      //nodes back onto the region adjacency
+      //free list
+      if ( exists )
+        freeRAList = oldRAFreeList;
+
+    }
+  }
+
+  //check only to the right neighbors of the bottom boundary
+  //pixels...
+
+  //check the right for pixel locations whose x < width - 1
+  for ( j = 0; j < width - 1; j++ )
+  {
+    //calculate pixel labels (i = height-1)
+    curLabel = labels[i*width+j    ]; //current pixel
+    rightLabel = labels[i*width+j+1  ]; //right   pixel
+
+    //check to the right, if the label of
+    //the right pixel is not the same as that
+    //of the current one then region[j] and region[j+1]
+    //are adjacent to one another - update the RAM
+    if ( curLabel != rightLabel )
+    {
+      //obtain RAList object from region adjacency free
+      //list
+      raNode1   = freeRAList;
+      raNode2   = freeRAList->next;
+
+      //keep a pointer to the old region adj. free
+      //list just in case nodes already exist in respective
+      //region lists
+      oldRAFreeList = freeRAList;
+
+      //update region adjacency free list
+      freeRAList  = freeRAList->next->next;
+
+      //populate RAList nodes
+      raNode1->label = curLabel;
+      raNode2->label = rightLabel;
+
+      //insert nodes into the RAM
+      exists   = 0;
+      raList[curLabel  ].Insert ( raNode2 );
+      exists   = raList[rightLabel].Insert ( raNode1 );
+
+      //if the node already exists then place
+      //nodes back onto the region adjacency
+      //free list
+      if ( exists )
+        freeRAList = oldRAFreeList;
+
+    }
+
+  }
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Destroy Region Adjacency Matrix                      */
+/*******************************************************/
+/*Destroy a region adjacency matrix.                   */
+/*******************************************************/
+/*Post:                                                */
+/*      - the region adjacency matrix has been destr-  */
+/*        oyed: (1) its memory has been de-allocated,  */
+/*        (2) the RAM structure has been initialize    */
+/*        for re-use.                                  */
+/*******************************************************/
+
+void msImageProcessor::DestroyRAM ( void )
+{
+
+  //de-allocate memory for region adjaceny list
+  if ( raList )    delete [] raList;
+  if ( raPool )    delete [] raPool;
+
+  //initialize region adjacency matrix
+  raList    = NULL;
+  freeRAList   = NULL;
+  raPool    = NULL;
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Transitive Closure                                   */
+/*******************************************************/
+/*Applies transitive closure to the RAM updating       */
+/*labels, modes and modePointCounts to reflect the new */
+/*set of merged regions resulting from transitive clo- */
+/*sure.                                                */
+/*******************************************************/
+/*Post:                                                */
+/*      - transitive closure has been applied to the   */
+/*        regions classified by the RAM and labels,    */
+/*        modes and modePointCounts have been updated  */
+/*        to reflect the new set of mergd regions res- */
+/*        ulting from transitive closure.              */
+/*******************************************************/
+
+void msImageProcessor::TransitiveClosure ( void )
+{
+
+  //Step (1):
+
+  // Build RAM using classifiction structure originally
+  // generated by the method GridTable::Connect()
+  BuildRAM();
+
+  //Step (1a):
+  //Compute weights of weight graph using confidence map
+  //(if defined)
+  if ( weightMapDefined ) ComputeEdgeStrengths();
+
+  //Step (2):
+
+  //Treat each region Ri as a disjoint set:
+
+  // - attempt to join Ri and Rj for all i != j that are neighbors and
+  //   whose associated modes are a normalized distance of < 0.5 from one
+  //   another
+
+  // - the label of each region in the raList is treated as a pointer to the
+  //   canonical element of that region (e.g. raList[i], initially has raList[i].label = i,
+  //   namely each region is initialized to have itself as its canonical element).
+
+  //Traverse RAM attempting to join raList[i] with its neighbors...
+  int  i, iCanEl, neighCanEl;
+  float threshold;
+  RAList *neighbor;
+  for ( i = 0; i < regionCount; i++ )
+  {
+    //aquire first neighbor in region adjacency list pointed to
+    //by raList[i]
+    neighbor = raList[i].next;
+
+    //compute edge strenght threshold using global and local
+    //epsilon
+    if ( epsilon > raList[i].edgeStrength )
+      threshold   = epsilon;
+    else
+      threshold   = raList[i].edgeStrength;
+
+    //traverse region adjacency list of region i, attempting to join
+    //it with regions whose mode is a normalized distance < 0.5 from
+    //that of region i...
+    while ( neighbor )
+    {
+      //attempt to join region and neighbor...
+      if ( ( InWindow ( i, neighbor->label ) ) && ( neighbor->edgeStrength < epsilon ) )
+      {
+        //region i and neighbor belong together so join them
+        //by:
+
+        // (1) find the canonical element of region i
+        iCanEl  = i;
+        while ( raList[iCanEl].label != iCanEl )
+          iCanEl  = raList[iCanEl].label;
+
+        // (2) find the canonical element of neighboring region
+        neighCanEl = neighbor->label;
+        while ( raList[neighCanEl].label != neighCanEl )
+          neighCanEl = raList[neighCanEl].label;
+
+        // if the canonical elements of are not the same then assign
+        // the canonical element having the smaller label to be the parent
+        // of the other region...
+        if ( iCanEl < neighCanEl )
+          raList[neighCanEl].label = iCanEl;
+        else
+        {
+          //must replace the canonical element of previous
+          //parent as well
+          raList[raList[iCanEl].label].label = neighCanEl;
+
+          //re-assign canonical element
+          raList[iCanEl].label    = neighCanEl;
+        }
+      }
+
+      //check the next neighbor...
+      neighbor = neighbor->next;
+
+    }
+  }
+
+  // Step (3):
+
+  // Level binary trees formed by canonical elements
+  for ( i = 0; i < regionCount; i++ )
+  {
+    iCanEl = i;
+    while ( raList[iCanEl].label != iCanEl )
+      iCanEl = raList[iCanEl].label;
+    raList[i].label = iCanEl;
+  }
+
+  // Step (4):
+
+  //Traverse joint sets, relabeling image.
+
+  // (a)
+
+  // Accumulate modes and re-compute point counts using canonical
+  // elements generated by step 2.
+
+  //allocate memory for mode and point count temporary buffers...
+  float *modes_buffer = new float [N*regionCount];
+  int  *MPC_buffer  = new int [regionCount];
+
+  //initialize buffers to zero
+  for ( i = 0; i < regionCount; i++ )
+    MPC_buffer[i] = 0;
+  for ( i = 0; i < N*regionCount; i++ )
+    modes_buffer[i] = 0;
+
+  //traverse raList accumulating modes and point counts
+  //using canoncial element information...
+  int k, iMPC;
+  for ( i = 0; i < regionCount; i++ )
+  {
+
+    //obtain canonical element of region i
+    iCanEl = raList[i].label;
+
+    //obtain mode point count of region i
+    iMPC = modePointCounts[i];
+
+    //accumulate modes_buffer[iCanEl]
+    for ( k = 0; k < N; k++ )
+      modes_buffer[ ( N*iCanEl ) +k] += iMPC * modes[ ( N*i ) +k];
+
+    //accumulate MPC_buffer[iCanEl]
+    MPC_buffer[iCanEl] += iMPC;
+
+  }
+
+  // (b)
+
+  // Re-label new regions of the image using the canonical
+  // element information generated by step (2)
+
+  // Also use this information to compute the modes of the newly
+  // defined regions, and to assign new region point counts in
+  // a consecute manner to the modePointCounts array
+
+  //allocate memory for label buffer
+  int *label_buffer = new int [regionCount];
+
+  //initialize label buffer to -1
+  for ( i = 0; i < regionCount; i++ )
+    label_buffer[i] = -1;
+
+  //traverse raList re-labeling the regions
+  int label = -1;
+  for ( i = 0; i < regionCount; i++ )
+  {
+    //obtain canonical element of region i
+    iCanEl = raList[i].label;
+    if ( label_buffer[iCanEl] < 0 )
+    {
+      //assign a label to the new region indicated by canonical
+      //element of i
+      label_buffer[iCanEl] = ++label;
+
+      //recompute mode storing the result in modes[label]...
+      iMPC = MPC_buffer[iCanEl];
+      for ( k = 0; k < N; k++ )
+        modes[ ( N*label ) +k] = ( modes_buffer[ ( N*iCanEl ) +k] ) / ( iMPC );
+
+      //assign a corresponding mode point count for this region into
+      //the mode point counts array using the MPC buffer...
+      modePointCounts[label] = MPC_buffer[iCanEl];
+    }
+  }
+
+  //re-assign region count using label counter
+  //int oldRegionCount = regionCount;
+  regionCount = label + 1;
+
+  // (c)
+
+  // Use the label buffer to reconstruct the label map, which specified
+  // the new image given its new regions calculated above
+
+  for ( i = 0; i < height*width; i++ )
+    labels[i] = label_buffer[raList[labels[i]].label];
+
+  //de-allocate memory
+  delete [] modes_buffer;
+  delete [] MPC_buffer;
+  delete [] label_buffer;
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Compute Edge Strengths                               */
+/*******************************************************/
+/*Computes the a weight for each link in the region    */
+/*graph maintined by the RAM, resulting in a weighted  */
+/*graph in which the weights consist of a confidence   */
+/*between zero and one indicating if the regions are   */
+/*separated by a strong or weak edge.                  */
+/*******************************************************/
+/*Post:                                                */
+/*      - an edge strength has been computed between   */
+/*        each region of the image and placed as a     */
+/*        weight in the RAM to be used during transi-  */
+/*        tive closure.                                */
+/*******************************************************/
+
+void msImageProcessor::ComputeEdgeStrengths ( void )
+{
+
+  //initialize visit table - used to keep track
+  //of which pixels have already been visited such
+  //as not to contribute their strength value to
+  //a boundary sum multiple times...
+  memset ( visitTable, 0, L*sizeof ( unsigned char ) );
+
+  //traverse labeled image computing edge strengths
+  //(excluding image boundary)...
+  int    x, y, dp, curLabel, rightLabel, bottomLabel;
+  RAList *curRegion;
+  for ( y = 1; y < height - 1; y++ )
+  {
+    for ( x = 1; x < width - 1; x++ )
+    {
+      //compute data point location using x and y
+      dp = y * width + x;
+
+      //obtain labels at different pixel locations
+      curLabel = labels[dp      ]; //current pixel
+      rightLabel = labels[dp+1    ]; //right   pixel
+      bottomLabel = labels[dp+width]; //bottom  pixel
+
+      //check right and bottom neighbor to see if there is a
+      //change in label then we are at an edge therefore record
+      //the edge strength at this edge accumulating its value
+      //in the RAM...
+      if ( curLabel != rightLabel )
+      {
+        //traverse into RAM...
+        curRegion = &raList[curLabel];
+        while ( ( curRegion ) && ( curRegion->label != rightLabel ) )
+          curRegion = curRegion->next;
+
+        //this should not occur...
+        assert ( curRegion );
+
+        //accumulate edge strength
+        curRegion->edgeStrength   += weightMap[dp] + weightMap[dp+1];
+        curRegion->edgePixelCount += 2;
+      }
+
+      if ( curLabel != bottomLabel )
+      {
+        //traverse into RAM...
+        curRegion = &raList[curLabel];
+        while ( ( curRegion ) && ( curRegion->label != bottomLabel ) )
+          curRegion = curRegion->next;
+
+        //this should not occur...
+        assert ( curRegion );
+
+        //accumulate edge strength
+        if ( curLabel == rightLabel )
+        {
+          curRegion->edgeStrength   += weightMap[dp] + weightMap[dp+width];
+          curRegion->edgePixelCount += 2;
+        }
+        else
+        {
+          curRegion->edgeStrength   += weightMap[dp+width];
+          curRegion->edgePixelCount += 1;
+        }
+
+      }
+    }
+  }
+
+  //compute strengths using accumulated strengths obtained above...
+  RAList *neighborRegion;
+  float edgeStrength;
+  int  edgePixelCount;
+  for ( x = 0; x < regionCount; x++ )
+  {
+    //traverse the region list of the current region
+    curRegion = &raList[x];
+    curRegion = curRegion->next;
+    while ( curRegion )
+    {
+      //with the assumption that regions having a smaller
+      //label in the current region list have already
+      //had their edge strengths computed, only compute
+      //edge strengths for the regions whose label is greater
+      //than x, the current region (region list) under
+      //consideration...
+      curLabel = curRegion->label;
+      if ( curLabel > x )
+      {
+        //obtain pointer to the element identifying the
+        //current region in the neighbors region list...
+        neighborRegion = &raList[curLabel];
+        while ( ( neighborRegion ) && ( neighborRegion->label != x ) )
+          neighborRegion = neighborRegion->next;
+
+        //this should not occur...
+        assert ( neighborRegion );
+
+        //compute edge strengths using accumulated confidence
+        //value and pixel count
+        if ( ( edgePixelCount = curRegion->edgePixelCount + neighborRegion->edgePixelCount ) != 0 )
+        {
+          //compute edge strength
+          edgeStrength = curRegion->edgeStrength + neighborRegion->edgeStrength;
+          edgeStrength /= edgePixelCount;
+
+          //store edge strength and pixel count for corresponding regions
+          curRegion->edgeStrength  = neighborRegion->edgeStrength  = edgeStrength;
+          curRegion->edgePixelCount = neighborRegion->edgePixelCount = edgePixelCount;
+        }
+      }
+
+      //traverse to the next region in the region adjacency list
+      //of the current region x
+      curRegion = curRegion->next;
+
+    }
+  }
+
+  //compute average edge strength amongst the edges connecting
+  //it to each of its neighbors
+  int numNeighbors;
+  for ( x = 0; x < regionCount; x++ )
+  {
+    //traverse the region list of the current region
+    //accumulating weights
+    curRegion  = &raList[x];
+    curRegion  = curRegion->next;
+    edgeStrength = 0;
+    numNeighbors = 0;
+    while ( curRegion )
+    {
+      numNeighbors++;
+      edgeStrength   += curRegion->edgeStrength;
+      curRegion  = curRegion->next;
+    }
+
+    //divide by the number of regions connected
+    //to the current region
+    if ( numNeighbors ) edgeStrength /= numNeighbors;
+
+    //store the result in the raList for region
+    //x
+    raList[x].edgeStrength = edgeStrength;
+  }
+
+  //traverse raList and output the resulting list
+  //to a file
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Prune                                                */
+/*******************************************************/
+/*Prunes regions from the image whose pixel density    */
+/*is less than a specified threshold.                  */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - minRegion is the minimum allowable pixel de- */
+/*        nsity a region may have without being pruned */
+/*        from the image                               */
+/*Post:                                                */
+/*      - regions whose pixel density is less than     */
+/*        or equal to minRegion have been pruned from  */
+/*        the image.                                   */
+/*******************************************************/
+
+void msImageProcessor::Prune ( int minRegion )
+{
+
+  //Allocate Memory for temporary buffers...
+
+  //allocate memory for mode and point count temporary buffers...
+  float *modes_buffer = new float [N*regionCount];
+  int  *MPC_buffer  = new int [regionCount];
+
+  //allocate memory for label buffer
+  int *label_buffer  = new int [regionCount];
+
+  //Declare variables
+  int  i, k, candidate, iCanEl, neighCanEl, iMPC, label, oldRegionCount, minRegionCount;
+  double minSqDistance, neighborDistance;
+  RAList *neighbor;
+
+  //Apply pruning algorithm to classification structure, removing all regions whose area
+  //is under the threshold area minRegion (pixels)
+  do
+  {
+    //Assume that no region has area under threshold area  of
+    minRegionCount = 0;
+
+    //Step (1):
+
+    // Build RAM using classifiction structure originally
+    // generated by the method GridTable::Connect()
+    BuildRAM();
+
+    // Step (2):
+
+    // Traverse the RAM joining regions whose area is less than minRegion (pixels)
+    // with its respective candidate region.
+
+    // A candidate region is a region that displays the following properties:
+
+    // - it is adjacent to the region being pruned
+
+    //  - the distance of its mode is a minimum to that of the region being pruned
+    //    such that or it is the only adjacent region having an area greater than
+    //    minRegion
+
+    for ( i = 0; i < regionCount; i++ )
+    {
+      //if the area of the ith region is less than minRegion
+      //join it with its candidate region...
+
+      //*******************************************************************************
+
+      //Note: Adjust this if statement if a more sophisticated pruning criterion
+      //      is desired. Basically in this step a region whose area is less than
+      //      minRegion is pruned by joining it with its "closest" neighbor (in color).
+      //      Therefore, by placing a different criterion for fusing a region the
+      //      pruning method may be altered to implement a more sophisticated algorithm.
+
+      //*******************************************************************************
+
+      if ( modePointCounts[i] < minRegion )
+      {
+        //update minRegionCount to indicate that a region
+        //having area less than minRegion was found
+        minRegionCount++;
+
+        //obtain a pointer to the first region in the
+        //region adjacency list of the ith region...
+        neighbor = raList[i].next;
+
+        //calculate the distance between the mode of the ith
+        //region and that of the neighboring region...
+        candidate  = neighbor->label;
+        minSqDistance = SqDistance ( i, candidate );
+
+        //traverse region adjacency list of region i and select
+        //a candidate region
+        neighbor = neighbor->next;
+        while ( neighbor )
+        {
+
+          //calculate the square distance between region i
+          //and current neighbor...
+          neighborDistance = SqDistance ( i, neighbor->label );
+
+          //if this neighbors square distance to region i is less
+          //than minSqDistance, then select this neighbor as the
+          //candidate region for region i
+          if ( neighborDistance < minSqDistance )
+          {
+            minSqDistance = neighborDistance;
+            candidate  = neighbor->label;
+          }
+
+          //traverse region list of region i
+          neighbor = neighbor->next;
+
+        }
+
+        //join region i with its candidate region:
+
+        // (1) find the canonical element of region i
+        iCanEl  = i;
+        while ( raList[iCanEl].label != iCanEl )
+          iCanEl  = raList[iCanEl].label;
+
+        // (2) find the canonical element of neighboring region
+        neighCanEl = candidate;
+        while ( raList[neighCanEl].label != neighCanEl )
+          neighCanEl = raList[neighCanEl].label;
+
+        // if the canonical elements of are not the same then assign
+        // the canonical element having the smaller label to be the parent
+        // of the other region...
+        if ( iCanEl < neighCanEl )
+          raList[neighCanEl].label = iCanEl;
+        else
+        {
+          //must replace the canonical element of previous
+          //parent as well
+          raList[raList[iCanEl].label].label = neighCanEl;
+
+          //re-assign canonical element
+          raList[iCanEl].label    = neighCanEl;
+        }
+      }
+    }
+
+    // Step (3):
+
+    // Level binary trees formed by canonical elements
+    for ( i = 0; i < regionCount; i++ )
+    {
+      iCanEl = i;
+      while ( raList[iCanEl].label != iCanEl )
+        iCanEl = raList[iCanEl].label;
+      raList[i].label = iCanEl;
+    }
+
+    // Step (4):
+
+    //Traverse joint sets, relabeling image.
+
+    // Accumulate modes and re-compute point counts using canonical
+    // elements generated by step 2.
+
+    //initialize buffers to zero
+    for ( i = 0; i < regionCount; i++ )
+      MPC_buffer[i] = 0;
+    for ( i = 0; i < N*regionCount; i++ )
+      modes_buffer[i] = 0;
+
+    //traverse raList accumulating modes and point counts
+    //using canoncial element information...
+    for ( i = 0; i < regionCount; i++ )
+    {
+
+      //obtain canonical element of region i
+      iCanEl = raList[i].label;
+
+      //obtain mode point count of region i
+      iMPC = modePointCounts[i];
+
+      //accumulate modes_buffer[iCanEl]
+      for ( k = 0; k < N; k++ )
+        modes_buffer[ ( N*iCanEl ) +k] += iMPC * modes[ ( N*i ) +k];
+
+      //accumulate MPC_buffer[iCanEl]
+      MPC_buffer[iCanEl] += iMPC;
+
+    }
+
+    // (b)
+
+    // Re-label new regions of the image using the canonical
+    // element information generated by step (2)
+
+    // Also use this information to compute the modes of the newly
+    // defined regions, and to assign new region point counts in
+    // a consecute manner to the modePointCounts array
+
+    //initialize label buffer to -1
+    for ( i = 0; i < regionCount; i++ )
+      label_buffer[i] = -1;
+
+    //traverse raList re-labeling the regions
+    label = -1;
+    for ( i = 0; i < regionCount; i++ )
+    {
+      //obtain canonical element of region i
+      iCanEl = raList[i].label;
+      if ( label_buffer[iCanEl] < 0 )
+      {
+        //assign a label to the new region indicated by canonical
+        //element of i
+        label_buffer[iCanEl] = ++label;
+
+        //recompute mode storing the result in modes[label]...
+        iMPC = MPC_buffer[iCanEl];
+        for ( k = 0; k < N; k++ )
+          modes[ ( N*label ) +k] = ( modes_buffer[ ( N*iCanEl ) +k] ) / ( iMPC );
+
+        //assign a corresponding mode point count for this region into
+        //the mode point counts array using the MPC buffer...
+        modePointCounts[label] = MPC_buffer[iCanEl];
+      }
+    }
+
+    //re-assign region count using label counter
+    oldRegionCount = regionCount;
+    regionCount  = label + 1;
+
+    // (c)
+
+    // Use the label buffer to reconstruct the label map, which specified
+    // the new image given its new regions calculated above
+
+    for ( i = 0; i < height*width; i++ )
+      labels[i] = label_buffer[raList[labels[i]].label];
+
+
+  } while ( minRegionCount > 0 );
+
+  //de-allocate memory
+  delete [] modes_buffer;
+  delete [] MPC_buffer;
+  delete [] label_buffer;
+
+  //done.
+  return;
+
+}
+
+/*******************************************************/
+/*Define Boundaries                                    */
+/*******************************************************/
+/*Defines the boundaries for each region of the segm-  */
+/*ented image storing the result into a region list    */
+/*object.                                              */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - the image has been segmented and a classifi- */
+/*        cation structure has been created for this   */
+/*        image                                        */
+/*Post:                                                */
+/*      - the boundaries of the segmented image have   */
+/*        been defined and the boundaries of each reg- */
+/*        ion has been stored into a region list obj-  */
+/*        ect.                                         */
+/*******************************************************/
+
+void msImageProcessor::DefineBoundaries ( void )
+{
+
+  //declare and allocate memory for boundary map and count
+  int *boundaryMap, *boundaryCount;
+  if ( ( ! ( boundaryMap = new int [L] ) ) || ( ! ( boundaryCount = new int [regionCount] ) ) )
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "DefineBoundaries", ( char* ) "Not enough memory." );
+
+  //initialize boundary map and count
+  int i;
+  for ( i = 0; i < L; i++ )
+    boundaryMap[i]  = -1;
+  for ( i = 0; i < regionCount; i++ )
+    boundaryCount[i] =  0;
+
+  //initialize and declare total boundary count -
+  //the total number of boundary pixels present in
+  //the segmented image
+  int totalBoundaryCount = 0;
+
+  //traverse the image checking the right and bottom
+  //four connected neighbors of each pixel marking
+  //boundary map with the boundaries of each region and
+  //incrementing boundaryCount using the label information
+
+  //***********************************************************************
+  //***********************************************************************
+
+  int  j, label, dataPoint;
+
+  //first row (every pixel is a boundary pixel)
+  for ( i = 0; i < width; i++ )
+  {
+    boundaryMap[i]  = label = labels[i];
+    boundaryCount[label]++;
+    totalBoundaryCount++;
+  }
+
+  //define boundaries for all rows except for the first
+  //and last one...
+  for ( i = 1; i < height - 1; i++ )
+  {
+    //mark the first pixel in an image row as an image boundary...
+    dataPoint    = i * width;
+    boundaryMap[dataPoint] = label = labels[dataPoint];
+    boundaryCount[label]++;
+    totalBoundaryCount++;
+
+    for ( j = 1; j < width - 1; j++ )
+    {
+      //define datapoint and its right and bottom
+      //four connected neighbors
+      dataPoint  = i * width + j;
+
+      //check four connected neighbors if they are
+      //different this pixel is a boundary pixel
+      label = labels[dataPoint];
+      if ( ( label != labels[dataPoint-1] )    || ( label != labels[dataPoint+1] ) ||
+           ( label != labels[dataPoint-width] ) || ( label != labels[dataPoint+width] ) )
+      {
+        boundaryMap[dataPoint]  = label = labels[dataPoint];
+        boundaryCount[label]++;
+        totalBoundaryCount++;
+      }
+    }
+
+    //mark the last pixel in an image row as an image boundary...
+    dataPoint    = ( i + 1 ) * width - 1;
+    boundaryMap[dataPoint] = label = labels[dataPoint];
+    boundaryCount[label]++;
+    totalBoundaryCount++;
+
+  }
+
+  //last row (every pixel is a boundary pixel) (i = height-1)
+  register int start = ( height - 1 ) * width, stop = height * width;
+  for ( i = start; i < stop; i++ )
+  {
+    boundaryMap[i]  = label = labels[i];
+    boundaryCount[label]++;
+    totalBoundaryCount++;
+  }
+
+  //***********************************************************************
+  //***********************************************************************
+
+  //store boundary locations into a boundary buffer using
+  //boundary map and count
+
+  //***********************************************************************
+  //***********************************************************************
+
+  int *boundaryBuffer = new int [totalBoundaryCount], *boundaryIndex = new int [regionCount];
+
+  //use boundary count to initialize boundary index...
+  int counter = 0;
+  for ( i = 0; i < regionCount; i++ )
+  {
+    boundaryIndex[i] = counter;
+    counter      += boundaryCount[i];
+  }
+
+  //traverse boundary map placing the boundary pixel
+  //locations into the boundaryBuffer
+  for ( i = 0; i < L; i++ )
+  {
+    //if its a boundary pixel store it into
+    //the boundary buffer
+    if ( ( label = boundaryMap[i] ) >= 0 )
+    {
+      boundaryBuffer[boundaryIndex[label]] = i;
+      boundaryIndex[label]++;
+    }
+  }
+
+  //***********************************************************************
+  //***********************************************************************
+
+  //store the boundary locations stored by boundaryBuffer into
+  //the region list for each region
+
+  //***********************************************************************
+  //***********************************************************************
+
+  //destroy the old region list
+  if ( regionList ) delete regionList;
+
+  //create a new region list
+  if ( ! ( regionList = new RegionList ( regionCount, totalBoundaryCount, N ) ) )
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "DefineBoundaries", ( char* ) "Not enough memory." );
+
+  //add boundary locations for each region using the boundary
+  //buffer and boundary counts
+  counter = 0;
+  for ( i = 0; i < regionCount; i++ )
+  {
+    regionList->AddRegion ( i, boundaryCount[i], &boundaryBuffer[counter] );
+    counter += boundaryCount[i];
+  }
+
+  //***********************************************************************
+  //***********************************************************************
+
+  // dealocate local used memory
+  delete [] boundaryMap;
+  delete [] boundaryCount;
+  delete [] boundaryBuffer;
+  delete [] boundaryIndex;
+
+  //done.
+  return;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+/*  Image Data Searching/Distance Calculation */
+/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*In Window                                            */
+/*******************************************************/
+/*Returns true if the two specified data points are    */
+/*within rR of each other.                             */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - mode1 and mode2 are indeces into msRawData   */
+/*        specifying the modes of the pixels having    */
+/*        these indeces.                               */
+/*Post:                                                */
+/*      - true is returned if mode1 and mode2 are wi-  */
+/*        thin rR of one another, false is returned    */
+/*        otherwise.                                   */
+/*******************************************************/
+
+bool msImageProcessor::InWindow ( int mode1, int mode2 )
+{
+  int  k  = 1, s = 0, p;
+  double diff = 0, el;
+  while ( ( diff < 0.25 ) && ( k != kp ) ) // Partial Distortion Search
+  {
+    //Calculate distance squared of sub-space s
+    diff = 0;
+    for ( p = 0; p < P[k]; p++ )
+    {
+      el    = ( modes[mode1*N+p+s] - modes[mode2*N+p+s] ) / ( h[k] * offset[k] );
+      if ( ( !p ) && ( k == 1 ) && ( modes[mode1*N] > 80 ) )
+        diff += 4 * el * el;
+      else
+        diff += el * el;
+    }
+
+    //next subspace
+    s += P[k];
+    k++;
+  }
+  return ( bool ) ( diff < 0.25 );
+}
+
+/*******************************************************/
+/*Square Distance                                      */
+/*******************************************************/
+/*Computs the normalized square distance between two   */
+/*modes.                                               */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - mode1 and mode2 are indeces into the modes   */
+/*        array specifying two modes of the image      */
+/*Post:                                                */
+/*      - the normalized square distance between modes */
+/*        indexed by mode1 and mode2 has been calc-    */
+/*        ulated and the result has been returned.     */
+/*******************************************************/
+
+float msImageProcessor::SqDistance ( int mode1, int mode2 )
+{
+
+  int  k  = 1, s = 0, p;
+  float dist = 0, el;
+  for ( k = 1; k < kp; k++ )
+  {
+    //Calculate distance squared of sub-space s
+    for ( p = 0; p < P[k]; p++ )
+    {
+      el    = ( modes[mode1*N+p+s] - modes[mode2*N+p+s] ) / ( h[k] * offset[k] );
+      dist += el * el;
+    }
+
+    //next subspace
+    s += P[k];
+    k++;
+  }
+
+  //return normalized square distance between modes
+  //1 and 2
+  return dist;
+
+}
+
+/*/\/\/\/\/\/\/\/\/\/\*/
+/*  Memory Management */
+/*\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Initialize Output                                    */
+/*******************************************************/
+/*Allocates memory needed by the mean shift image pro- */
+/*cessor class output storage data structure.          */
+/*******************************************************/
+/*Post:                                                */
+/*      - the memory needed by the output storage      */
+/*        structure of this class has been (re-)allo-  */
+/*        cated.                                       */
+/*******************************************************/
+
+void msImageProcessor::InitializeOutput ( void )
+{
+
+  //De-allocate memory if output was defined for previous image
+  DestroyOutput();
+
+  //Allocate memory for msRawData (filtered image output)
+  if ( ! ( msRawData = new float [L*N] ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Allocate", ( char* ) "Not enough memory." );
+    return;
+  }
+
+  //Allocate memory used to store image modes and their corresponding regions...
+  if ( ( ! ( modes = new float [L* ( N+2 ) ] ) ) || ( ! ( labels = new int [L] ) ) || ( ! ( modePointCounts = new int [L] ) ) || ( ! ( indexTable = new int [L] ) ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Allocate", ( char* ) "Not enough memory" );
+    return;
+  }
+
+  //Allocate memory for integer modes used to perform connected components
+  //(image labeling)...
+// if(!(LUV_data = new int [N*L]))
+  if ( ! ( LUV_data = new float[N*L] ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Allocate", ( char* ) "Not enough memory" );
+    return;
+  }
+
+  //indicate that the class output storage structure has been defined
+  class_state.OUTPUT_DEFINED = true;
+
+}
+
+/*******************************************************/
+/*Destroy Output                                       */
+/*******************************************************/
+/*De-allocates memory needed by the mean shift image   */
+/*processor class output storage data structure.       */
+/*******************************************************/
+/*Post:                                                */
+/*      - the memory needed by the output storage      */
+/*        structure of this class has been de-alloc-   */
+/*        ated.                                        */
+/*      - the output storage structure has been init-  */
+/*        ialized for re-use.                          */
+/*******************************************************/
+
+void msImageProcessor::DestroyOutput ( void )
+{
+
+  //de-allocate memory for msRawData (filtered image output)
+  if ( msRawData )   delete [] msRawData;
+
+  //de-allocate memory used by output storage and image
+  //classification structure
+  if ( modes )    delete [] modes;
+  if ( labels )    delete [] labels;
+  if ( modePointCounts ) delete [] modePointCounts;
+  if ( indexTable )   delete [] indexTable;
+
+  //de-allocate memory for LUV_data
+  if ( LUV_data )   delete [] LUV_data;
+
+  //initialize data members for re-use...
+
+  //initialize output structures...
+  msRawData   = NULL;
+
+  //re-initialize classification structure
+  modes      = NULL;
+  labels      = NULL;
+  modePointCounts    = NULL;
+  regionCount     = 0;
+
+  //indicate that the output has been destroyed
+  class_state.OUTPUT_DEFINED = false;
+
+  //done.
+  return;
+
+}
+
+// NEW
+void msImageProcessor::NewOptimizedFilter1 ( float sigmaS, float sigmaR )
+{
+  // Declare Variables
+  int  iterationCount, i, j, k, modeCandidateX, modeCandidateY, modeCandidate_i;
+  double mvAbs, diff, el;
+
+  //make sure that a lattice height and width have
+  //been defined...
+  if ( !height )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "LFilter", ( char* ) "Lattice height and width are undefined." );
+    return;
+  }
+
+  //re-assign bandwidths to sigmaS and sigmaR
+  if ( ( ( h[0] = sigmaS ) <= 0 ) || ( ( h[1] = sigmaR ) <= 0 ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Segment", ( char* ) "sigmaS and/or sigmaR is zero or negative." );
+    return;
+  }
+
+  //define input data dimension with lattice
+  int lN = N + 2;
+
+  // Traverse each data point applying mean shift
+  // to each data point
+
+  // Allcocate memory for yk
+  double *yk  = new double [lN];
+
+  // Allocate memory for Mh
+  double *Mh  = new double [lN];
+
+  // let's use some temporary data
+  float* sdata;
+  sdata = new float[lN*L];
+
+  // copy the scaled data
+  int idxs, idxd;
+  idxs = idxd = 0;
+  if ( N == 3 )
+  {
+    for ( i = 0; i < L; i++ )
+    {
+      sdata[idxs++] = ( i % width ) / sigmaS;
+      sdata[idxs++] = ( i / width ) / sigmaS;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+    }
+  } else if ( N == 1 )
+  {
+    for ( i = 0; i < L; i++ )
+    {
+      sdata[idxs++] = ( i % width ) / sigmaS;
+      sdata[idxs++] = ( i / width ) / sigmaS;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+    }
+  } else
+  {
+    for ( i = 0; i < L; i++ )
+    {
+      sdata[idxs++] = ( i % width ) / sigmaS;
+      sdata[idxs++] = ( i / width ) / sigmaS;
+      for ( j = 0; j < N; j++ )
+        sdata[idxs++] = data[idxd++] / sigmaR;
+    }
+  }
+  // index the data in the 3d buckets (x, y, L)
+  int* buckets;
+  int* slist;
+  slist = new int[L];
+  int bucNeigh[27];
+
+  float sMins; // just for L
+  float sMaxs[3]; // for all
+  sMaxs[0] = width / sigmaS;
+  sMaxs[1] = height / sigmaS;
+  sMins = sMaxs[2] = sdata[2];
+  idxs = 2;
+  float cval;
+  for ( i = 0; i < L; i++ )
+  {
+    cval = sdata[idxs];
+    if ( cval < sMins )
+      sMins = cval;
+    else if ( cval > sMaxs[2] )
+      sMaxs[2] = cval;
+
+    idxs += lN;
+  }
+
+  int nBuck1, nBuck2, nBuck3;
+  int cBuck1, cBuck2, cBuck3, cBuck;
+  nBuck1 = ( int ) ( sMaxs[0] + 3 );
+  nBuck2 = ( int ) ( sMaxs[1] + 3 );
+  nBuck3 = ( int ) ( sMaxs[2] - sMins + 3 );
+  buckets = new int[nBuck1*nBuck2*nBuck3];
+
+  for ( i = 0; i < ( nBuck1*nBuck2*nBuck3 ); i++ )
+    buckets[i] = -1;
+
+  idxs = 0;
+
+  for ( i = 0; i < L; i++ )
+  {
+    // find bucket for current data and add it to the list
+    cBuck1 = ( int )  sdata[idxs] + 1;
+    cBuck2 = ( int )  sdata[idxs+1] + 1;
+    cBuck3 = ( int ) ( sdata[idxs+2] - sMins ) + 1;
+
+    idxs += lN;
+
+    cBuck = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+
+    slist[i] = buckets[cBuck];
+    buckets[cBuck] = i;
+  }
+  // init bucNeigh
+
+  idxd = 0;
+  for ( cBuck1 = -1; cBuck1 <= 1; cBuck1++ )
+  {
+    for ( cBuck2 = -1; cBuck2 <= 1; cBuck2++ )
+    {
+      for ( cBuck3 = -1; cBuck3 <= 1; cBuck3++ )
+      {
+        bucNeigh[idxd++] = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+      }
+    }
+  }
+
+  double wsuml, weight;
+  double hiLTr = 80.0 / sigmaR;
+  // done indexing/hashing
+
+
+  // Initialize mode table used for basin of attraction
+  memset ( modeTable, 0, width*height );
+
+  // proceed ...
+#ifdef PROMPT
+  printf ( ( char* ) "done.\nApplying mean shift (Using Lattice) ... " );
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\n 0%%" );
+#endif
+#endif
+
+
+  for ( i = 0; i < L; i++ )
+  {
+    // if a mode was already assigned to this data point
+    // then skip this point, otherwise proceed to
+    // find its mode by applying mean shift...
+    if ( modeTable[i] == 1 )
+      continue;
+
+    // initialize point list...
+    pointCount = 0;
+
+    // Assign window center (window centers are
+    // initialized by createLattice to be the point
+    // data[i])
+    idxs = i * lN;
+    for ( j = 0; j < lN; j++ )
+      yk[j] = sdata[idxs+j];
+
+    // Calculate the mean shift vector using the lattice
+    // LatticeMSVector(Mh, yk); // modify to new
+    /*****************************************************/
+    // Initialize mean shift vector
+
+    for ( j = 0; j < lN; j++ )
+      Mh[j] = 0;
+    wsuml = 0;
+    // uniformLSearch(Mh, yk_ptr); // modify to new
+    // find bucket of yk
+    cBuck1 = ( int ) yk[0] + 1;
+    cBuck2 = ( int ) yk[1] + 1;
+    cBuck3 = ( int ) ( yk[2] - sMins ) + 1;
+    cBuck = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+    for ( j = 0; j < 27; j++ )
+    {
+      idxd = buckets[cBuck+bucNeigh[j]];
+      // list parse, crt point is cHeadList
+      while ( idxd >= 0 )
+      {
+        idxs = lN * idxd;
+        // determine if inside search window
+        el = sdata[idxs+0] - yk[0];
+        diff = el * el;
+        el = sdata[idxs+1] - yk[1];
+        diff += el * el;
+
+        if ( diff < 1.0 )
+        {
+          el = sdata[idxs+2] - yk[2];
+          if ( yk[2] > hiLTr )
+            diff = 4 * el * el;
+          else
+            diff = el * el;
+
+          if ( N > 1 )
+          {
+            el = sdata[idxs+3] - yk[3];
+            diff += el * el;
+            el = sdata[idxs+4] - yk[4];
+            diff += el * el;
+          }
+
+          if ( diff < 1.0 )
+          {
+            weight = 1 - weightMap[idxd];
+            for ( k = 0; k < lN; k++ )
+              Mh[k] += weight * sdata[idxs+k];
+            wsuml += weight;
+          }
+        }
+        idxd = slist[idxd];
+      }
+    }
+    if ( wsuml > 0 )
+    {
+      for ( j = 0; j < lN; j++ )
+        Mh[j] = Mh[j] / wsuml - yk[j];
+    }
+    else
+    {
+      for ( j = 0; j < lN; j++ )
+        Mh[j] = 0;
+    }
+    /*****************************************************/
+    // Calculate its magnitude squared
+    //mvAbs = 0;
+    //for(j = 0; j < lN; j++)
+    // mvAbs += Mh[j]*Mh[j];
+    mvAbs = ( Mh[0] * Mh[0] + Mh[1] * Mh[1] ) * sigmaS * sigmaS;
+    if ( N == 3 )
+      mvAbs += ( Mh[2] * Mh[2] + Mh[3] * Mh[3] + Mh[4] * Mh[4] ) * sigmaR * sigmaR;
+    else
+      mvAbs += Mh[2] * Mh[2] * sigmaR * sigmaR;
+
+
+    // Keep shifting window center until the magnitude squared of the
+    // mean shift vector calculated at the window center location is
+    // under a specified threshold (Epsilon)
+
+    // NOTE: iteration count is for speed up purposes only - it
+    //       does not have any theoretical importance
+    iterationCount = 1;
+    while ( ( mvAbs >= EPSILON2 ) && ( iterationCount < LIMIT ) )
+    {
+
+      // Shift window location
+      for ( j = 0; j < lN; j++ )
+        yk[j] += Mh[j];
+
+      // check to see if the current mode location is in the
+      // basin of attraction...
+
+      // calculate the location of yk on the lattice
+      modeCandidateX = ( int ) ( sigmaS * yk[0] + 0.5 );
+      modeCandidateY = ( int ) ( sigmaS * yk[1] + 0.5 );
+      modeCandidate_i = modeCandidateY * width + modeCandidateX;
+
+      // if mvAbs != 0 (yk did indeed move) then check
+      // location basin_i in the mode table to see if
+      // this data point either:
+
+      // (1) has not been associated with a mode yet
+      //     (modeTable[basin_i] = 0), so associate
+      //     it with this one
+      //
+      // (2) it has been associated with a mode other
+      //     than the one that this data point is converging
+      //     to (modeTable[basin_i] = 1), so assign to
+      //     this data point the same mode as that of basin_i
+
+      if ( ( modeTable[modeCandidate_i] != 2 ) && ( modeCandidate_i != i ) )
+      {
+        // obtain the data point at basin_i to
+        // see if it is within h*TC_DIST_FACTOR of
+        // of yk
+        diff = 0;
+        idxs = lN * modeCandidate_i;
+        for ( k = 2; k < lN; k++ )
+        {
+          el = sdata[idxs+k] - yk[k];
+          diff += el * el;
+        }
+
+        // if the data point at basin_i is within
+        // a distance of h*TC_DIST_FACTOR of yk
+        // then depending on modeTable[basin_i] perform
+        // either (1) or (2)
+        if ( diff < TC_DIST_FACTOR )
+        {
+          // if the data point at basin_i has not
+          // been associated to a mode then associate
+          // it with the mode that this one will converge
+          // to
+          if ( modeTable[modeCandidate_i] == 0 )
+          {
+            // no mode associated yet so associate
+            // it with this one...
+            pointList[pointCount++]  = modeCandidate_i;
+            modeTable[modeCandidate_i] = 2;
+
+          } else
+          {
+
+            // the mode has already been associated with
+            // another mode, thererfore associate this one
+            // mode and the modes in the point list with
+            // the mode associated with data[basin_i]...
+
+            // store the mode info into yk using msRawData...
+            for ( j = 0; j < N; j++ )
+              yk[j+2] = msRawData[modeCandidate_i*N+j] / sigmaR;
+
+            // update mode table for this data point
+            // indicating that a mode has been associated
+            // with it
+            modeTable[i] = 1;
+
+            // indicate that a mode has been associated
+            // to this data point (data[i])
+            mvAbs = -1;
+
+            // stop mean shift calculation...
+            break;
+          }
+        }
+      }
+
+      // Calculate the mean shift vector at the new
+      // window location using lattice
+      // Calculate the mean shift vector using the lattice
+      // LatticeMSVector(Mh, yk); // modify to new
+      /*****************************************************/
+      // Initialize mean shift vector
+      for ( j = 0; j < lN; j++ )
+        Mh[j] = 0;
+      wsuml = 0;
+      // uniformLSearch(Mh, yk_ptr); // modify to new
+      // find bucket of yk
+      cBuck1 = ( int ) yk[0] + 1;
+      cBuck2 = ( int ) yk[1] + 1;
+      cBuck3 = ( int ) ( yk[2] - sMins ) + 1;
+      cBuck = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+      for ( j = 0; j < 27; j++ )
+      {
+        idxd = buckets[cBuck+bucNeigh[j]];
+        // list parse, crt point is cHeadList
+        while ( idxd >= 0 )
+        {
+          idxs = lN * idxd;
+          // determine if inside search window
+          el = sdata[idxs+0] - yk[0];
+          diff = el * el;
+          el = sdata[idxs+1] - yk[1];
+          diff += el * el;
+
+          if ( diff < 1.0 )
+          {
+            el = sdata[idxs+2] - yk[2];
+            if ( yk[2] > hiLTr )
+              diff = 4 * el * el;
+            else
+              diff = el * el;
+
+            if ( N > 1 )
+            {
+              el = sdata[idxs+3] - yk[3];
+              diff += el * el;
+              el = sdata[idxs+4] - yk[4];
+              diff += el * el;
+            }
+
+            if ( diff < 1.0 )
+            {
+              weight = 1 - weightMap[idxd];
+              for ( k = 0; k < lN; k++ )
+                Mh[k] += weight * sdata[idxs+k];
+              wsuml += weight;
+            }
+          }
+          idxd = slist[idxd];
+        }
+      }
+      if ( wsuml > 0 )
+      {
+        for ( j = 0; j < lN; j++ )
+          Mh[j] = Mh[j] / wsuml - yk[j];
+      }
+      else
+      {
+        for ( j = 0; j < lN; j++ )
+          Mh[j] = 0;
+      }
+      /*****************************************************/
+
+      // Calculate its magnitude squared
+      //mvAbs = 0;
+      //for(j = 0; j < lN; j++)
+      // mvAbs += Mh[j]*Mh[j];
+      mvAbs = ( Mh[0] * Mh[0] + Mh[1] * Mh[1] ) * sigmaS * sigmaS;
+      if ( N == 3 )
+        mvAbs += ( Mh[2] * Mh[2] + Mh[3] * Mh[3] + Mh[4] * Mh[4] ) * sigmaR * sigmaR;
+      else
+        mvAbs += Mh[2] * Mh[2] * sigmaR * sigmaR;
+
+      // Increment iteration count
+      iterationCount++;
+
+    }
+
+    // if a mode was not associated with this data point
+    // yet associate it with yk...
+    if ( mvAbs >= 0 )
+    {
+      // Shift window location
+      for ( j = 0; j < lN; j++ )
+        yk[j] += Mh[j];
+
+      // update mode table for this data point
+      // indicating that a mode has been associated
+      // with it
+      modeTable[i] = 1;
+
+    }
+
+    for ( k = 0; k < N; k++ )
+      yk[k+2] *= sigmaR;
+
+    // associate the data point indexed by
+    // the point list with the mode stored
+    // by yk
+    for ( j = 0; j < pointCount; j++ )
+    {
+      // obtain the point location from the
+      // point list
+      modeCandidate_i = pointList[j];
+
+      // update the mode table for this point
+      modeTable[modeCandidate_i] = 1;
+
+      //store result into msRawData...
+      for ( k = 0; k < N; k++ )
+        msRawData[N*modeCandidate_i+k] = ( float ) ( yk[k+2] );
+    }
+
+    //store result into msRawData...
+    for ( j = 0; j < N; j++ )
+      msRawData[N*i+j] = ( float ) ( yk[j+2] );
+
+    // Prompt user on progress
+#ifdef SHOW_PROGRESS
+    percent_complete = ( float ) ( i / ( float ) ( L ) ) * 100;
+    printf ( ( char* ) "\r%2d%%", ( int ) ( percent_complete + 0.5 ) );
+#endif
+
+    // Check to see if the algorithm has been halted
+    if ( ( i % PROGRESS_RATE == 0 ) && ( ( ErrorStatus = msSys.Progress ( ( float ) ( i / ( float ) ( L ) ) * ( float ) ( 0.8 ) ) ) ) == EL_HALT )
+      break;
+  }
+
+  // Prompt user that filtering is completed
+#ifdef PROMPT
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\r" );
+#endif
+  printf ( ( char* ) "done." );
+#endif
+  // de-allocate memory
+  delete [] buckets;
+  delete [] slist;
+  delete [] sdata;
+
+  delete [] yk;
+  delete [] Mh;
+  // done.
+  return;
+
+}
+
+// NEW
+void msImageProcessor::NewOptimizedFilter2 ( float sigmaS, float sigmaR )
+{
+  // Declare Variables
+  int  iterationCount, i, j, k, modeCandidateX, modeCandidateY, modeCandidate_i;
+  double mvAbs, diff, el;
+
+  //make sure that a lattice height and width have
+  //been defined...
+  if ( !height )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "LFilter", ( char* ) "Lattice height and width are undefined." );
+    return;
+  }
+
+  //re-assign bandwidths to sigmaS and sigmaR
+  if ( ( ( h[0] = sigmaS ) <= 0 ) || ( ( h[1] = sigmaR ) <= 0 ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Segment", ( char* ) "sigmaS and/or sigmaR is zero or negative." );
+    return;
+  }
+
+  //define input data dimension with lattice
+  int lN = N + 2;
+
+  // Traverse each data point applying mean shift
+  // to each data point
+
+  // Allcocate memory for yk
+  double *yk  = new double [lN];
+
+  // Allocate memory for Mh
+  double *Mh  = new double [lN];
+
+  // let's use some temporary data
+  float* sdata;
+  sdata = new float[lN*L];
+
+  // copy the scaled data
+  int idxs, idxd;
+  idxs = idxd = 0;
+  if ( N == 3 )
+  {
+    for ( i = 0; i < L; i++ )
+    {
+      sdata[idxs++] = ( i % width ) / sigmaS;
+      sdata[idxs++] = ( i / width ) / sigmaS;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+    }
+  } else if ( N == 1 )
+  {
+    for ( i = 0; i < L; i++ )
+    {
+      sdata[idxs++] = ( i % width ) / sigmaS;
+      sdata[idxs++] = ( i / width ) / sigmaS;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+    }
+  } else
+  {
+    for ( i = 0; i < L; i++ )
+    {
+      sdata[idxs++] = ( i % width ) / sigmaS;
+      sdata[idxs++] = ( i / width ) / sigmaS;
+      for ( j = 0; j < N; j++ )
+        sdata[idxs++] = data[idxd++] / sigmaR;
+    }
+  }
+  // index the data in the 3d buckets (x, y, L)
+  int* buckets;
+  int* slist;
+  slist = new int[L];
+  int bucNeigh[27];
+
+  float sMins; // just for L
+  float sMaxs[3]; // for all
+  sMaxs[0] = width / sigmaS;
+  sMaxs[1] = height / sigmaS;
+  sMins = sMaxs[2] = sdata[2];
+  idxs = 2;
+  float cval;
+  for ( i = 0; i < L; i++ )
+  {
+    cval = sdata[idxs];
+    if ( cval < sMins )
+      sMins = cval;
+    else if ( cval > sMaxs[2] )
+      sMaxs[2] = cval;
+
+    idxs += lN;
+  }
+
+  int nBuck1, nBuck2, nBuck3;
+  int cBuck1, cBuck2, cBuck3, cBuck;
+  nBuck1 = ( int ) ( sMaxs[0] + 3 );
+  nBuck2 = ( int ) ( sMaxs[1] + 3 );
+  nBuck3 = ( int ) ( sMaxs[2] - sMins + 3 );
+  buckets = new int[nBuck1*nBuck2*nBuck3];
+  for ( i = 0; i < ( nBuck1*nBuck2*nBuck3 ); i++ )
+    buckets[i] = -1;
+
+  idxs = 0;
+  for ( i = 0; i < L; i++ )
+  {
+    // find bucket for current data and add it to the list
+    cBuck1 = ( int ) sdata[idxs] + 1;
+    cBuck2 = ( int ) sdata[idxs+1] + 1;
+    cBuck3 = ( int ) ( sdata[idxs+2] - sMins ) + 1;
+    cBuck = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+
+    slist[i] = buckets[cBuck];
+    buckets[cBuck] = i;
+
+    idxs += lN;
+  }
+  // init bucNeigh
+  idxd = 0;
+  for ( cBuck1 = -1; cBuck1 <= 1; cBuck1++ )
+  {
+    for ( cBuck2 = -1; cBuck2 <= 1; cBuck2++ )
+    {
+      for ( cBuck3 = -1; cBuck3 <= 1; cBuck3++ )
+      {
+        bucNeigh[idxd++] = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+      }
+    }
+  }
+  double wsuml, weight;
+  double hiLTr = 80.0 / sigmaR;
+  // done indexing/hashing
+
+
+  // Initialize mode table used for basin of attraction
+  memset ( modeTable, 0, width*height );
+
+  // proceed ...
+#ifdef PROMPT
+  printf ( ( char* ) "done.\nApplying mean shift (Using Lattice) ... " );
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\n 0%%" );
+#endif
+#endif
+
+
+  for ( i = 0; i < L; i++ )
+  {
+    // if a mode was already assigned to this data point
+    // then skip this point, otherwise proceed to
+    // find its mode by applying mean shift...
+    if ( modeTable[i] == 1 )
+      continue;
+
+    // initialize point list...
+    pointCount = 0;
+
+    // Assign window center (window centers are
+    // initialized by createLattice to be the point
+    // data[i])
+    idxs = i * lN;
+    for ( j = 0; j < lN; j++ )
+      yk[j] = sdata[idxs+j];
+
+    // Calculate the mean shift vector using the lattice
+    // LatticeMSVector(Mh, yk); // modify to new
+    /*****************************************************/
+    // Initialize mean shift vector
+    for ( j = 0; j < lN; j++ )
+      Mh[j] = 0;
+    wsuml = 0;
+    // uniformLSearch(Mh, yk_ptr); // modify to new
+    // find bucket of yk
+    cBuck1 = ( int ) yk[0] + 1;
+    cBuck2 = ( int ) yk[1] + 1;
+    cBuck3 = ( int ) ( yk[2] - sMins ) + 1;
+    cBuck = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+    for ( j = 0; j < 27; j++ )
+    {
+      idxd = buckets[cBuck+bucNeigh[j]];
+      // list parse, crt point is cHeadList
+      while ( idxd >= 0 )
+      {
+        idxs = lN * idxd;
+        // determine if inside search window
+        el = sdata[idxs+0] - yk[0];
+        diff = el * el;
+        el = sdata[idxs+1] - yk[1];
+        diff += el * el;
+
+        if ( diff < 1.0 )
+        {
+          el = sdata[idxs+2] - yk[2];
+          if ( yk[2] > hiLTr )
+            diff = 4 * el * el;
+          else
+            diff = el * el;
+
+          if ( N > 1 )
+          {
+            el = sdata[idxs+3] - yk[3];
+            diff += el * el;
+            el = sdata[idxs+4] - yk[4];
+            diff += el * el;
+          }
+
+          if ( diff < 1.0 )
+          {
+            weight = 1 - weightMap[idxd];
+            for ( k = 0; k < lN; k++ )
+              Mh[k] += weight * sdata[idxs+k];
+            wsuml += weight;
+
+            //set basin of attraction mode table
+            if ( diff < speedThreshold )
+            {
+              if ( modeTable[idxd] == 0 )
+              {
+                pointList[pointCount++] = idxd;
+                modeTable[idxd] = 2;
+              }
+            }
+          }
+        }
+        idxd = slist[idxd];
+      }
+    }
+    if ( wsuml > 0 )
+    {
+      for ( j = 0; j < lN; j++ )
+        Mh[j] = Mh[j] / wsuml - yk[j];
+    }
+    else
+    {
+      for ( j = 0; j < lN; j++ )
+        Mh[j] = 0;
+    }
+    /*****************************************************/
+    // Calculate its magnitude squared
+    //mvAbs = 0;
+    //for(j = 0; j < lN; j++)
+    // mvAbs += Mh[j]*Mh[j];
+    mvAbs = ( Mh[0] * Mh[0] + Mh[1] * Mh[1] ) * sigmaS * sigmaS;
+    if ( N == 3 )
+      mvAbs += ( Mh[2] * Mh[2] + Mh[3] * Mh[3] + Mh[4] * Mh[4] ) * sigmaR * sigmaR;
+    else
+      mvAbs += Mh[2] * Mh[2] * sigmaR * sigmaR;
+
+
+    // Keep shifting window center until the magnitude squared of the
+    // mean shift vector calculated at the window center location is
+    // under a specified threshold (Epsilon)
+
+    // NOTE: iteration count is for speed up purposes only - it
+    //       does not have any theoretical importance
+    iterationCount = 1;
+    while ( ( mvAbs >= EPSILON2 ) && ( iterationCount < LIMIT ) )
+    {
+
+      // Shift window location
+      for ( j = 0; j < lN; j++ )
+        yk[j] += Mh[j];
+
+      // check to see if the current mode location is in the
+      // basin of attraction...
+
+      // calculate the location of yk on the lattice
+      modeCandidateX = ( int ) ( sigmaS * yk[0] + 0.5 );
+      modeCandidateY = ( int ) ( sigmaS * yk[1] + 0.5 );
+      modeCandidate_i = modeCandidateY * width + modeCandidateX;
+
+      // if mvAbs != 0 (yk did indeed move) then check
+      // location basin_i in the mode table to see if
+      // this data point either:
+
+      // (1) has not been associated with a mode yet
+      //     (modeTable[basin_i] = 0), so associate
+      //     it with this one
+      //
+      // (2) it has been associated with a mode other
+      //     than the one that this data point is converging
+      //     to (modeTable[basin_i] = 1), so assign to
+      //     this data point the same mode as that of basin_i
+
+      if ( ( modeTable[modeCandidate_i] != 2 ) && ( modeCandidate_i != i ) )
+      {
+        // obtain the data point at basin_i to
+        // see if it is within h*TC_DIST_FACTOR of
+        // of yk
+        diff = 0;
+        idxs = lN * modeCandidate_i;
+        for ( k = 2; k < lN; k++ )
+        {
+          el = sdata[idxs+k] - yk[k];
+          diff += el * el;
+        }
+
+        // if the data point at basin_i is within
+        // a distance of h*TC_DIST_FACTOR of yk
+        // then depending on modeTable[basin_i] perform
+        // either (1) or (2)
+        if ( diff < speedThreshold )
+        {
+          // if the data point at basin_i has not
+          // been associated to a mode then associate
+          // it with the mode that this one will converge
+          // to
+          if ( modeTable[modeCandidate_i] == 0 )
+          {
+            // no mode associated yet so associate
+            // it with this one...
+            pointList[pointCount++]  = modeCandidate_i;
+            modeTable[modeCandidate_i] = 2;
+
+          } else
+          {
+
+            // the mode has already been associated with
+            // another mode, thererfore associate this one
+            // mode and the modes in the point list with
+            // the mode associated with data[basin_i]...
+
+            // store the mode info into yk using msRawData...
+            for ( j = 0; j < N; j++ )
+              yk[j+2] = msRawData[modeCandidate_i*N+j] / sigmaR;
+
+            // update mode table for this data point
+            // indicating that a mode has been associated
+            // with it
+            modeTable[i] = 1;
+
+            // indicate that a mode has been associated
+            // to this data point (data[i])
+            mvAbs = -1;
+
+            // stop mean shift calculation...
+            break;
+          }
+        }
+      }
+
+      // Calculate the mean shift vector at the new
+      // window location using lattice
+      // Calculate the mean shift vector using the lattice
+      // LatticeMSVector(Mh, yk); // modify to new
+      /*****************************************************/
+      // Initialize mean shift vector
+      for ( j = 0; j < lN; j++ )
+        Mh[j] = 0;
+      wsuml = 0;
+      // uniformLSearch(Mh, yk_ptr); // modify to new
+      // find bucket of yk
+      cBuck1 = ( int ) yk[0] + 1;
+      cBuck2 = ( int ) yk[1] + 1;
+      cBuck3 = ( int ) ( yk[2] - sMins ) + 1;
+      cBuck = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+      for ( j = 0; j < 27; j++ )
+      {
+        idxd = buckets[cBuck+bucNeigh[j]];
+        // list parse, crt point is cHeadList
+        while ( idxd >= 0 )
+        {
+          idxs = lN * idxd;
+          // determine if inside search window
+          el = sdata[idxs+0] - yk[0];
+          diff = el * el;
+          el = sdata[idxs+1] - yk[1];
+          diff += el * el;
+
+          if ( diff < 1.0 )
+          {
+            el = sdata[idxs+2] - yk[2];
+            if ( yk[2] > hiLTr )
+              diff = 4 * el * el;
+            else
+              diff = el * el;
+
+            if ( N > 1 )
+            {
+              el = sdata[idxs+3] - yk[3];
+              diff += el * el;
+              el = sdata[idxs+4] - yk[4];
+              diff += el * el;
+            }
+
+            if ( diff < 1.0 )
+            {
+              weight = 1 - weightMap[idxd];
+              for ( k = 0; k < lN; k++ )
+                Mh[k] += weight * sdata[idxs+k];
+              wsuml += weight;
+
+              //set basin of attraction mode table
+              if ( diff < speedThreshold )
+              {
+                if ( modeTable[idxd] == 0 )
+                {
+                  pointList[pointCount++] = idxd;
+                  modeTable[idxd] = 2;
+                }
+              }
+
+            }
+          }
+          idxd = slist[idxd];
+        }
+      }
+      if ( wsuml > 0 )
+      {
+        for ( j = 0; j < lN; j++ )
+          Mh[j] = Mh[j] / wsuml - yk[j];
+      }
+      else
+      {
+        for ( j = 0; j < lN; j++ )
+          Mh[j] = 0;
+      }
+      /*****************************************************/
+
+      // Calculate its magnitude squared
+      //mvAbs = 0;
+      //for(j = 0; j < lN; j++)
+      // mvAbs += Mh[j]*Mh[j];
+      mvAbs = ( Mh[0] * Mh[0] + Mh[1] * Mh[1] ) * sigmaS * sigmaS;
+      if ( N == 3 )
+        mvAbs += ( Mh[2] * Mh[2] + Mh[3] * Mh[3] + Mh[4] * Mh[4] ) * sigmaR * sigmaR;
+      else
+        mvAbs += Mh[2] * Mh[2] * sigmaR * sigmaR;
+
+      // Increment iteration count
+      iterationCount++;
+
+    }
+
+    // if a mode was not associated with this data point
+    // yet associate it with yk...
+    if ( mvAbs >= 0 )
+    {
+      // Shift window location
+      for ( j = 0; j < lN; j++ )
+        yk[j] += Mh[j];
+
+      // update mode table for this data point
+      // indicating that a mode has been associated
+      // with it
+      modeTable[i] = 1;
+
+    }
+
+    for ( k = 0; k < N; k++ )
+      yk[k+2] *= sigmaR;
+
+    // associate the data point indexed by
+    // the point list with the mode stored
+    // by yk
+    for ( j = 0; j < pointCount; j++ )
+    {
+      // obtain the point location from the
+      // point list
+      modeCandidate_i = pointList[j];
+
+      // update the mode table for this point
+      modeTable[modeCandidate_i] = 1;
+
+      //store result into msRawData...
+      for ( k = 0; k < N; k++ )
+        msRawData[N*modeCandidate_i+k] = ( float ) ( yk[k+2] );
+    }
+
+    //store result into msRawData...
+    for ( j = 0; j < N; j++ )
+      msRawData[N*i+j] = ( float ) ( yk[j+2] );
+
+    // Prompt user on progress
+#ifdef SHOW_PROGRESS
+    percent_complete = ( float ) ( i / ( float ) ( L ) ) * 100;
+    printf ( ( char* ) "\r%2d%%", ( int ) ( percent_complete + 0.5 ) );
+#endif
+
+    // Check to see if the algorithm has been halted
+    if ( ( i % PROGRESS_RATE == 0 ) && ( ( ErrorStatus = msSys.Progress ( ( float ) ( i / ( float ) ( L ) ) * ( float ) ( 0.8 ) ) ) ) == EL_HALT )
+      break;
+  }
+
+  // Prompt user that filtering is completed
+#ifdef PROMPT
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\r" );
+#endif
+  printf ( ( char* ) "done." );
+#endif
+  // de-allocate memory
+  delete [] buckets;
+  delete [] slist;
+  delete [] sdata;
+
+  delete [] yk;
+  delete [] Mh;
+
+  // done.
+  return;
+
+}
+
+void msImageProcessor::NewNonOptimizedFilter ( float sigmaS, float sigmaR )
+{
+
+  // Declare Variables
+  int   iterationCount, i, j, k;
+  double mvAbs, diff, el;
+
+  //make sure that a lattice height and width have
+  //been defined...
+  if ( !height )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "LFilter", ( char* ) "Lattice height and width are undefined." );
+    return;
+  }
+
+  //re-assign bandwidths to sigmaS and sigmaR
+  if ( ( ( h[0] = sigmaS ) <= 0 ) || ( ( h[1] = sigmaR ) <= 0 ) )
+  {
+    ErrorHandler ( ( char* ) "msImageProcessor", ( char* ) "Segment", ( char* ) "sigmaS and/or sigmaR is zero or negative." );
+    return;
+  }
+
+  //define input data dimension with lattice
+  int lN = N + 2;
+
+  // Traverse each data point applying mean shift
+  // to each data point
+
+  // Allcocate memory for yk
+  double *yk  = new double [lN];
+
+  // Allocate memory for Mh
+  double *Mh  = new double [lN];
+
+  // let's use some temporary data
+  double* sdata;
+  sdata = new double[lN*L];
+
+  // copy the scaled data
+  int idxs, idxd;
+  idxs = idxd = 0;
+  if ( N == 3 )
+  {
+    for ( i = 0; i < L; i++ )
+    {
+      sdata[idxs++] = ( i % width ) / sigmaS;
+      sdata[idxs++] = ( i / width ) / sigmaS;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+    }
+  } else if ( N == 1 )
+  {
+    for ( i = 0; i < L; i++ )
+    {
+      sdata[idxs++] = ( i % width ) / sigmaS;
+      sdata[idxs++] = ( i / width ) / sigmaS;
+      sdata[idxs++] = data[idxd++] / sigmaR;
+    }
+  } else
+  {
+    for ( i = 0; i < L; i++ )
+    {
+      sdata[idxs++] = ( i % width ) / sigmaS;
+      sdata[idxs++] = ( i % width ) / sigmaS;
+      for ( j = 0; j < N; j++ )
+        sdata[idxs++] = data[idxd++] / sigmaR;
+    }
+  }
+  // index the data in the 3d buckets (x, y, L)
+  int* buckets;
+  int* slist;
+  slist = new int[L];
+  int bucNeigh[27];
+
+  double sMins; // just for L
+  double sMaxs[3]; // for all
+  sMaxs[0] = width / sigmaS;
+  sMaxs[1] = height / sigmaS;
+  sMins = sMaxs[2] = sdata[2];
+  idxs = 2;
+  double cval;
+  for ( i = 0; i < L; i++ )
+  {
+    cval = sdata[idxs];
+    if ( cval < sMins )
+      sMins = cval;
+    else if ( cval > sMaxs[2] )
+      sMaxs[2] = cval;
+
+    idxs += lN;
+  }
+
+  int nBuck1, nBuck2, nBuck3;
+  int cBuck1, cBuck2, cBuck3, cBuck;
+  nBuck1 = ( int ) ( sMaxs[0] + 3 );
+  nBuck2 = ( int ) ( sMaxs[1] + 3 );
+  nBuck3 = ( int ) ( sMaxs[2] - sMins + 3 );
+  buckets = new int[nBuck1*nBuck2*nBuck3];
+  for ( i = 0; i < ( nBuck1*nBuck2*nBuck3 ); i++ )
+    buckets[i] = -1;
+
+  idxs = 0;
+  for ( i = 0; i < L; i++ )
+  {
+    // find bucket for current data and add it to the list
+    cBuck1 = ( int ) sdata[idxs] + 1;
+    cBuck2 = ( int ) sdata[idxs+1] + 1;
+    cBuck3 = ( int ) ( sdata[idxs+2] - sMins ) + 1;
+    cBuck = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+
+    slist[i] = buckets[cBuck];
+    buckets[cBuck] = i;
+
+    idxs += lN;
+  }
+  // init bucNeigh
+  idxd = 0;
+  for ( cBuck1 = -1; cBuck1 <= 1; cBuck1++ )
+  {
+    for ( cBuck2 = -1; cBuck2 <= 1; cBuck2++ )
+    {
+      for ( cBuck3 = -1; cBuck3 <= 1; cBuck3++ )
+      {
+        bucNeigh[idxd++] = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+      }
+    }
+  }
+  double wsuml, weight;
+  double hiLTr = 80.0 / sigmaR;
+  // done indexing/hashing
+
+  // proceed ...
+#ifdef PROMPT
+  printf ( ( char* ) "done.\nApplying mean shift (Using Lattice)... " );
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\n 0%%" );
+#endif
+#endif
+
+  for ( i = 0; i < L; i++ )
+  {
+
+    // Assign window center (window centers are
+    // initialized by createLattice to be the point
+    // data[i])
+    idxs = i * lN;
+    for ( j = 0; j < lN; j++ )
+      yk[j] = sdata[idxs+j];
+
+    // Calculate the mean shift vector using the lattice
+    // LatticeMSVector(Mh, yk);
+    /*****************************************************/
+    // Initialize mean shift vector
+    for ( j = 0; j < lN; j++ )
+      Mh[j] = 0;
+    wsuml = 0;
+    // uniformLSearch(Mh, yk_ptr); // modify to new
+    // find bucket of yk
+    cBuck1 = ( int ) yk[0] + 1;
+    cBuck2 = ( int ) yk[1] + 1;
+    cBuck3 = ( int ) ( yk[2] - sMins ) + 1;
+    cBuck = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+    for ( j = 0; j < 27; j++ )
+    {
+      idxd = buckets[cBuck+bucNeigh[j]];
+      // list parse, crt point is cHeadList
+      while ( idxd >= 0 )
+      {
+        idxs = lN * idxd;
+        // determine if inside search window
+        el = sdata[idxs+0] - yk[0];
+        diff = el * el;
+        el = sdata[idxs+1] - yk[1];
+        diff += el * el;
+
+        if ( diff < 1.0 )
+        {
+          el = sdata[idxs+2] - yk[2];
+          if ( yk[2] > hiLTr )
+            diff = 4 * el * el;
+          else
+            diff = el * el;
+
+          if ( N > 1 )
+          {
+            el = sdata[idxs+3] - yk[3];
+            diff += el * el;
+            el = sdata[idxs+4] - yk[4];
+            diff += el * el;
+          }
+
+          if ( diff < 1.0 )
+          {
+            weight = 1 - weightMap[idxd];
+            for ( k = 0; k < lN; k++ )
+              Mh[k] += weight * sdata[idxs+k];
+            wsuml += weight;
+          }
+        }
+        idxd = slist[idxd];
+      }
+    }
+    if ( wsuml > 0 )
+    {
+      for ( j = 0; j < lN; j++ )
+        Mh[j] = Mh[j] / wsuml - yk[j];
+    }
+    else
+    {
+      for ( j = 0; j < lN; j++ )
+        Mh[j] = 0;
+    }
+    /*****************************************************/
+
+    // Calculate its magnitude squared
+    mvAbs = 0;
+    for ( j = 0; j < lN; j++ )
+      mvAbs += Mh[j] * Mh[j];
+
+    // Keep shifting window center until the magnitude squared of the
+    // mean shift vector calculated at the window center location is
+    // under a specified threshold (Epsilon)
+
+    // NOTE: iteration count is for speed up purposes only - it
+    //       does not have any theoretical importance
+    iterationCount = 1;
+    while ( ( mvAbs >= EPSILON2 ) && ( iterationCount < LIMIT ) )
+    {
+
+      // Shift window location
+      for ( j = 0; j < lN; j++ )
+        yk[j] += Mh[j];
+
+      // Calculate the mean shift vector at the new
+      // window location using lattice
+      // LatticeMSVector(Mh, yk);
+      /*****************************************************/
+      // Initialize mean shift vector
+      for ( j = 0; j < lN; j++ )
+        Mh[j] = 0;
+      wsuml = 0;
+      // uniformLSearch(Mh, yk_ptr); // modify to new
+      // find bucket of yk
+      cBuck1 = ( int ) yk[0] + 1;
+      cBuck2 = ( int ) yk[1] + 1;
+      cBuck3 = ( int ) ( yk[2] - sMins ) + 1;
+      cBuck = cBuck1 + nBuck1 * ( cBuck2 + nBuck2 * cBuck3 );
+      for ( j = 0; j < 27; j++ )
+      {
+        idxd = buckets[cBuck+bucNeigh[j]];
+        // list parse, crt point is cHeadList
+        while ( idxd >= 0 )
+        {
+          idxs = lN * idxd;
+          // determine if inside search window
+          el = sdata[idxs+0] - yk[0];
+          diff = el * el;
+          el = sdata[idxs+1] - yk[1];
+          diff += el * el;
+
+          if ( diff < 1.0 )
+          {
+            el = sdata[idxs+2] - yk[2];
+            if ( yk[2] > hiLTr )
+              diff = 4 * el * el;
+            else
+              diff = el * el;
+
+            if ( N > 1 )
+            {
+              el = sdata[idxs+3] - yk[3];
+              diff += el * el;
+              el = sdata[idxs+4] - yk[4];
+              diff += el * el;
+            }
+
+            if ( diff < 1.0 )
+            {
+              weight = 1 - weightMap[idxd];
+              for ( k = 0; k < lN; k++ )
+                Mh[k] += weight * sdata[idxs+k];
+              wsuml += weight;
+            }
+          }
+          idxd = slist[idxd];
+        }
+      }
+      if ( wsuml > 0 )
+      {
+        for ( j = 0; j < lN; j++ )
+          Mh[j] = Mh[j] / wsuml - yk[j];
+      }
+      else
+      {
+        for ( j = 0; j < lN; j++ )
+          Mh[j] = 0;
+      }
+      /*****************************************************/
+
+      // Calculate its magnitude squared
+      //mvAbs = 0;
+      //for(j = 0; j < lN; j++)
+      // mvAbs += Mh[j]*Mh[j];
+      mvAbs = ( Mh[0] * Mh[0] + Mh[1] * Mh[1] ) * sigmaS * sigmaS;
+      if ( N == 3 )
+        mvAbs += ( Mh[2] * Mh[2] + Mh[3] * Mh[3] + Mh[4] * Mh[4] ) * sigmaR * sigmaR;
+      else
+        mvAbs += Mh[2] * Mh[2] * sigmaR * sigmaR;
+
+      // Increment interation count
+      iterationCount++;
+    }
+
+    // Shift window location
+    for ( j = 0; j < lN; j++ )
+      yk[j] += Mh[j];
+
+    //store result into msRawData...
+    for ( j = 0; j < N; j++ )
+      msRawData[N*i+j] = ( float ) ( yk[j+2] * sigmaR );
+
+    // Prompt user on progress
+#ifdef SHOW_PROGRESS
+    percent_complete = ( float ) ( i / ( float ) ( L ) ) * 100;
+    printf ( ( char* ) "\r%2d%%", ( int ) ( percent_complete + 0.5 ) );
+#endif
+
+    // Check to see if the algorithm has been halted
+    if ( ( i % PROGRESS_RATE == 0 ) && ( ( ErrorStatus = msSys.Progress ( ( float ) ( i / ( float ) ( L ) ) * ( float ) ( 0.8 ) ) ) ) == EL_HALT )
+      break;
+  }
+
+  // Prompt user that filtering is completed
+#ifdef PROMPT
+#ifdef SHOW_PROGRESS
+  printf ( ( char* ) "\r" );
+#endif
+  printf ( ( char* ) "done." );
+#endif
+
+  // de-allocate memory
+  delete [] buckets;
+  delete [] slist;
+  delete [] sdata;
+
+  delete [] yk;
+  delete [] Mh;
+
+  // done.
+  return;
+
+}
+
+void msImageProcessor::SetSpeedThreshold ( float speedUpThreshold )
+{
+  speedThreshold = speedUpThreshold;
+}
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ END OF CLASS DEFINITION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

+ 800 - 0
edisonSegm/msImageProcessor.h

@@ -0,0 +1,800 @@
+/*******************************************************
+
+                 Mean Shift Analysis Library
+	=============================================
+
+
+	The mean shift library is a collection of routines
+	that use the mean shift algorithm. Using this algorithm,
+	the necessary output will be generated needed
+	to analyze a given input set of data.
+
+  Mean Shift Image Processor Class:
+  ================================
+
+	The following class inherits from the mean shift library
+	in order to perform the specialized tasks of image
+	segmentation and filtering.
+	
+	The prototype of the Mean Shift	Image Processor Class
+	is provided below. Its definition is provided in
+	'msImageProcessor.cc'.
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+									 space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+
+#ifndef msImageProcessor_H
+#define msImageProcessor_H
+
+//include mean shift library
+#include	"ms.h"
+
+//include prototypes of additional strucuters
+//used for image segmentation...
+
+//include region list used to store boundary pixel
+//indeces for each region
+#include	"rlist.h"
+
+//include region adjacency list class used for
+//region pruning and transitive closure
+#include	"RAList.h"
+
+//define constants
+
+	//image pruning
+#define	TOTAL_ITERATIONS	14
+#define BIG_NUM				0xffffffff	//BIG_NUM = 2^32-1
+#define NODE_MULTIPLE		10
+
+	//data space conversion...
+const double Xn			= 0.95050;
+const double Yn			= 1.00000;
+const double Zn			= 1.08870;
+//const double Un_prime	= 0.19780;
+//const double Vn_prime	= 0.46830;
+const double Un_prime	= 0.19784977571475;
+const double Vn_prime	= 0.46834507665248;
+const double Lt			= 0.008856;
+
+	//RGB to LUV conversion
+const double XYZ[3][3] = {	{  0.4125,  0.3576,  0.1804 },
+							{  0.2125,  0.7154,  0.0721 },
+							{  0.0193,  0.1192,  0.9502 }	};
+
+	//LUV to RGB conversion
+const double RGB[3][3] = {	{  3.2405, -1.5371, -0.4985 },
+							{ -0.9693,  1.8760,  0.0416 },
+							{  0.0556, -0.2040,  1.0573 }	};
+
+//define data types
+typedef unsigned char byte;
+
+//define enumerations
+enum imageType {GRAYSCALE, COLOR};
+
+//define prototype
+class msImageProcessor: public MeanShift {
+
+public:
+
+  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+  /* Class Constructor and Destructor */
+  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+  msImageProcessor( void );        //Default Constructor
+ ~msImageProcessor( void );        //Class Destructor
+
+ /*/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+ /* Input Image Declaration  */
+ /*\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				  * Define Image *                   |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Uploads an image to be segmented by the image    |//
+  //|   segmenter class.                                 |//
+  //|                                                    |//
+  //|   An image is defined by specifying the folloing:  |//
+  //|                                                    |//
+  //|   <* data *>                                       |//
+  //|   A one dimensional unsigned char array of RGB     |//
+  //|   vectors.                                         |//
+  //|                                                    |//
+  //|   <* type *>                                       |//
+  //|   Specifies the image type: COLOR or GREYSCALE.    |//
+  //|                                                    |//
+  //|   <* height *>                                     |//
+  //|   The image height.                                |//
+  //|                                                    |//
+  //|   <* width *>                                      |//
+  //|   The image width.                                 |//
+  //|                                                    |//
+  //|   This method uploads the image and converts its   |//
+  //|   data into the LUV space. If another conversion   |//
+  //|   is desired data may be uploaded into this class  |//
+  //|   via the procedure MeanShift::UploadInput().      |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		DefineImage(data, type, height, width)       |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  void DefineImage(byte*,imageType, int, int);
+  void DefineBgImage(byte*, imageType , int , int );
+
+
+ /*/\/\/\/\/\/\*/
+ /* Weight Map */
+ /*\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|			     * Set Weight Map *                  |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Uploads weight map specifying for each pixel     |//
+  //|   in the image a value between 0 and 1 - 1 indica- |//
+  //|   ting the presence of an edge and 0 the absense   |//
+  //|   of an edge.                                      |//
+  //|                                                    |//
+  //|   The arguments to this method are:                |//
+  //|                                                    |//
+  //|   <* weightMap *>                                  |//
+  //|   A floating point array of size (height x width)  |//
+  //|   specifying at location (i,j) the edge strength   |//
+  //|   of pixel (i,j). (e.g. pixel (i,j) has an edge    |//
+  //|   strength of weightMap[j*width+i]).               |//
+  //|                                                    |//
+  //|   <* epsilon *>                                    |//
+  //|   A floating point number specifying the threshold |//
+  //|   used to fuse regions during transitive closure.  |//
+  //|                                                    |//
+  //|   Note: DefineImage must be called prior to call-  |//
+  //|         ing this method. DefineImage is used to    |//
+  //|         define the dimensions of the image.        |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		SetWeightMap(weightMap, epsilon)             |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  void SetWeightMap(float*, float);
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|			   * Remove Weight Map *                 |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Removes weight map. An error is NOT flagged      |//
+  //|   if a weight map was not defined prior to calling |//
+  //|   this method.                                     |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		RemoveWeightMap(void)                        |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  void RemoveWeightMap(void);
+
+ /*/\/\/\/\/\/\/\/\/\*/
+ /* Image Filtering  */
+ /*\/\/\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|                   *  Filter  *                     |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Apply mean shift filter to the defined image,    |//
+  //|   defined either via MeanShift::DefineLInput or    |//
+  //|   msImageProcessor::DefineImage. The resulting     |//
+  //|   segmented image is stored in the private data    |//
+  //|   members of the image segmenter class which can   |//
+  //|   be obtained by calling image msImageProcessor::  |//
+  //|   GetResults().                                    |//
+  //|                                                    |//
+  //|   The arguments to this method are:                |//
+  //|                                                    |//
+  //|   <* sigmaS *>                                     |//
+  //|   The spatial radius of the mean shift window.     |//
+  //|                                                    |//
+  //|   <* sigmaR *>                                     |//
+  //|   The range radius of the mean shift window.       |//
+  //|                                                    |//
+  //|   <* speedUpLevel *>                               |//
+  //|   Determines if a speed up optimization should be  |//
+  //|   used to perform image filtering. A value of      |//
+  //|   NO_SPEEDUP turns this optimization off and a     |//
+  //|   value of SPEEDUP turns this optimization on.     |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		Filter(sigmaS, sigmaR, speedUpLevel)         |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  void Filter(int, float, SpeedUpLevel);
+
+ /*/\/\/\/\/\/\/\/\/\/\/\*/
+ /* Image Region Fusing  */
+ /*\/\/\/\/\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				  *  Fuse Regions  *                 |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Fuses the regions of a filtered image,           |//
+  //|   defined either via MeanShift::DefineLInput or    |//
+  //|   msImageProcessor::DefineImage. The resulting     |//
+  //|   segmented image is stored in the private data    |//
+  //|   members of the image segmenter class which can   |//
+  //|   be obtained by calling image msImageProcessor::  |//
+  //|   GetResults().                                    |//
+  //|                                                    |//
+  //|   The arguments to this method are:                |//
+  //|                                                    |//
+  //|   <* sigmaR *>                                     |//
+  //|   The range radius that defines similar color      |//
+  //|   amongst image regions.                           |//
+  //|                                                    |//
+  //|   <* minRegion *>                                  |//
+  //|   The minimum density a region may have in the     |//
+  //|   resulting segmented image. All regions have      |//
+  //|   point density < minRegion are pruned from the    |//
+  //|   image.                                           |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		FuseRegions(sigmaR, minRegion)               |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  void FuseRegions(float, int);
+
+ /*/\/\/\/\/\/\/\/\/\/\*/
+ /* Image Segmentation */
+ /*\/\/\/\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				     *  Segment  *                   |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Segments the defined image, defined either via   |//
+  //|   MeanShift::DefineLInput or msImageProcessor::De- |//
+  //|   fineImage. The resulting segmented image is      |//
+  //|   stored in the private data members of the image  |//
+  //|   processor class which can be obtained by calling |//
+  //|   ImageSegmenter::GetResults().                    |//
+  //|                                                    |//
+  //|   The arguments to this method are:                |//
+  //|                                                    |//
+  //|   <* sigmaS *>                                     |//
+  //|   The spatial radius of the mean shift window.     |//
+  //|                                                    |//
+  //|   <* sigmaR *>                                     |//
+  //|   The range radius of the mean shift window.       |//
+  //|                                                    |//
+  //|   <* minRegion *>                                  |//
+  //|   The minimum density a region may have in the     |//
+  //|   resulting segmented image. All regions have      |//
+  //|   point density < minRegion are pruned from the    |//
+  //|   image.                                           |//
+  //|                                                    |//
+  //|   <* speedUpLevel *>                               |//
+  //|   Determines if a speed up optimization should be  |//
+  //|   used to perform image filtering. A value of      |//
+  //|   NO_SPEEDUP turns this optimization off and a     |//
+  //|   value of SPEEDUP turns this optimization on.     |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		Segment(sigmaS, sigmaR, minRegion,           |//
+  //|                       speedUpLevel)                |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+ 
+  void Segment(int, float, int, SpeedUpLevel);
+
+  /*/\/\/\/\/\/\/\/\/\/\/\/\*/
+  /* Data Space Conversion  */
+  /*\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				 *  RGB To LUV  *                    |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Converts an RGB vector to LUV.                   |//
+  //|                                                    |//
+  //|   The arguments to this method are:                |//
+  //|                                                    |//
+  //|   <* rgbVal *>                                     |//
+  //|   An unsigned char array containing the RGB        |//
+  //|   vector.                                          |//
+  //|                                                    |//
+  //|   <* luvVal *>                                     |//
+  //|   A floating point array containing the LUV        |//
+  //|   vector.                                          |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		RGBtoLUV(rgbVal, luvVal)                     |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  void RGBtoLUV(byte*, float*);
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				 *  LUV To RGB  *                    |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Converts an LUV vector to RGB.                   |//
+  //|                                                    |//
+  //|   The arguments to this method are:                |//
+  //|                                                    |//
+  //|   <* luvVal *>                                     |//
+  //|   A floating point array containing the LUV        |//
+  //|   vector.                                          |//
+  //|                                                    |//
+  //|   <* rgbVal *>                                     |//
+  //|   An unsigned char array containing the RGB        |//
+  //|   vector.                                          |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		LUVtoRGB(luvVal, rgbVal)                     |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  void LUVtoRGB(float*, byte*);
+
+  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+  /*  Filtered and Segmented Image Output */
+  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|			      *  Get Raw Data  *                 |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Returns the resulting filtered or segmented im-  |//
+  //|   age data after calling Filter() or Segment().    |//
+  //|                                                    |//
+  //|   The arguments to this method are:                |//
+  //|                                                    |//
+  //|   <* outputImageData *>                            |//
+  //|   A floating point array containing the vector     |//
+  //|   data of the filtered or segmented image.         |//
+  //|                                                    |//
+  //|   NOTE: If DefineImage was used to specify the     |//
+  //|         the input to this class, outputImageData   |//
+  //|         is in the LUV data space.                  |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		GetResults(outputImageData)                  |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  void GetRawData(float*);
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				 *  Get Results  *                   |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Returns the resulting filtered or segmented im-  |//
+  //|   age after calling Filter() or Segment().         |//
+  //|                                                    |//
+  //|   The arguments to this method are:                |//
+  //|                                                    |//
+  //|   <* outputImage *>                                |//
+  //|   An unsigned char array containing the RGB        |//
+  //|   vector data of the output image.                 |//
+  //|                                                    |//
+  //|   To obtain the un-converted (LUV) data space      |//
+  //|   output one may use                               |//
+  //|   msImageProcessor::GetRawData().                  |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		GetResults(outputImage)                      |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  void GetResults(byte*);
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				 *  Get Boundaries  *                |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Returns the boundaries of each region of the     |//
+  //|   segmented image using a region list object,      |//
+  //|   available after filtering or segmenting the      |//
+  //|   defined image.                                   |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		regionList = GetBoundaries()                 |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  RegionList *GetBoundaries( void );
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|			        * Get Regions *                  |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Returns the regions of the processed image.      |//
+  //|   Each region in the image is uniquely character-  |//
+  //|   ized by its location and color (e.g. RGB).       |//
+  //|   GetRegions() therefore returns the following     |//
+  //|   information about the regions of the processed   |//
+  //|   image:                                           |//
+  //|                                                    |//
+  //|   <* regionCount *>                                |//
+  //|   An integer that specifies the number of regions  |//
+  //|   contained in the processed image.                |//
+  //|                                                    |//
+  //|   <* modes *>                                      |//
+  //|   A floating point array of length regionCount*N   |//
+  //|   containing the feature space component of each   |//
+  //|   region (e.g. LUV), and indexed by region label.  |//
+  //|                                                    |//
+  //|   <* labels *>                                     |//
+  //|   An integer array of length (height*width) which  |//
+  //|   contains at every pixel location (x,y) a label   |//
+  //|   relating that pixel to a region whose mode is    |//
+  //|   specified by modes and whose area is specified   |//
+  //|   by modePointCounts.                              |//
+  //|                                                    |//
+  //|   <* modePointCounts *>                            |//
+  //|   An integer array of length regionCount and ind-  |//
+  //|   exed by region label, that specifies the region  |//
+  //|   area (in pixels) for each segmented image reg-   |//
+  //|   ion. (e.g. Area of region having label specif-   |//
+  //|   ified by l, has area modePointCounts[l] (pix-    |//
+  //|   els).)                                           |//
+  //|                                                    |//
+  //|   NOTE: Memory for the above integer and floating  |//
+  //|         point arrays is allocated inside this      |//
+  //|         method.                                    |//
+  //|                                                    |//
+  //|         Also modes stored by the modes array are   |//
+  //|         not in the RGB space. Instead if the       |//
+  //|         method DefineImage was used, these data    |//
+  //|         points are in the LUV space, and if the    |//
+  //|         method DefineLInput was used these data    |//
+  //|         points are in whatever space you specified |//
+  //|         them to be in when calling DefineLInput.   |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		regionCount = GetRegions(labels, modes       |//
+  //|                                modePointCounts)    |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+  int GetRegions(int**, float**, int**);
+
+
+  void SetSpeedThreshold(float);
+private:
+
+  //========================
+  // *** Private Methods ***
+  //========================
+
+	/*/\/\/\/\/\/\/\/\/\*/
+	/*  Image Filtering */
+	/*\/\/\/\/\/\/\/\/\/*/
+
+	void NonOptimizedFilter(float, float);	// filters the image applying mean shift to each point
+											// Advantage	: most accurate
+											// Disadvantage	: time expensive
+   void NewNonOptimizedFilter(float, float);
+
+	void OptimizedFilter1(float, float);	// filters the image using previous mode information
+											// to avoid re-applying mean shift to some data points
+											// Advantage	: maintains high level of accuracy,
+											//				  large speed up compared to non-optimized
+											//				  version
+											// Disadvantage	: POSSIBLY not as accurate as non-optimized
+											//				  version
+   void NewOptimizedFilter1(float, float);
+
+
+	void OptimizedFilter2(float, float);	//filter the image using previous mode information
+											//and window traversals to avoid re-applying mean shift to
+											//some data points
+											// Advantage	: huge speed up - maintains accuracy good enough
+											//				  for segmentation
+											// Disadvantage	: not as accurate as previous filters
+   void NewOptimizedFilter2(float, float);
+
+	
+	/*/\/\/\/\/\/\/\/\/\/\/\*/
+	/* Image Classification */
+	/*\/\/\/\/\/\/\/\/\/\/\/*/
+
+	void Connect( void );					// classifies mean shift filtered image regions using
+											// private classification structure of this class
+
+	void Fill(int, int);					// used by Connect to perform label each region in the
+											// mean shift filtered image using an eight-connected
+											// fill
+
+	/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+	/* Transitive Closure and Image Pruning */
+	/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+	void BuildRAM( void );					// build a region adjacency matrix using the region list
+											// object
+
+	void DestroyRAM( void );				// destroy the region adjacency matrix: de-allocate its memory
+											// initialize it for re-use
+
+	void TransitiveClosure( void );			// use the RAM to apply transitive closure to the image modes
+
+	void ComputeEdgeStrengths( void );		// computes the weights of the weighted graph using the weight
+											// map
+
+	//Usage: Prune(minRegion)
+	void Prune(int);						// use the RAM to prune the image of spurious regions (regions
+											// whose area is less than minRegion pixels, where minRegion is
+											// an argument of this method)
+
+	/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+	/*  Region Boundary Detection */
+	/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+	void DefineBoundaries( void );			// defines the boundaries of each region using the classified segmented
+											// image storing the resulting boundary locations for each region using
+											// a region list object
+
+	/*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+	/*  Image Data Searching/Distance Calculation */
+	/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+	//Usage: InWindow(modeIndex1, modeIndex2)
+	bool InWindow(int, int);				//returns true if the range data of the specified data points
+											//are within the defined search window (defined by kernel
+											//bandwidth h[1])
+
+	float SqDistance(int, int);				// computes the normalized square distance between two modes 
+
+	/*/\/\/\/\/\/\/\/\/\/\*/
+	/* Memory Management  */
+	/*\/\/\/\/\/\/\/\/\/\/*/
+
+	void InitializeOutput( void );			//Allocates memory needed by this class to perform image
+											//filtering and segmentation
+
+	void DestroyOutput( void );				//De-allocates memory needed by this class to perform image
+											//filtering and segmentation
+
+  //=============================
+  // *** Private Data Members ***
+  //=============================
+
+   //##########################################
+   //#######    IMAGE CLASSIFICATION   ########
+   //##########################################
+
+	/////////Image Boundaries/////////
+	RegionList		*regionList;			// stores the boundary locations for each region
+
+	/////////Image Regions////////
+	int				regionCount;			// stores the number of connected regions contained by the
+											// image
+
+	/////////8 Connected Neighbors/////////
+	int				neigh[8];
+
+	/////////Index Table/////////////////
+	int				*indexTable;			//used during fill algorithm
+
+	/////////LUV_data/////////////////
+   //int            *LUV_data;           //stores modes in integer format on lattice
+	float				*LUV_data;				//stores modes in float format on lattice
+   float          LUV_treshold;        //in float mode this determines what "close" means between modes
+
+
+   //##########################################
+   //#######   OUTPUT DATA STORAGE     ########
+   //##########################################
+
+	////////Raw Data (1 to 1 correlation with input)////////
+	float			*msRawData;				// Raw data output of mean shift algorithm
+											// to the location of the data point on the lattice
+
+	////////Data Modes////////
+	int				*labels;				// assigns a label to each data point associating it to
+											// a mode in modes (e.g. a data point having label l has
+											// mode modes[l])
+
+	float			*modes;					// stores the mode data of the input data set, indexed by labels
+
+	int				*modePointCounts;		// stores for each mode the number of point mapped to that mode,
+											// indexed by labels
+
+   //##########################################
+   //#######  REGION ADJACENCY MATRIX  ########
+   //##########################################
+
+	//////////Region Adjacency List/////////
+	RAList			*raList;				// an array of RAList objects containing an entry for each
+											// region of the image
+
+	//////////RAMatrix Free List///////////
+	RAList			*freeRAList;			// a pointer to the head of a region adjacency list object
+											// free list
+
+	RAList			*raPool;				// a pool of RAList objects used in the construction of the
+											// RAM
+
+   //##############################################
+   //#######  COMPUTATION OF EDGE STRENGTHS #######
+   //##############################################
+
+	//////////Epsilon///////////
+	float			epsilon;				//Epsilon used for transitive closure
+
+	//////Visit Table//////
+	unsigned char	*visitTable;			//Table used to keep track of which pixels have been
+											//already visited upon computing the boundary edge strengths
+
+   //##########################################
+   //#######       IMAGE PRUNING       ########
+   //##########################################
+
+	////////Transitive Closure/////////
+	float			rR2;					//defines square range radius used when clustering pixels
+											//together, thus defining image regions
+
+   float speedThreshold; // the % of window radius used in new optimized filter 2.
+
+	float percent_complete;
+};
+
+#endif

+ 236 - 0
edisonSegm/msSys.cpp

@@ -0,0 +1,236 @@
+/*******************************************************
+
+                 Mean Shift Analysis Library
+	=============================================
+
+	The mean shift library is a collection of routines
+	that use the mean shift algorithm. Using this algorithm,
+	the necessary output will be generated needed
+	to analyze a given input set of data.
+
+  Mean Shift System:
+  ==================
+
+	The Mean Shift System class provides a mechanism for the
+	mean shift library classes to prompt progress and to
+	time its computations. When porting the mean shift library
+	to an application the methods of this class may be changed
+	such that the output of the mean shift class prompts
+	will be given to whatever hardware or software device that
+	is desired.
+
+	The definition for the mean shift system class is provided
+	below. Its prototype is provided in "msSys.cc".
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+									 space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+
+//include the msSystem class prototype
+#include	"msSys.h"
+
+//include needed system libraries
+#include	<time.h>
+#include	<stdio.h>
+#include	<stdarg.h>
+#include	<stdlib.h>
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@      PUBLIC METHODS     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+  /*** Class Constructor and Destructor ***/
+  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Class Constructor                                    */
+/*******************************************************/
+/*Constructs a mean shift system object.               */
+/*******************************************************/
+/*Post:                                                */
+/*      - an msSystem object has been properly init-   */
+/*        ialized.                                     */
+/*******************************************************/
+
+msSystem::msSystem( void )
+{
+
+	//initialize currentTime
+	currentTime = clock();
+
+	//done.
+
+}
+
+/*******************************************************/
+/*Class Destructor                                     */
+/*******************************************************/
+/*Destroys a mean shift system object.                 */
+/*******************************************************/
+/*Post:                                                */
+/*      - an msSystem object has been properly dest-   */
+/*        royed.                                       */
+/*******************************************************/
+
+msSystem::~msSystem( void )
+{
+	/* do nothing */
+}
+
+ /*/\/\/\/\/\/\/\/\/\*/
+ /*** System Timer ***/
+ /*\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Start Timer                                          */
+/*******************************************************/
+/*Sets the mean shift system time to the current       */
+/*system time.                                         */
+/*******************************************************/
+/*Post:                                                */
+/*      - the mean shift system time has been set to   */
+/*        the current system time.                     */
+/*******************************************************/
+
+void msSystem::StartTimer( void )
+{
+
+	//set msSystem time to system time
+	currentTime = clock();
+
+	//done.
+	return;
+
+}
+
+/*******************************************************/
+/*Elapsed Time                                         */
+/*******************************************************/
+/*Returns the amount of time in seconds since the      */
+/*mean shift system time was last set.                 */
+/*******************************************************/
+/*Post:                                                */
+/*      - the amount of time in seconds since the mean */
+/*        shift system time was last set is returned.  */
+/*******************************************************/
+
+double msSystem::ElapsedTime( void )
+{
+
+	//return the amount of time elapsed in seconds
+	//since the msSystem time was last set...
+	return ((double) (clock() - currentTime))/(CLOCKS_PER_SEC);
+
+}
+
+ /*/\/\/\/\/\/\/\/\/\/\*/
+ /***  System Output ***/
+ /*\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Prompt                                               */
+/*******************************************************/
+/*Output a text message to the user.                   */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - PromptStr is a string containing delimeters  */
+/*        that is to be output to the user.            */
+/*      - a variable set of arguments is also passed   */
+/*        to this method that are used to replace      */
+/*        the delimeters contained by PromptStr        */
+/*Post:                                                */
+/*      - the delimeters of PromptStr have been        */
+/*        replaced accordingly using the variable      */
+/*        set of arguments and the resulting string    */
+/*        has been output to the user.                 */
+/*******************************************************/
+
+//extern void bgLogVar(const char *, va_list);
+
+void msSystem::Prompt(const char *PromptStr, ...)
+{
+
+	//obtain argument list using ANSI standard...
+	va_list	argList;
+	va_start(argList, PromptStr);
+
+	//print the output string to stderr using
+	//vfprintf
+	//bgLogVar(PromptStr, argList);
+	va_end(argList);
+
+	//done.
+	return;
+
+}
+
+/*******************************************************/
+/*Progress                                             */
+/*******************************************************/
+/*The progress of a specific algorithm of the mean     */
+/*shift library is output to the user.                 */
+/*******************************************************/
+/*Pre:                                                 */
+/*		- percentComplete indicates the percentage     */
+/*		  of the algorithm that has executed and is    */
+/*		  a floating point number from zero to one     */
+/*Post:                                                */
+/*      - the percentComplete has been noted by the    */
+/*        interface (possibly to update a progress     */
+/*        bar).                                        */
+/*      - if the thread executing the mean shift code  */
+/*        must halt execution msSYS_HALT is returned,  */
+/*        msSYS_OK is returned otherwise               */
+/*******************************************************/
+
+///////////////////////////////////////////////////////////////////
+//NOTE: This implementation is specific to EDISON. In order
+//      for one to port the mean shift class to another project
+//      or program one must re-implement this method.
+///////////////////////////////////////////////////////////////////
+
+//is set by the GUI when the user presses the Cancel button
+//on the wxWindows progress modal window; this flag indicates
+//to the mean shift library that it is to halt execution.
+//This parameter is used and checked in the method
+//BgMdiSegmentChild::OnSegment.
+//extern bool stop_flag;
+bool stop_flag;
+
+//is updated in the msSystem::Progress method and indicates to
+//the wxWindows progress modal window the percent complete, such
+//that it may update its progress bar accordingly; This parameter
+//is used and checked in the method BgMdiSegmentChild::OnSegment.
+//extern int	percentDone;
+int percentDone;
+
+ErrorLevel msSystem::Progress(float percentComplete)
+{
+	percentDone	= (int)(percentComplete*100);
+
+	//check stop flag and return appropriate system state
+	ErrorLevel		myState = EL_OKAY;
+	if(stop_flag)	myState	= EL_HALT;
+
+	//done.
+	return myState;
+
+}
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ END OF CLASS DEFINITION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

+ 229 - 0
edisonSegm/msSys.h

@@ -0,0 +1,229 @@
+/*******************************************************
+
+                 Mean Shift Analysis Library
+	=============================================
+
+	The mean shift library is a collection of routines
+	that use the mean shift algorithm. Using this algorithm,
+	the necessary output will be generated needed
+	to analyze a given input set of data.
+
+  Mean Shift System:
+  ==================
+
+	The Mean Shift System class provides a mechanism for the
+	mean shift library classes to prompt progress and to
+	time its computations. When porting the mean shift library
+	to an application the methods of this class may be changed
+	such that the output of the mean shift class prompts
+	will be given to whatever hardware or software device that
+	is desired.
+
+	The prototype for the mean shift system class is provided
+	below. Its defition is provided in "msSys.cc".
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+									 space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+
+
+#ifndef MSSYS_H
+#define MSSYS_H
+
+//Include standard mean shift library type definitions
+#include	"tdef.h"
+
+//Include standard libraries needed for msSystem prototype
+#include	<time.h>
+
+extern void bgLogFile(const char*, ...);
+
+//Mean Shify System class prototype
+class msSystem {
+
+ public:
+
+  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+  /* Class Constructor and Destructor */
+  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+  msSystem( void ); //Default Constructor
+ ~msSystem( void ); //Class Destructor
+
+ /*/\/\/\/\/\/\/\*/
+ /* System Timer */
+ /*\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				  *  Start Timer  *                  |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Initializes the system timer. The timer object   |//
+  //|   synthesized by this class is initialized during  |//
+  //|   construction of the msSystem class to be the     |//
+  //|   current time during construction.                |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+ void StartTimer( void );
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				 *  Elapsed Time  *                  |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Returns the amount of time elapsed in seconds    |//
+  //|   from when StartTimer() was called. If            |//
+  //|   StartTimer() was not called, the time returned   |//
+  //|   is the time elapsed from the construction of the |//
+  //|   msSystem object.                                 |//
+  //|                                                    |//
+  //|   In order to create a valid kernel the following  |//
+  //|   argumens must be provided this method:           |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		TimeInSeconds = ElapsedTime()                |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+ double	ElapsedTime( void );
+
+ /*/\/\/\/\/\/\/\/\*/
+ /*  System Output */
+ /*\/\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				     *  Prompt  *                    |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Outputs to a device a character message contain- |//
+  //|   ing delimeters. These delimeters are replaced by |//
+  //|   the variable input parameters passed to prompt.  |//
+  //|   (Like printf.)                                   |//
+  //|                                                    |//
+  //|   This method should be altered if a special       |//
+  //|   device either than stderr is desired to be used  |//
+  //|   as an output prompt.                             |//
+  //|                                                    |//
+  //|   The arguments to this method are:                |//
+  //|                                                    |//
+  //|   <* PromptStr *>                                  |//
+  //|   A string possibly containing delimeters that     |//
+  //|   is to be output to the user.                     |//
+  //|                                                    |//
+  //|   <* varArgs *>                                    |//
+  //|   A variable set of arguments to be placed into    |//
+  //|   the prompt string.                               |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|		Prompt(PromptStr, varArgs)                   |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+ void	Prompt(const char*, ...);
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|				   *  Progress  *                    |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   This method is called by the mean shift library  |//
+  //|   methods during the application of a specific     |//
+  //|   algorithm in which the progress of the algorithm |//
+  //|   is indicated. Its main use is for a multi-thre-  |//
+  //|   aded programming envioronment. Namely, it is     |//
+  //|   called fairly frequently by the mean shift       |//
+  //|   library methods. It then can be used to grace-   |//
+  //|   fully halt the algorithm, or to simply update    |//
+  //|   a progress bar.                                  |//
+  //|                                                    |//
+  //|   This method depends strongly on the interface    |//
+  //|   and therefore must be re-implemented to accom-   |//
+  //|   odate ones needs.                                |//
+  //|                                                    |//
+  //|   To facilitate a multi-threaded enviornment       |//
+  //|   the prompt function returns a value that         |//
+  //|   indicates to the mean shift method whether       |//
+  //|   to continue execution. EL_HALT is returned       |//
+  //|   when the mean shift procedure is to stop         |//
+  //|   execution and EL_OKAY is returned otherwise.     |//
+  //|                                                    |//
+  //|   The arguments to this method are:                |//
+  //|                                                    |//
+  //|   <* PercentComplete *>                            |//
+  //|   A floating point number that indicates the perc- |//
+  //|   ent complete of the algorithm. PercentComplete   |//
+  //|   takes a value between zero and one.              |//
+  //|                                                    |//
+  //|   <* SystemState *>                                |//
+  //|   Indicates the system state. It is EL_HALT        |//
+  //|   when the mean shift method is to halt execution  |//
+  //|   and it is EL_OKAY otherwise.                     |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|	 SystemState = Progress(PercentComplete)         |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+ ErrorLevel Progress(float);
+
+ private:
+
+	 //Timer object...
+	 time_t currentTime;
+
+};
+
+#endif

+ 339 - 0
edisonSegm/rlist.cpp

@@ -0,0 +1,339 @@
+/*******************************************************
+
+                 Mean Shift Analysis Library
+	=============================================
+
+
+	The mean shift library is a collection of routines
+	that use the mean shift algorithm. Using this algorithm,
+	the necessary output will be generated needed
+	to analyze a given input set of data.
+
+  Region List Class:
+  =================
+
+	During segmentation, data regions are defined. The 
+	RegionList class provides a mechanism for doing so, as
+	well as defines some basic operations, such as region
+	growing or small region pruning, on the defined regions.
+	It is defined below. Its prototype is given in (char *)"region.h".
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+									 space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+
+
+#include	"rlist.h"
+#include	<stdio.h>
+#include	<stdlib.h>
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@      PUBLIC METHODS     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+  /*** Class Constructor and Destructor ***/
+  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Constructor                                          */
+/*******************************************************/
+/*Constructor                                          */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - modesPtr is a pointer to an array of modes   */
+/*      - maxRegions_ is the maximum number of regions */
+/*        that can be defined                          */
+/*      - L_ is the number of data points being class- */
+/*        ified by the region list class               */
+/*      - N is the dimension of the data set being cl- */
+/*        assified by the region list class            */
+/*Post:                                                */
+/*      - a region list object has been properly init- */
+/*        ialized.                                     */
+/*******************************************************/
+
+RegionList::RegionList(int maxRegions_, int L_, int N_)
+{
+
+	//Obtain maximum number of regions that can be
+	//defined by user
+	if((maxRegions = maxRegions_) <= 0)
+		ErrorHandler((char *)"RegionList", (char *)"Maximum number of regions is zero or negative.", FATAL);
+
+	//Obtain dimension of data set being classified by
+	//region list class
+	if((N = N_) <= 0)
+		ErrorHandler((char *)"RegionList", (char *)"Dimension is zero or negative.", FATAL);
+
+	//Obtain length of input data set...
+	if((L = L_) <= 0)
+		ErrorHandler((char *)"RegionList", (char *)"Length of data set is zero or negative.", FATAL);
+
+	//Allocate memory for index table
+	if(!(indexTable = new int [L]))
+		ErrorHandler((char *)"RegionList", (char *)"Not enough memory.", FATAL);
+
+	//Allocate memory for region list array
+	if(!(regionList = new REGION [maxRegions]))
+		ErrorHandler((char *)"RegionList", (char *)"Not enough memory.", FATAL);
+
+	//Initialize region list...
+	numRegions		= freeRegion = 0;
+
+	//Initialize indexTable
+	freeBlockLoc	= 0;
+
+	//done.
+	return;
+
+}
+
+/*******************************************************/
+/*Destructor                                           */
+/*******************************************************/
+/*Destroys region list object.                         */
+/*******************************************************/
+/*Post:                                                */
+/*      - region list object has been properly dest-   */
+/*        oyed.                                        */
+/*******************************************************/
+
+RegionList::~RegionList( void )
+{
+	//de-allocate memory...
+	delete [] regionList;
+	delete [] indexTable;
+
+	//done.
+	return;
+}
+
+  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+  /***  Region List Manipulation  ***/
+  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Add Region                                           */
+/*******************************************************/
+/*Adds a region to the region list.                    */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - label is a positive integer used to uniquely */
+/*        identify a region                            */
+/*      - pointCount is the number of N-dimensional    */
+/*        data points that exist in the region being   */
+/*        classified.                                  */
+/*      - indeces is a set of indeces specifying the   */
+/*        data points contained within this region     */
+/*      - pointCount must be > 0                       */
+/*Post:                                                */
+/*      - a new region labeled using label and contai- */
+/*        ning pointCount number of points has been    */
+/*        added to the region list.                    */
+/*******************************************************/
+
+void RegionList::AddRegion(int label, int pointCount, int *indeces)
+{
+
+	//make sure that there is enough room for this new region 
+	//in the region list array...
+	if(numRegions >= maxRegions)
+		ErrorHandler((char *)"AddRegion", (char *)"Not enough memory allocated.", FATAL);
+
+	//make sure that label is positive and point Count > 0...
+	if((label < 0)||(pointCount <= 0))
+		ErrorHandler((char *)"AddRegion", (char *)"Label is negative or number of points in region is invalid.", FATAL);
+
+	//make sure that there is enough memory in the indexTable
+	//for this region...
+	if((freeBlockLoc + pointCount) > L)
+		ErrorHandler((char *)"AddRegion", (char *)"Adding more points than what is contained in data set.", FATAL);
+
+	//place new region into region list array using
+	//freeRegion index
+	regionList[freeRegion].label		= label;
+	regionList[freeRegion].pointCount	= pointCount;
+	regionList[freeRegion].region		= freeBlockLoc;
+
+	//copy indeces into indexTable using freeBlock...
+	int i;
+	for(i = 0; i < pointCount; i++)
+		indexTable[freeBlockLoc+i] = indeces[i];
+
+	//increment freeBlock to point to the next free
+	//block
+	freeBlockLoc	+= pointCount;
+
+	//increment freeRegion to point to the next free region
+	//also, increment numRegions to indicate that another
+	//region has been added to the region list
+	freeRegion++;
+	numRegions++;
+
+	//done.
+	return;
+
+}
+
+/*******************************************************/
+/*Reset                                                */
+/*******************************************************/
+/*Resets the region list.                              */
+/*******************************************************/
+/*Post:                                                */
+/*      - the region list has been reset.              */
+/*******************************************************/
+
+void RegionList::Reset( void )
+{
+
+	//reset region list
+	freeRegion = numRegions = freeBlockLoc = 0;
+
+	//done.
+	return;
+
+}
+
+  /*/\/\/\/\/\/\/\/\/\/\*/
+  /*  Query Region List */
+  /*\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Get Number Regions                                   */
+/*******************************************************/
+/*Returns the number of regions stored by region list. */
+/*******************************************************/
+/*Post:                                                */
+/*      - the number of regions stored by the region   */
+/*        list is returned.                            */
+/*******************************************************/
+
+int	RegionList::GetNumRegions( void )
+{
+	// return region count
+	return numRegions;
+}
+
+/*******************************************************/
+/*Get Label                                            */
+/*******************************************************/
+/*Returns the label of a specified region.             */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - regionNum is an index into the region list   */
+/*        array.                                       */
+/*Post:                                                */
+/*      - the label of the region having region index  */
+/*        specified by regionNum has been returned.    */
+/*******************************************************/
+
+int	RegionList::GetLabel(int regionNum)
+{
+	//return the label of a specified region
+	return regionList[regionNum].label;
+}
+
+/*******************************************************/
+/*Get Region Count                                     */
+/*******************************************************/
+/*Returns the point count of a specified region.       */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - regionNum is an index into the region list   */
+/*        array.                                       */
+/*Post:                                                */
+/*      - the number of points that classify the       */
+/*        region whose index is specified by regionNum */
+/*        is returned.                                 */
+/*******************************************************/
+
+int RegionList::GetRegionCount(int regionNum)
+{
+	//return the region count of a specified region
+	return regionList[regionNum].pointCount;
+}
+
+/*******************************************************/
+/*Get Region Indeces                                   */
+/*******************************************************/
+/*Returns the point indeces specifying a region.       */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - regionNum is an index into the region list   */
+/*        array.                                       */
+/*Post:                                                */
+/*      - the region indeces specifying the points     */
+/*        contained by the region specified by region- */
+/*        Num are returned.                            */
+/*******************************************************/
+
+int *RegionList::GetRegionIndeces(int regionNum)
+{
+	//return point indeces using regionNum
+	return &indexTable[regionList[regionNum].region];
+}
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     PRIVATE METHODS     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+
+  /*/\/\/\/\/\/\/\/\/\/\/\*/
+  /*  Class Error Handler */
+  /*\/\/\/\/\/\/\/\/\/\/\/*/
+
+/*******************************************************/
+/*Error Handler                                        */
+/*******************************************************/
+/*Class error handler.                                 */
+/*******************************************************/
+/*Pre:                                                 */
+/*      - functName is the name of the function that   */
+/*        caused an error                              */
+/*      - errmsg is the error message given by the     */
+/*        calling function                             */
+/*      - status is the error status: FATAL or NON-    */
+/*        FATAL                                        */
+/*Post:                                                */
+/*      - the error message errmsg is flagged on beh-  */
+/*        ave of function functName.                   */
+/*      - if the error status is FATAL then the program*/
+/*        is halted, otherwise execution is continued, */
+/*        error recovery is assumed to be handled by   */
+/*        the calling function.                        */
+/*******************************************************/
+
+void RegionList::ErrorHandler(char *functName, char* errmsg, ErrorType status)
+{
+
+	//flag error message on behalf of calling function, error format
+	//specified by the error status...
+	if(status == NONFATAL)
+		fprintf(stderr, (char *)"\n%s Error: %s\n", functName, errmsg);
+	else
+	{
+		fprintf(stderr, (char *)"\n%s Fatal Error: %s\n\nAborting Program.\n\n", functName, errmsg);
+		exit(1);
+	}
+
+}
+
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ END OF CLASS DEFINITION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
+/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

+ 337 - 0
edisonSegm/rlist.h

@@ -0,0 +1,337 @@
+/*******************************************************
+
+                 Mean Shift Analysis Library
+	=============================================
+
+
+	The mean shift library is a collection of routines
+	that use the mean shift algorithm. Using this algorithm,
+	the necessary output will be generated needed
+	to analyze a given input set of data.
+
+  Region List Class:
+  =================
+
+	During segmentation, data regions are defined. The 
+	RegionList class provides a mechanism for doing so, as
+	well as defines some basic operations, such as region
+	growing or small region pruning, on the defined regions.
+	The prototype for the RegionList class is provided below. It
+	is defined in "region.cc".
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+									 space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+
+#ifndef RLIST_H
+#define RLIST_H
+
+//include global type definitions
+#include	"tdef.h"
+
+//define region structure
+struct REGION {
+	int			label;
+	int			pointCount;
+	int			region;
+
+};
+
+//region class prototype...
+class RegionList {
+
+public:
+
+  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+  /* Class Constructor and Destructor */
+  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|               *  Class Constructor  *              |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Constructs a region list object.                 |//
+  //|                                                    |//
+  //|   Its arguments are:                               |//
+  //|                                                    |//
+  //|   <* maxRegions *>                                 |//
+  //|   The maximum amount of regions that can be class- |//
+  //|   ified by the region list.                        |//
+  //|                                                    |//
+  //|   <* L *>                                          |//
+  //|   The length of the input data set being class-    |//
+  //|   ified by the region list object.                 |//
+  //|                                                    |//
+  //|   <* N *>                                          |//
+  //|   The dimension of the input data set being class- |//
+  //|   ified by the region list object.                 |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|     RegionList(maxRegions, L, N)                   |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+	RegionList(int, int, int);
+
+	// Class Destructor
+	~RegionList( void );
+
+  /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/
+  /*  Region List Manipulation  */
+  /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|                *  Add Region  *                    |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Adds a region to the region list.                |//
+  //|                                                    |//
+  //|   Its arguments are:                               |//
+  //|                                                    |//
+  //|   <* label *>                                      |//
+  //|                                                    |//
+  //|   A positive integer used to uniquely identify     |//
+  //|   a region.                                        |//
+  //|                                                    |//
+  //|   <* pointCount *>                                 |//
+  //|   A positive integer that specifies the number of  |//
+  //|   N-dimensional data points that exist in the re-  |//
+  //|   gion being classified.                           |//
+  //|                                                    |//
+  //|   <* indeces *>                                    |//
+  //|   An integer array that specifies the set of ind-  |//
+  //|   eces of the data points that are contianed with- |//
+  //|   in this region.                                  |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|     AddRegion(label, pointCount, indeces)          |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+	void AddRegion(int, int, int*);
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|                    *  Reset  *                     |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Resets the region list for re-use (for new       |//
+  //|   classification).                                 |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+	void Reset( void );	
+
+  /*/\/\/\/\/\/\/\/\/\/\*/
+  /*  Query Region List */
+  /*\/\/\/\/\/\/\/\/\/\/*/
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|          *  Get Number of Regions  *               |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Returns the number of regions stored by the      |//
+  //|   region list.                                     |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+	int	GetNumRegions ( void );
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|                  *  Get Label  *                   |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Returns the label of a specified region.         |//
+  //|                                                    |//
+  //|   Its arguments are:                               |//
+  //|                                                    |//
+  //|   <* regionNumber *>                               |//
+  //|   The index of the region in the region list       |//
+  //|   array.                                           |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|     label = GetLabel(regionNumber)                 |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+	int	GetLabel(int);
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|                *  Get Region Count  *              |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Returns number of data points contained by a sp- |//
+  //|   ecified region.                                  |//
+  //|                                                    |//
+  //|   Its arguments are:                               |//
+  //|                                                    |//
+  //|   <* regionNumber *>                               |//
+  //|   The index of the region in the region list       |//
+  //|   array.                                           |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|     pointCount = GetRegionCount(regionNumber)      |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+	int GetRegionCount(int);
+
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Method Name:								     |//
+  //|   ============								     |//
+  //|               *  Get Region Indeces  *             |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Description:								     |//
+  //|	============								     |//
+  //|                                                    |//
+  //|   Returns a pointer to a set of grid location ind- |//
+  //|   eces specifying the data points belonging to a   |//
+  //|   specified region.                                |//
+  //|                                                    |//
+  //|   Its arguments are:                               |//
+  //|                                                    |//
+  //|   <* regionNumber *>                               |//
+  //|   The index of the region in the region list       |//
+  //|   array.                                           |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //|                                                    |//
+  //|	Usage:      								     |//
+  //|   ======      								     |//
+  //|     indeces = GetRegionIndeces(regionNumber)       |//
+  //|                                                    |//
+  //<--------------------------------------------------->|//
+  //--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//--\\||//
+
+	int*GetRegionIndeces(int);
+
+private:
+
+  /*/\/\/\/\/\/\/\/\/\/\/\*/
+  /*  Class Error Handler */
+  /*\/\/\/\/\/\/\/\/\/\/\/*/
+
+	void ErrorHandler(char*, char*, ErrorType);
+
+  //=============================
+  // *** Private Data Members ***
+  //=============================
+
+	//#####################################
+	//### REGION LIST PARTITIONED ARRAY ###
+	//#####################################
+
+	REGION		*regionList;			//array of maxRegions regions
+	int			minRegion;
+
+	int			maxRegions;				//defines the number maximum number of regions
+										//allowed (determined by user during class construction)
+	int			numRegions;				//the number of regions currently stored by the
+										//region list
+	int			freeRegion;				//an index into the regionList pointing to the next
+										//available region in the regionList
+
+	//#####################################
+	//###         INDEX TABLE           ###
+	//#####################################
+
+	int			*indexTable;			//an array of indexes that point into an external structure
+										//specifying which points belong to a region
+	int			freeBlockLoc;			//points to the next free block of memory in the indexTable
+
+	//#####################################
+	//###     INPUT DATA PARAMETERS     ###
+	//#####################################
+
+	//Dimension of data set
+	int			N;						//dimension of data set being classified by region list
+										//class
+
+	//Length of the data set
+	int			L;						//number of points contained by the data set being classified by
+										//region list class
+
+};
+
+#endif
+
+
+

+ 51 - 0
edisonSegm/tdef.h

@@ -0,0 +1,51 @@
+/*******************************************************
+
+                 Mean Shift Analysis Library
+	=============================================
+
+	The mean shift library is a collection of routines
+	that use the mean shift algorithm. Using this algorithm,
+	the necessary output will be generated needed
+	to analyze a given input set of data.
+
+  Type Defintions:
+  ===============
+
+	This header file contains the type defintions and
+	enumerations shared among the various classes of the mean
+	shift library.
+
+The theory is described in the papers:
+
+  D. Comaniciu, P. Meer: Mean Shift: A robust approach toward feature
+									 space analysis.
+
+  C. Christoudias, B. Georgescu, P. Meer: Synergism in low level vision.
+
+and they are is available at:
+  http://www.caip.rutgers.edu/riul/research/papers/
+
+Implemented by Chris M. Christoudias, Bogdan Georgescu
+********************************************************/
+
+#ifndef TDEF_H
+#define TDEF_H
+
+/*/\/\/\/\/\/\/\/\/\/\/\*/
+/* Define Enumerations  */
+/*\/\/\/\/\/\/\/\/\/\/\/*/
+
+//Kernel
+enum kernelType		{Uniform, Gaussian, UserDefined};
+
+// kd-Tree
+enum childType		{LEFT, RIGHT};
+
+// Speed Up Level
+enum SpeedUpLevel	{NO_SPEEDUP, MED_SPEEDUP, HIGH_SPEEDUP};
+
+// Error Handler
+enum ErrorLevel		{EL_OKAY, EL_ERROR, EL_HALT};
+enum ErrorType		{NONFATAL, FATAL};
+
+#endif

+ 339 - 0
felzenszwalb/COPYING

@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 23 - 0
felzenszwalb/Makefile

@@ -0,0 +1,23 @@
+INCDIR = -I.
+DBG    = -g
+OPT    = -O3
+CPP    = g++
+CFLAGS = $(DBG) $(OPT) $(INCDIR)
+LINK   = -lm 
+
+.cpp.o:
+	$(CPP) $(CFLAGS) -c $< -o $@
+
+all: segment
+
+segment: segment.cpp segment-image.h segment-graph.h disjoint-set.h
+	$(CPP) $(CFLAGS) -o segment segment.cpp $(LINK)
+
+clean:
+	/bin/rm -f segment *.o
+
+clean-all: clean
+	/bin/rm -f *~ 
+
+
+

+ 25 - 0
felzenszwalb/README

@@ -0,0 +1,25 @@
+
+Implementation of the segmentation algorithm described in:
+
+Efficient Graph-Based Image Segmentation
+Pedro F. Felzenszwalb and Daniel P. Huttenlocher
+International Journal of Computer Vision, 59(2) September 2004.
+
+The program takes a color image (PPM format) and produces a segmentation
+with a random color assigned to each region.
+
+1) Type "make" to compile "segment".
+
+2) Run "segment sigma k min input output".
+
+The parameters are: (see the paper for details)
+
+sigma: Used to smooth the input image before segmenting it.
+k: Value for the threshold function.
+min: Minimum component size enforced by post-processing.
+input: Input image.
+output: Output image.
+
+Typical parameters are sigma = 0.5, k = 500, min = 20.
+Larger values for k result in larger components in the result.
+

+ 76 - 0
felzenszwalb/convolve.h

@@ -0,0 +1,76 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+/* convolution */
+
+#ifndef CONVOLVE_H
+#define CONVOLVE_H
+
+#ifdef NICE_USELIB_OPENMP
+#include <omp.h>
+#endif
+
+#include <vector>
+#include <algorithm>
+#include <cmath>
+#include "segmentation/felzenszwalb/image.h"
+namespace felzenszwalb {
+/* convolve src with mask.  dst is flipped! */
+static void convolve_even(image<float> *src, image<float> *dst,
+                          std::vector<float> &mask) {
+  int width = src->width();
+  int height = src->height();
+  int len = mask.size();
+#pragma omp parallel for
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      float sum = mask[0] * imRef(src, x, y);
+      for (int i = 1; i < len; i++) {
+        sum += mask[i] *
+               (imRef(src, std::max(x - i, 0), y) +
+                imRef(src, std::min(x + i, width - 1), y));
+      }
+      imRef(dst, y, x) = sum;
+    }
+  }
+}
+
+/* convolve src with mask.  dst is flipped! */
+static void convolve_odd(image<float> *src, image<float> *dst,
+                         std::vector<float> &mask) {
+  int width = src->width();
+  int height = src->height();
+  int len = mask.size();
+
+#pragma omp parallel for
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      float sum = mask[0] * imRef(src, x, y);
+      for (int i = 1; i < len; i++) {
+        sum += mask[i] *
+               (imRef(src, std::max(x - i, 0), y) -
+                imRef(src, std::min(x + i, width - 1), y));
+      }
+      imRef(dst, y, x) = sum;
+    }
+  }
+}
+
+}//namespace
+
+#endif

+ 81 - 0
felzenszwalb/disjoint-set.h

@@ -0,0 +1,81 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+#ifndef DISJOINT_SET
+#define DISJOINT_SET
+
+// disjoint-set forests using union-by-rank and path compression (sort of).
+namespace felzenszwalb{
+typedef struct {
+  int rank;
+  int p;
+  int size;
+} uni_elt;
+
+class universe {
+public:
+  universe(int elements);
+  ~universe();
+  int find(int x);  
+  void join(int x, int y);
+  int size(int x) const { return elts[x].size; }
+  int num_sets() const { return num; }
+
+private:
+  uni_elt *elts;
+  int num;
+};
+
+universe::universe(int elements) {
+  elts = new uni_elt[elements];
+  num = elements;
+  for (int i = 0; i < elements; i++) {
+    elts[i].rank = 0;
+    elts[i].size = 1;
+    elts[i].p = i;
+  }
+}
+  
+universe::~universe() {
+  delete [] elts;
+}
+
+int universe::find(int x) {
+  int y = x;
+  while (y != elts[y].p)
+    y = elts[y].p;
+  elts[x].p = y;
+  return y;
+}
+
+void universe::join(int x, int y) {
+  if (elts[x].rank > elts[y].rank) {
+    elts[y].p = x;
+    elts[x].size += elts[y].size;
+  } else {
+    elts[x].p = y;
+    elts[y].size += elts[x].size;
+    if (elts[x].rank == elts[y].rank)
+      elts[y].rank++;
+  }
+  num--;
+}
+
+}//namespace
+
+#endif

+ 103 - 0
felzenszwalb/filter.h

@@ -0,0 +1,103 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+/* simple filters */
+
+#ifndef FILTER_H
+#define FILTER_H
+
+#include <vector>
+#include <cmath>
+#include "segmentation/felzenszwalb/image.h"
+#include "segmentation/felzenszwalb/misc.h"
+#include "segmentation/felzenszwalb/convolve.h"
+#include "segmentation/felzenszwalb/imconv.h"
+
+#define WIDTH 4.0
+namespace felzenszwalb{
+/* normalize mask so it integrates to one */
+static void normalize(std::vector<float> &mask) {
+  int len = mask.size();
+  float sum = 0;
+  for (int i = 1; i < len; i++) {
+    sum += fabs(mask[i]);
+  }
+  sum = 2*sum + fabs(mask[0]);
+  for (int i = 0; i < len; i++) {
+    mask[i] /= sum;
+  }
+}
+
+/* make filters */
+#define MAKE_FILTER(name, fun)                                \
+static std::vector<float> make_ ## name (float sigma) {       \
+  sigma = std::max(sigma, 0.01F);			      \
+  int len = (int)ceil(sigma * WIDTH) + 1;                     \
+  std::vector<float> mask(len);                               \
+  for (int i = 0; i < len; i++) {                             \
+    mask[i] = fun;                                            \
+  }                                                           \
+  return mask;                                                \
+}
+
+MAKE_FILTER(fgauss, exp(-0.5*square(i/sigma)));
+
+/* convolve image with gaussian filter */
+static image<float> *smooth(image<float> *src, float sigma) {
+  std::vector<float> mask = make_fgauss(sigma);
+  normalize(mask);
+
+  image<float> *tmp = new image<float>(src->height(), src->width(), false);
+  image<float> *dst = new image<float>(src->width(), src->height(), false);
+  convolve_even(src, tmp, mask);
+  convolve_even(tmp, dst, mask);
+
+  delete tmp;
+  return dst;
+}
+
+/* convolve image with gaussian filter */
+image<float> *smooth(image<uchar> *src, float sigma) {
+  image<float> *tmp = imageUCHARtoFLOAT(src);
+  image<float> *dst = smooth(tmp, sigma);
+  delete tmp;
+  return dst;
+}
+
+/* compute laplacian */
+static image<float> *laplacian(image<float> *src) {
+  int width = src->width();
+  int height = src->height();
+  image<float> *dst = new image<float>(width, height);  
+
+#pragma omp parallel for
+  for (int y = 1; y < height-1; y++) {
+    for (int x = 1; x < width-1; x++) {
+      float d2x = imRef(src, x-1, y) + imRef(src, x+1, y) -
+	2*imRef(src, x, y);
+      float d2y = imRef(src, x, y-1) + imRef(src, x, y+1) -
+	2*imRef(src, x, y);
+      imRef(dst, x, y) = d2x + d2y;
+    }
+  }
+  return dst;
+}
+
+}//namespace
+
+#endif

+ 103 - 0
felzenszwalb/image.h

@@ -0,0 +1,103 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+/* a simple image class */
+
+#ifndef IMAGE_H
+#define IMAGE_H
+
+#include <cstring>
+namespace felzenszwalb{
+template <class T>
+class image {
+ public:
+  /* create an image */
+  image(const int width, const int height, const bool init = true);
+
+  /* delete an image */
+  ~image();
+
+  /* init an image */
+  void init(const T &val);
+
+  /* copy an image */
+  image<T> *copy() const;
+  
+  /* get the width of an image. */
+  int width() const { return w; }
+  
+  /* get the height of an image. */
+  int height() const { return h; }
+  
+  /* image data. */
+  T *data;
+  
+  /* row pointers. */
+  T **access;
+  
+ private:
+  int w, h;
+};
+
+/* use imRef to access image data. */
+#define imRef(im, x, y) (im->access[y][x])
+  
+/* use imPtr to get pointer to image data. */
+#define imPtr(im, x, y) &(im->access[y][x])
+
+template <class T>
+image<T>::image(const int width, const int height, const bool init) {
+  w = width;
+  h = height;
+  data = new T[w * h];  // allocate space for image data
+  access = new T*[h];   // allocate space for row pointers
+  
+  // initialize row pointers
+  for (int i = 0; i < h; i++)
+    access[i] = data + (i * w);  
+  
+  if (init)
+    memset(data, 0, w * h * sizeof(T));
+}
+
+template <class T>
+image<T>::~image() {
+  delete [] data; 
+  delete [] access;
+}
+
+template <class T>
+void image<T>::init(const T &val) {
+  T *ptr = imPtr(this, 0, 0);
+  T *end = imPtr(this, w-1, h-1);
+  while (ptr <= end)
+    *ptr++ = val;
+}
+
+
+template <class T>
+image<T> *image<T>::copy() const {
+  image<T> *im = new image<T>(w, h, false);
+  memcpy(im->data, data, w * h * sizeof(T));
+  return im;
+}
+
+}//namespace
+
+#endif
+  

+ 181 - 0
felzenszwalb/imconv.h

@@ -0,0 +1,181 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+/* image conversion */
+
+#ifndef CONV_H
+#define CONV_H
+
+#include <climits>
+#include "segmentation/felzenszwalb/image.h"
+#include "segmentation/felzenszwalb/imutil.h"
+#include "segmentation/felzenszwalb/misc.h"
+
+#define RED_WEIGHT 0.299
+#define GREEN_WEIGHT 0.587
+#define BLUE_WEIGHT 0.114
+
+namespace felzenszwalb {
+
+static image<uchar> *imageRGBtoGRAY(image<rgb> *input) {
+  int width = input->width();
+  int height = input->height();
+  image<uchar> *output = new image<uchar>(width, height, false);
+
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      imRef(output, x, y) = (uchar)
+                            (imRef(input, x, y).r * RED_WEIGHT +
+                             imRef(input, x, y).g * GREEN_WEIGHT +
+                             imRef(input, x, y).b * BLUE_WEIGHT);
+    }
+  }
+  return output;
+}
+
+static image<rgb> *imageGRAYtoRGB(image<uchar> *input) {
+  int width = input->width();
+  int height = input->height();
+  image<rgb> *output = new image<rgb>(width, height, false);
+
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      imRef(output, x, y).r = imRef(input, x, y);
+      imRef(output, x, y).g = imRef(input, x, y);
+      imRef(output, x, y).b = imRef(input, x, y);
+    }
+  }
+  return output;
+}
+
+static image<float> *imageUCHARtoFLOAT(image<uchar> *input) {
+  int width = input->width();
+  int height = input->height();
+  image<float> *output = new image<float>(width, height, false);
+
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      imRef(output, x, y) = imRef(input, x, y);
+    }
+  }
+  return output;
+}
+
+static image<float> *imageINTtoFLOAT(image<int> *input) {
+  int width = input->width();
+  int height = input->height();
+  image<float> *output = new image<float>(width, height, false);
+
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      imRef(output, x, y) = imRef(input, x, y);
+    }
+  }
+  return output;
+}
+
+static image<uchar> *imageFLOATtoUCHAR(image<float> *input,
+                                       float min, float max) {
+  int width = input->width();
+  int height = input->height();
+  image<uchar> *output = new image<uchar>(width, height, false);
+
+  if (max == min)
+    return output;
+
+  float scale = UCHAR_MAX / (max - min);
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      uchar val = (uchar)((imRef(input, x, y) - min) * scale);
+      imRef(output, x, y) = bound(val, (uchar)0, (uchar)UCHAR_MAX);
+    }
+  }
+  return output;
+}
+
+static image<uchar> *imageFLOATtoUCHAR(image<float> *input) {
+  float min, max;
+  min_max(input, &min, &max);
+  return imageFLOATtoUCHAR(input, min, max);
+}
+
+static image<long> *imageUCHARtoLONG(image<uchar> *input) {
+  int width = input->width();
+  int height = input->height();
+  image<long> *output = new image<long>(width, height, false);
+
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      imRef(output, x, y) = imRef(input, x, y);
+    }
+  }
+  return output;
+}
+
+static image<uchar> *imageLONGtoUCHAR(image<long> *input, long min, long max) {
+  int width = input->width();
+  int height = input->height();
+  image<uchar> *output = new image<uchar>(width, height, false);
+
+  if (max == min)
+    return output;
+
+  float scale = UCHAR_MAX / (float)(max - min);
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      uchar val = (uchar)((imRef(input, x, y) - min) * scale);
+      imRef(output, x, y) = bound(val, (uchar)0, (uchar)UCHAR_MAX);
+    }
+  }
+  return output;
+}
+
+static image<uchar> *imageLONGtoUCHAR(image<long> *input) {
+  long min, max;
+  min_max(input, &min, &max);
+  return imageLONGtoUCHAR(input, min, max);
+}
+
+static image<uchar> *imageSHORTtoUCHAR(image<short> *input,
+                                       short min, short max) {
+  int width = input->width();
+  int height = input->height();
+  image<uchar> *output = new image<uchar>(width, height, false);
+
+  if (max == min)
+    return output;
+
+  float scale = UCHAR_MAX / (float)(max - min);
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      uchar val = (uchar)((imRef(input, x, y) - min) * scale);
+      imRef(output, x, y) = bound(val, (uchar)0, (uchar)UCHAR_MAX);
+    }
+  }
+  return output;
+}
+
+static image<uchar> *imageSHORTtoUCHAR(image<short> *input) {
+  short min, max;
+  min_max(input, &min, &max);
+  return imageSHORTtoUCHAR(input, min, max);
+}
+
+}//namespace
+
+#endif

+ 70 - 0
felzenszwalb/imutil.h

@@ -0,0 +1,70 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+/* some image utilities */
+
+#ifndef IMUTIL_H
+#define IMUTIL_H
+
+#include "segmentation/felzenszwalb/image.h"
+#include "segmentation/felzenszwalb/misc.h"
+
+namespace felzenszwalb {
+
+/* compute minimum and maximum value in an image */
+template <class T>
+void min_max(image<T> *im, T *ret_min, T *ret_max) {
+  int width = im->width();
+  int height = im->height();
+
+  T min = imRef(im, 0, 0);
+  T max = imRef(im, 0, 0);
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      T val = imRef(im, x, y);
+      if (min > val)
+        min = val;
+      if (max < val)
+        max = val;
+    }
+  }
+
+  *ret_min = min;
+  *ret_max = max;
+}
+
+/* threshold image */
+template <class T>
+image<uchar> *threshold(image<T> *src, int t) {
+  int width = src->width();
+  int height = src->height();
+  image<uchar> *dst = new image<uchar>(width, height);
+
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      imRef(dst, x, y) = (imRef(src, x, y) >= t);
+    }
+  }
+
+  return dst;
+}
+
+}//namespace
+
+#endif
+

+ 69 - 0
felzenszwalb/misc.h

@@ -0,0 +1,69 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+/* random stuff */
+
+#ifndef MISC_H
+#define MISC_H
+
+#include <cmath>
+
+#ifndef M_PI
+#define M_PI 3.141592653589793
+#endif
+
+namespace felzenszwalb{
+
+typedef unsigned char uchar;
+
+typedef struct { uchar r, g, b; } rgb;
+
+inline bool operator==(const rgb &a, const rgb &b) {
+  return ((a.r == b.r) && (a.g == b.g) && (a.b == b.b));
+}
+
+template <class T>
+inline T abs(const T &x) { return (x > 0 ? x : -x); };
+
+template <class T>
+inline int sign(const T &x) { return (x >= 0 ? 1 : -1); };
+
+template <class T>
+inline T square(const T &x) { return x*x; };
+
+template <class T>
+inline T bound(const T &x, const T &min, const T &max) {
+  return (x < min ? min : (x > max ? max : x));
+}
+
+template <class T>
+inline bool check_bound(const T &x, const T&min, const T &max) {
+  return ((x < min) || (x > max));
+}
+
+inline int vlib_round(float x) { return (int)(x + 0.5F); }
+
+inline int vlib_round(double x) { return (int)(x + 0.5); }
+
+inline double gaussian(double val, double sigma) {
+  return exp(-square(val/sigma)/2)/(sqrt(2*M_PI)*sigma);
+}
+
+}//namespace
+
+#endif

+ 213 - 0
felzenszwalb/pnmfile.h

@@ -0,0 +1,213 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+/* basic image I/O */
+
+#ifndef PNM_FILE_H
+#define PNM_FILE_H
+
+#include <cstdlib>
+#include <climits>
+#include <cstring>
+#include <fstream>
+#include "segmentation/felzenszwalb/image.h"
+#include "segmentation/felzenszwalb/misc.h"
+
+#define BUF_SIZE 256
+namespace felzenszwalb{
+class pnm_error { };
+
+static void read_packed(unsigned char *data, int size, std::ifstream &f) {
+  unsigned char c = 0;
+  
+  int bitshift = -1;
+  for (int pos = 0; pos < size; pos++) {
+    if (bitshift == -1) {
+      c = f.get();
+      bitshift = 7;
+    }
+    data[pos] = (c >> bitshift) & 1;
+    bitshift--;
+    }
+}
+
+static void write_packed(unsigned char *data, int size, std::ofstream &f) {
+  unsigned char c = 0;
+  
+  int bitshift = 7;
+  for (int pos = 0; pos < size; pos++) {
+      c = c | (data[pos] << bitshift);
+      bitshift--;
+      if ((bitshift == -1) || (pos == size-1)) {
+	f.put(c);
+	bitshift = 7;
+	c = 0;
+      }
+  }
+}
+
+/* read PNM field, skipping comments */ 
+static void pnm_read(std::ifstream &file, char *buf) {
+  char doc[BUF_SIZE];
+  char c;
+  
+  file >> c;
+  while (c == '#') {
+    file.getline(doc, BUF_SIZE);
+    file >> c;
+  }
+  file.putback(c);
+  
+  file.width(BUF_SIZE);
+  file >> buf;
+  file.ignore();
+}
+
+static image<uchar> *loadPBM(const char *name) {
+  char buf[BUF_SIZE];
+  
+  /* read header */
+  std::ifstream file(name, std::ios::in | std::ios::binary);
+  pnm_read(file, buf);
+  if (strncmp(buf, "P4", 2))
+    throw pnm_error();
+    
+  pnm_read(file, buf);
+  int width = atoi(buf);
+  pnm_read(file, buf);
+  int height = atoi(buf);
+  
+  /* read data */
+  image<uchar> *im = new image<uchar>(width, height);
+  for (int i = 0; i < height; i++)
+    read_packed(imPtr(im, 0, i), width, file);
+  
+  return im;
+}
+
+static void savePBM(image<uchar> *im, const char *name) {
+  int width = im->width();
+  int height = im->height();
+  std::ofstream file(name, std::ios::out | std::ios::binary);
+
+  file << "P4\n" << width << " " << height << "\n";
+  for (int i = 0; i < height; i++)
+    write_packed(imPtr(im, 0, i), width, file);
+}
+
+static image<uchar> *loadPGM(const char *name) {
+  char buf[BUF_SIZE];
+  
+  /* read header */
+  std::ifstream file(name, std::ios::in | std::ios::binary);
+  pnm_read(file, buf);
+  if (strncmp(buf, "P5", 2))
+    throw pnm_error();
+
+  pnm_read(file, buf);
+  int width = atoi(buf);
+  pnm_read(file, buf);
+  int height = atoi(buf);
+
+  pnm_read(file, buf);
+  if (atoi(buf) > UCHAR_MAX)
+    throw pnm_error();
+
+  /* read data */
+  image<uchar> *im = new image<uchar>(width, height);
+  file.read((char *)imPtr(im, 0, 0), width * height * sizeof(uchar));
+
+  return im;
+}
+
+static void savePGM(image<uchar> *im, const char *name) {
+  int width = im->width();
+  int height = im->height();
+  std::ofstream file(name, std::ios::out | std::ios::binary);
+
+  file << "P5\n" << width << " " << height << "\n" << UCHAR_MAX << "\n";
+  file.write((char *)imPtr(im, 0, 0), width * height * sizeof(uchar));
+}
+
+static image<rgb> *loadPPM(const char *name) {
+  char buf[BUF_SIZE], doc[BUF_SIZE];
+  
+  /* read header */
+  std::ifstream file(name, std::ios::in | std::ios::binary);
+  pnm_read(file, buf);
+  if (strncmp(buf, "P6", 2))
+    throw pnm_error();
+
+  pnm_read(file, buf);
+  int width = atoi(buf);
+  pnm_read(file, buf);
+  int height = atoi(buf);
+
+  pnm_read(file, buf);
+  if (atoi(buf) > UCHAR_MAX)
+    throw pnm_error();
+
+  /* read data */
+  image<rgb> *im = new image<rgb>(width, height);
+  file.read((char *)imPtr(im, 0, 0), width * height * sizeof(rgb));
+
+  return im;
+}
+
+static void savePPM(image<rgb> *im, const char *name) {
+  int width = im->width();
+  int height = im->height();
+  std::ofstream file(name, std::ios::out | std::ios::binary);
+
+  file << "P6\n" << width << " " << height << "\n" << UCHAR_MAX << "\n";
+  file.write((char *)imPtr(im, 0, 0), width * height * sizeof(rgb));
+}
+
+template <class T>
+void load_image(image<T> **im, const char *name) {
+  char buf[BUF_SIZE];
+  
+  /* read header */
+  std::ifstream file(name, std::ios::in | std::ios::binary);
+  pnm_read(file, buf);
+  if (strncmp(buf, "VLIB", 9))
+    throw pnm_error();
+
+  pnm_read(file, buf);
+  int width = atoi(buf);
+  pnm_read(file, buf);
+  int height = atoi(buf);
+
+  /* read data */
+  *im = new image<T>(width, height);
+  file.read((char *)imPtr((*im), 0, 0), width * height * sizeof(T));
+}
+
+template <class T>
+void save_image(image<T> *im, const char *name) {
+  int width = im->width();
+  int height = im->height();
+  std::ofstream file(name, std::ios::out | std::ios::binary);
+
+  file << "VLIB\n" << width << " " << height << "\n";
+  file.write((char *)imPtr(im, 0, 0), width * height * sizeof(T));
+}
+
+}//namespace
+
+#endif

+ 86 - 0
felzenszwalb/segment-graph.h

@@ -0,0 +1,86 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+#ifndef SEGMENT_GRAPH
+#define SEGMENT_GRAPH
+
+#include <algorithm>
+#include <cmath>
+#include "segmentation/felzenszwalb/disjoint-set.h"
+
+// threshold function
+#define THRESHOLD(size, c) (c/size)
+namespace felzenszwalb{
+typedef struct {
+  float w;
+  int a, b;
+} edge;
+
+bool operator<(const edge &a, const edge &b) {
+  return a.w < b.w;
+}
+
+/*
+ * Segment a graph
+ *
+ * Returns a disjoint-set forest representing the segmentation.
+ *
+ * num_vertices: number of vertices in graph.
+ * num_edges: number of edges in graph
+ * edges: array of edges.
+ * c: constant for treshold function.
+ */
+universe *segment_graph(int num_vertices, int num_edges, edge *edges, 
+			float c) { 
+  // sort edges by weight
+  std::sort(edges, edges + num_edges);
+
+  // make a disjoint-set forest
+  universe *u = new universe(num_vertices);
+
+  // init thresholds
+  float *threshold = new float[num_vertices];
+#pragma omp parallel for
+  for (int i = 0; i < num_vertices; i++)
+    threshold[i] = THRESHOLD(1,c);
+
+  // for each edge, in non-decreasing weight order...
+  for (int i = 0; i < num_edges; i++) {
+    edge *pedge = &edges[i];
+    
+    // components conected by this edge
+    int a = u->find(pedge->a);
+    int b = u->find(pedge->b);
+    if (a != b) {
+      if ((pedge->w <= threshold[a]) &&
+	  (pedge->w <= threshold[b])) {
+	u->join(a, b);
+	a = u->find(a);
+	threshold[a] = pedge->w + THRESHOLD(u->size(a), c);
+      }
+    }
+  }
+
+  // free up
+  delete threshold;
+  return u;
+}
+
+}//namespace
+
+#endif

+ 173 - 0
felzenszwalb/segment-image.h

@@ -0,0 +1,173 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+#ifndef SEGMENT_IMAGE
+#define SEGMENT_IMAGE
+
+#ifdef NICE_USELIB_OPENMP
+#include <omp.h>
+#endif
+
+#include <cstdlib>
+#include <segmentation/felzenszwalb/image.h>
+#include <segmentation/felzenszwalb/misc.h>
+#include <segmentation/felzenszwalb/filter.h>
+#include "segmentation/felzenszwalb/segment-graph.h"
+
+namespace felzenszwalb {
+// random color
+rgb random_rgb() {
+  rgb c;
+  double r;
+
+  c.r = (uchar)random();
+  c.g = (uchar)random();
+  c.b = (uchar)random();
+
+  return c;
+}
+
+// dissimilarity measure between pixels
+static inline float diff(image<float> *r, image<float> *g, image<float> *b,
+                         int x1, int y1, int x2, int y2) {
+  return sqrt(square(imRef(r, x1, y1) - imRef(r, x2, y2)) +
+              square(imRef(g, x1, y1) - imRef(g, x2, y2)) +
+              square(imRef(b, x1, y1) - imRef(b, x2, y2)));
+}
+
+/*
+ * Segment an image
+ *
+ * Returns a color image representing the segmentation.
+ *
+ * im: image to segment.
+ * sigma: to smooth the image.
+ * c: constant for treshold function.
+ * min_size: minimum component size (enforced by post-processing stage).
+ * num_ccs: number of connected components in the segmentation.
+ */
+image<rgb> *segment_image(image<rgb> *im, float sigma, float c, int min_size,
+                          int *num_ccs) {
+  //clog << "\nsegment_image: Sprung in die Methode" << endl;
+  int width = im->width();
+  int height = im->height();
+  int size = width * height;
+
+  image<float> *r = new image<float>(width, height);
+  image<float> *g = new image<float>(width, height);
+  image<float> *b = new image<float>(width, height);
+
+  // smooth each color channel
+#pragma omp parallel for
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      imRef(r, x, y) = imRef(im, x, y).r;
+      imRef(g, x, y) = imRef(im, x, y).g;
+      imRef(b, x, y) = imRef(im, x, y).b;
+    }
+  }
+  image<float> *smooth_r = smooth(r, sigma);
+  image<float> *smooth_g = smooth(g, sigma);
+  image<float> *smooth_b = smooth(b, sigma);
+  delete r;
+  delete g;
+  delete b;
+
+  // build graph
+  //clog << "bulid graph: ... ";
+  edge *edges = new edge[size*4];
+  int num = 0;
+
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      if (x < width - 1) {
+        edges[num].a = y * width + x;
+        edges[num].b = y * width + (x + 1);
+        edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x + 1, y);
+        num++;
+      }
+
+      if (y < height - 1) {
+        edges[num].a = y * width + x;
+        edges[num].b = (y + 1) * width + x;
+        edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x, y + 1);
+        num++;
+      }
+
+      if ((x < width - 1) && (y < height - 1)) {
+        edges[num].a = y * width + x;
+        edges[num].b = (y + 1) * width + (x + 1);
+        edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x + 1, y + 1);
+        num++;
+      }
+
+      if ((x < width - 1) && (y > 0)) {
+        edges[num].a = y * width + x;
+        edges[num].b = (y - 1) * width + (x + 1);
+        edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x + 1, y - 1);
+        num++;
+      }
+    }
+  }
+//   clog << "fertig" << endl;
+  delete smooth_r;
+  delete smooth_g;
+  delete smooth_b;
+
+  // segment
+  //clog << "segment_graph: ... ";
+  universe *u = segment_graph(size, num, edges, c);
+  //clog << "fertig" << endl;
+
+  // post process small components
+#pragma omp parallel for
+  for (int i = 0; i < num; i++) {
+    int a = u->find(edges[i].a);
+    int b = u->find(edges[i].b);
+    if ((a != b) && ((u->size(a) < min_size) || (u->size(b) < min_size)))
+      u->join(a, b);
+  }
+  delete [] edges;
+  *num_ccs = u->num_sets();
+
+  image<rgb> *output = new image<rgb>(width, height);
+
+  // pick random colors for each component
+  //clog << "pick random colors for each component: ... ";
+  rgb *colors = new rgb[size];
+  for (int i = 0; i < size; i++)
+    colors[i] = random_rgb();
+//   clog << "/*fertig*/" << endl;
+#pragma omp parallel for
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      int comp = u->find(y * width + x);
+      imRef(output, x, y) = colors[comp];
+    }
+  }
+
+  delete [] colors;
+  delete u;
+
+  //clog << "segment_image: Sprung aus der Methode" << endl;
+  return output;
+}
+
+}//namespace
+
+#endif

+ 49 - 0
felzenszwalb/segment.cpp

@@ -0,0 +1,49 @@
+/*
+Copyright (C) 2006 Pedro Felzenszwalb
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+#include <cstdio>
+#include <cstdlib>
+#include <segmentation/felzenszwalb/image.h>
+#include <segmentation/felzenszwalb/misc.h>
+#include <segmentation/felzenszwalb/pnmfile.h>
+#include "segmentation/felzenszwalb/segment-image.h"
+
+int main(int argc, char **argv) {
+  if (argc != 6) {
+    fprintf(stderr, "usage: %s sigma k min input(ppm) output(ppm)\n", argv[0]);
+    return 1;
+  }
+
+  float sigma = atof(argv[1]);
+  float k = atof(argv[2]);
+  int min_size = atoi(argv[3]);
+
+  printf("loading input image.\n");
+  image<rgb> *input = loadPPM(argv[4]);
+
+  printf("processing\n");
+  int num_ccs;
+  image<rgb> *seg = segment_image(input, sigma, k, min_size, &num_ccs);
+  savePPM(seg, argv[5]);
+
+  printf("got %d components\n", num_ccs);
+  printf("done! uff...thats hard work.\n");
+
+  return 0;
+}
+

+ 3 - 0
libdepend.inc

@@ -0,0 +1,3 @@
+$(call PKG_DEPEND_EXT,OPENMP)
+$(call PKG_DEPEND_INT,core)
+$(call PKG_DEPEND_INT,vislearning)

+ 8 - 0
math/Makefile

@@ -0,0 +1,8 @@
+#TARGETS_FROM:=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM)
+#$(info recursivly going up: $(TARGETS_FROM) ($(shell pwd)))
+
+all:
+
+%:
+	$(MAKE) TARGETS_FROM=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM) -C .. $@
+

+ 103 - 0
math/Makefile.inc

@@ -0,0 +1,103 @@
+# LIBRARY-DIRECTORY-MAKEFILE
+# conventions:
+# - all subdirectories containing a "Makefile.inc" are considered sublibraries
+#   exception: "progs/" and "tests/" subdirectories!
+# - all ".C", ".cpp" and ".c" files in the current directory are linked to a
+#   library
+# - the library depends on all sublibraries 
+# - the library name is created with $(LIBNAME), i.e. it will be somehow
+#   related to the directory name and with the extension .a
+#   (e.g. lib1/sublib -> lib1_sublib.a)
+# - the library will be added to the default build list ALL_LIBRARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+ifeq "$(SUBDIR)" "./"
+SUBDIR:=
+endif
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# you can specify libraries needed by the individual objects or by the whole
+# directory. the object specific additional libraries are only considered
+# when compiling the specific object files
+# TODO: update documentation...
+
+-include $(SUBDIR)libdepend.inc
+
+$(foreach d,$(filter-out %progs %tests,$(SUBDIRS_OF_$(SUBDIR))),$(eval $(call PKG_DEPEND_INT,$(d))))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+	  $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+LIBRARY_BASENAME:=$(call LIBNAME,$(SUBDIR))
+ifneq "$(SUBDIR)" ""
+ALL_LIBRARIES+=$(LIBDIR)$(LIBRARY_BASENAME).$(LINK_FILE_EXTENSION)
+endif
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. the current library depends on all sublibraries.
+# all other dependencies have to be added manually by specifying, that the
+# current .pc file depends on some other .pc file. binaries depending on
+# libraries should exclusivelly use the .pc files as well.
+
+ifeq "$(SKIP_BUILD_$(OBJDIR))" "1"
+$(LIBDIR)$(LIBRARY_BASENAME).a:
+else
+$(LIBDIR)$(LIBRARY_BASENAME).a:$(OBJS) \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).a,.$(LINK_FILE_EXTENSION))
+endif
+
+$(PKGDIR)$(LIBRARY_BASENAME).pc: \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).pc,.pc)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 130 - 0
math/NodeCentricRepMatrix.cpp

@@ -0,0 +1,130 @@
+#include "NodeCentricRepMatrix.h"
+
+using namespace OBJREC;
+using namespace std;
+
+/** Member-Methodes **/
+NodeCentricRepMatrix::NodeCentricRepMatrix ( const uint m, const uint n, const uint e ) : std::valarray<double> ( m * n * e ) {
+  this->m = m;
+  this->n = n;
+  this->e = e;
+}
+NodeCentricRepMatrix::NodeCentricRepMatrix ( const NodeCentricRepMatrix& matrix ) : std::valarray<double> ( matrix ) {
+  this->m = matrix.getM();
+  this->n = matrix.getN();
+  this->e = matrix.getE();
+}
+
+
+NodeCentricRepMatrix::~NodeCentricRepMatrix() {}
+
+double NodeCentricRepMatrix::at ( uint m, uint n, uint e ) const {
+  checkRange ( m, n, e );
+  return valarray<double>::operator[] ( m * ( ( *this ).n * ( *this ).e ) + n * ( *this ).e + e );
+}
+
+double& NodeCentricRepMatrix::at ( uint m, uint n, uint e ) {
+  checkRange ( m, n, e );
+  return valarray<double>::operator[] ( m * ( ( *this ).n * ( *this ).e ) + n * ( *this ).e + e );
+}
+
+double NodeCentricRepMatrix::atQuick ( uint m, uint n, uint e ) const
+{
+  return valarray<double>::operator[] ( m * ( ( *this ).n * ( *this ).e ) + n * ( *this ).e + e );
+}
+
+double& NodeCentricRepMatrix::atQuick ( uint m, uint n, uint e )
+{
+  return valarray<double>::operator[] ( m * ( ( *this ).n * ( *this ).e ) + n * ( *this ).e + e );
+}
+
+
+void NodeCentricRepMatrix::checkRange ( uint m, uint n, uint e ) const {
+  if ( m >= ( *this ).m || n >= ( *this ).n || e >= ( *this ).e )
+    throw range_error ( "NodeCentricRepMatrix: You try to access an element outside the matrix!" );
+}
+
+NodeCentricRepMatrix& NodeCentricRepMatrix::operator= ( const NodeCentricRepMatrix & matrix ) {
+  // Selbstkopie verhindern
+  if ( this == &matrix ) return ( *this );
+
+  if ( ( *this ).getM() != matrix.getM() ||
+       ( *this ).getN() != matrix.getN() ||
+       ( *this ).getE() != matrix.getE() ) {
+    throw range_error ( "NodeCentricRepMatrix: Assigment not possible. Matrix-dim does not match." );
+  }
+
+  for ( uint i = 0; i < ( *this ).getN(); i++ ) {
+    for ( uint j = 0; j < ( *this ).getM(); j++ ) {
+      for ( uint e = 0; e < ( *this ).getE(); e++ ) {
+        ( *this ) ( j, i, e ) = matrix ( j, i, e );
+      }
+    }
+  }
+  return ( *this );
+}
+
+NodeCentricRepMatrix& NodeCentricRepMatrix::operator-= ( NodeCentricRepMatrix const & rhs )
+{
+  if ( ( *this ).getM() != rhs.getM() ||
+       ( *this ).getN() != rhs.getN() ||
+       ( *this ).getE() != rhs.getE() )
+  {
+    throw range_error ( "NodeCentricRepMatrix: Minus not possible. Matrix-dim does not match." );
+  }
+#pragma omp parallel for
+  for ( uint i = 0; i < ( *this ).getN(); i++ )
+  {
+    for ( uint j = 0; j < ( *this ).getM(); j++ )
+    {
+      for ( uint e = 0; e < ( *this ).getE(); e++ )
+      {
+        ( *this ) ( j, i, e ) -= rhs ( j, i, e );
+      }
+    }
+  }
+
+  return ( *this );
+}
+
+NodeCentricRepMatrix NodeCentricRepMatrix::operator- ( NodeCentricRepMatrix const& rhs )
+{
+  NodeCentricRepMatrix tmp ( ( *this ) );
+  tmp -= rhs;
+  return tmp;
+}
+
+double NodeCentricRepMatrix::operator() ( const uint m, const uint n, const uint e ) const
+{
+  return valarray<double>::operator[] ( m * ( ( *this ).n * ( *this ).e ) + n * ( *this ).e + e );
+}
+
+double& NodeCentricRepMatrix::operator() ( const uint m, const uint n, const uint e )
+{
+  return valarray<double>::operator[] ( m * ( ( *this ).n * ( *this ).e ) + n * ( *this ).e + e );
+}
+
+bool NodeCentricRepMatrix::changes ( const NodeCentricRepMatrix& matrix, double epsilon ) const {
+  if ( ( *this ).getM() != matrix.getM() ||
+       ( *this ).getN() != matrix.getN() ||
+       ( *this ).getE() != matrix.getE() ) {
+    throw range_error ( "NodeCentricRepMatrix: Calculate difference not possible. Matrix-dim does not match." );
+  }
+
+  bool retValue = false;
+
+//#pragma omp parallel for
+  for ( uint i = 0; i < ( *this ).getN(); i++ ) {
+    for ( uint j = 0; j < ( *this ).getM(); j++ ) {
+      for ( uint e = 0; e < ( *this ).getE(); e++ ) {
+        if ( abs ( ( *this ) ( j, i, e ) - matrix ( j, i, e ) ) > epsilon )
+        {
+          return true;
+        }
+
+      }
+    }
+  }
+  return retValue;
+}
+

+ 115 - 0
math/NodeCentricRepMatrix.h

@@ -0,0 +1,115 @@
+/**
+ *
+ *
+ */
+#ifndef NODECENTRICREPMATRIXINCLUDE
+#define NODECENTRICREPMATRIXINCLUDE
+
+/* System - includes */
+#include <sys/types.h>
+
+/* std - includes */
+#include <stdexcept>
+#include <iostream>
+#include <valarray>
+#include <cmath>
+
+/* omp - includes */
+#ifdef NICE_USELIB_OPENMP
+#include <omp.h>
+#endif
+
+namespace OBJREC
+{
+class NodeCentricRepMatrix : public std::valarray<double>
+{
+  private:
+    //! first dimension (y-axes)
+    uint m;
+    //! second dimension (x-axes)
+    uint n;
+    //! third dimension (number of edges departing from each node)
+    uint e;
+
+    //! check whether the given value is in the range of the given dim
+    void checkRange ( uint m, uint n, uint e ) const;
+
+    /** Matrix Access **/
+    //! returns the value at (y=m, x=n, e=e), without rangecheck
+    double atQuick ( uint m, uint n, uint e ) const;
+    //! returns a non-const referenz to the element at (y=m, x=n, e=e), without rangecheck
+    double& atQuick ( uint m, uint n, uint e );
+
+  public:
+    /* Constructor and Destructor */
+    /**
+    * @brief Simple constructor.
+    * @param uint - first dimension (y)
+    * @param uint - second dimension (x)
+    * @param uint - third dimension (e)
+    */
+    NodeCentricRepMatrix ( const uint m, const uint n, const uint e );
+    /**
+    * @brief Copy Constructor.
+    * @param NodeCentricRepMatrix& - matrix, which has to copy into a new Object. Note: Deepcopy!
+    */
+    NodeCentricRepMatrix ( const NodeCentricRepMatrix& matrix );
+
+    /**
+    * @brief Destructor. Free Matrix.
+    */
+    ~NodeCentricRepMatrix();
+
+
+    /** Getter **/
+    //! Get the first dimension
+    uint getM() const {
+      return m;
+    };
+    //! Get the second dimension
+    uint getN() const {
+      return n;
+    };
+    //! Get the third dimension
+    uint getE() const {
+      return e;
+    };
+
+    /** Matrix access **/
+    //! returns the value at (y=m, x=n, e=e)
+    double at ( uint m, uint n, uint e ) const;
+    //! returns a non-const referenz to the element at (y=m, x=n, e=e)
+    double& at ( uint m, uint n, uint e );
+
+    /** Operator **/
+    //! =+ operator
+    NodeCentricRepMatrix& operator-= ( NodeCentricRepMatrix const& rhs );
+    //! + operator
+    NodeCentricRepMatrix operator- ( NodeCentricRepMatrix const& rhs );
+    //! Assignt operator (deep copy)
+    NodeCentricRepMatrix& operator= ( NodeCentricRepMatrix const& matrix );
+    //! Access operator
+    double operator() ( const uint m, const uint n, const uint e ) const;
+    //! Access operator
+    double& operator() ( const uint m, const uint n, const uint e );
+
+
+
+    /** static Methodes **/
+    //! return the max. of matrix
+    static inline double maxValue ( const NodeCentricRepMatrix& matrix ) {
+      return matrix.max();
+    };
+
+    /**
+    * @brief This Function calculates the differenz between Member-Matrix and the given Matrix and check if there is NULL or less then epsilon.
+    * @param NodeCentricRepMatrix&        - given matrix
+    * @param double         - epsilon
+    * @return true if |M1(j,i,e) - M2(j,i,e)| <= epsilon, false else
+    */
+    bool changes ( const OBJREC::NodeCentricRepMatrix& matrix, double epsilon ) const;
+};
+}
+
+#endif
+

+ 2 - 0
math/libdepend.inc

@@ -0,0 +1,2 @@
+$(call PKG_DEPEND_EXT,OPENMP)
+$(call PKG_DEPEND_INT,core)

+ 88 - 0
progs/Makefile.inc

@@ -0,0 +1,88 @@
+# BINARY-DIRECTORY-MAKEFILE
+# conventions:
+# - there are no subdirectories, they are ignored!
+# - all ".C", ".cpp" and ".c" files in the current directory are considered
+#   independent binaries, and linked as such.
+# - the binaries depend on the library of the parent directory
+# - the binary names are created with $(BINNAME), i.e. it will be more or less
+#   the name of the .o file
+# - all binaries will be added to the default build list ALL_BINARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+#SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+#include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# include the libdepend.inc file, which gives additional dependencies for the
+# libraries and binaries. additionally, an automatic dependency from the library
+# of the parent directory is added (commented out in the code below).
+
+-include $(SUBDIR)libdepend.inc
+
+PARENTDIR:=$(patsubst %/,%,$(dir $(patsubst %/,%,$(SUBDIR))))
+$(eval $(call PKG_DEPEND_INT,$(PARENTDIR)))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+      $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+BINARIES:=$(patsubst %.o,$(BINDIR)%,$(filter-out moc_%,$(notdir $(OBJS))))
+ALL_BINARIES+=$(BINARIES)
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. each binary depends on the corresponding .o file and
+# on the libraries specified by the INTLIBS/EXTLIBS. these dependencies can be
+# specified manually or they are automatically stored in a .bd file.
+
+$(foreach head,$(wildcard $(SUBDIR)*.h),$(eval $(shell grep -q Q_OBJECT $(head) && echo $(head) | sed -e's@^@/@;s@.*/\(.*\)\.h$$@$(BINDIR)\1:$(OBJDIR)moc_\1.o@')))
+-include $(OBJS:%.o=%.bd)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 70 - 0
progs/testMarkov.cpp

@@ -0,0 +1,70 @@
+#include <segmentation/RSMarkovCluster.h>
+#include <core/basics/Config.h>
+#include <core/image/DeprecatedConverter.h>
+
+#include <iostream>
+#include <iomanip>
+#include <deque>
+#include <stdlib.h>
+#include <time.h>
+
+using namespace OBJREC;
+using namespace NICE;
+using namespace std;
+
+int main ( int argc, char** argv ) {
+
+  if ( argc < 3 ) return -1;
+
+  Config* conf = new Config ( argv[1] );
+
+  RSMarkovCluster clusterAlg ( conf );
+
+  ColorImage cimg ( argv[2] );
+  ColorImage segImage ( cimg.width(), cimg.height() );
+
+  //clusterAlg.findAttractorsOfGraph();
+
+  Matrix clusterMatrix ( cimg.height(), cimg.width(), 0 );
+
+
+  int count = clusterAlg.segRegions ( cimg, clusterMatrix );
+
+  printf ( "%d Regionen gefunden\n", count );
+  if ( count != 0 )
+  {
+    /* initialize random seed: */
+    srand ( time ( NULL ) );
+
+
+    VVector colors;
+    colors.resize ( ( cimg.height() *cimg.width() ) );
+    for ( uint i = 0;i < ( cimg.height() *cimg.width() );i++ )
+    {
+      Vector colors_i ( 3 );
+      for ( uint c = 0;c < 3;c++ ) colors_i[c] = ( rand() % 255 + 1 );
+      colors[i] = colors_i;
+    }
+
+
+    for ( uint y = 0;y < cimg.height();y++ )
+    {
+      for ( uint x = 0;x < cimg.width();x++ )
+      {
+        int indexP = clusterMatrix ( y, x );
+        //int R=round((double(clusterMatrix(y,x)))/255.0);//rand() % 255 + 1;
+        //int G=R;//rand() % 255 + 1;
+        //int B=G;//rand() % 255 + 1;
+
+        segImage.setPixel ( x, y, 0, colors[indexP][0] );
+        segImage.setPixel ( x, y, 1, colors[indexP][1] );
+        segImage.setPixel ( x, y, 2, colors[indexP][2] );
+      }
+    }
+
+    showImage ( segImage );
+  }
+  delete conf;
+
+  return 0;
+}

+ 127 - 0
progs/testSegmentation.cpp

@@ -0,0 +1,127 @@
+/**
+* @file testSegmentation.cpp
+* @brief test segmentation algorithm
+* @author Björn Fröhlich
+* @date 01/20/2010
+
+*/
+#include <core/basics/Config.h>
+
+#include <segmentation/RSMeanShift.h>
+#include <segmentation/RSGraphBased.h>
+#include <segmentation/RSSlic.h>
+
+#include <core/imagedisplay/OverlayColors.h>
+
+#include "core/basics/Timer.h"
+
+#include <core/imagedisplay/ImageDisplay.h>
+
+using namespace OBJREC;
+using namespace NICE;
+using namespace std;
+
+int main ( int argc, char **argv )
+{
+  if ( argc < 2 )
+  {
+    cerr << "Bitte Bild angeben" << endl;
+    return -1;
+  }
+
+  int type = 0;
+
+  RegionSegmentationMethod *rg = NULL;
+
+  if ( argc >= 3 )
+  {
+    string tmp;
+    tmp += argv[2];
+
+    if ( argc >= 4 )
+    {
+      string configfile;
+      configfile += argv[3];
+      Config conf ( configfile );
+      if ( tmp == "f" )
+      {
+        rg = new RSGraphBased ( &conf );
+      }
+      else if ( tmp == "m" ) {
+        rg = new RSMeanShift ( &conf );
+      }
+      else if ( tmp == "s" ) {
+        rg = new RSSlic ( &conf );
+      }
+      else
+      {
+        cout << "please choose between \nm: MeanShift and \nf: Felzenswalb \nas a segmentation method" << endl;
+        return -1;
+      }
+    }
+    else {
+
+      if ( tmp == "f" )
+      {
+        rg = new RSGraphBased();
+      }
+      else if ( tmp == "m" )
+      {
+        rg = new RSMeanShift();
+      }
+      else if ( tmp == "s" ) {
+        rg = new RSSlic ();
+      }
+      else
+      {
+        cout << "please choose between \nm: MeanShift and \nf: Felzenswalb \nas a segmentation method" << endl;
+        return -1;
+      }
+    }
+  }
+  else
+  {
+    rg = new RSGraphBased();
+  }
+
+  string filename;
+  filename += argv[1];
+
+
+  NICE::ColorImage img;
+
+  img.read ( filename );
+
+  Matrix result;
+
+  Timer timer;
+  timer.start();
+  rg->segRegions ( img, result );
+  timer.stop();
+  cerr << "segmentation finished in: " << timer.getLastAbsolute() << " seconds" << endl;
+  //rg->visualizeGraphRepresentation(img,result);
+
+  Image overlay ( img.width(), img.height() );
+
+  double maxval = 0.0;
+
+  for ( int y = 0; y < img.height(); y++ )
+  {
+    for ( int x = 0; x < img.width(); x++ )
+    {
+      int val = ( ( int ) result ( x, y ) + 1 ) % 256;
+      overlay.setPixel ( x, y, val );
+      maxval = std::max ( result ( x, y ), maxval );
+    }
+  }
+
+  cout << maxval << " different regions found" << endl;
+
+  vector<int> color (3);
+  color[0] = 255;
+  ColorImage marked(img.width(), img.height());
+  rg->markContours(img,result,color,marked);
+  NICE::showImage ( marked, "Segmentation Result" );
+  marked.write("segmented.ppm");
+  return 0;
+}