* green/demo/clustering/kmean2d/Makefile.am: New makefile.
* green/demo/clustering/kmean2d/kmean2d.cc: New demo code.
* green/mln/clustering/kmean2d.hh: New library file.
---
trunk/milena/sandbox/ChangeLog | 8 +
.../green/demo/clustering/kmean2d/Makefile.am | 148 +++
.../green/demo/clustering/kmean2d/kmean2d.cc | 237 ++++
.../milena/sandbox/green/mln/clustering/kmean2d.hh | 1340 ++++++++++++++++++++
4 files changed, 1733 insertions(+), 0 deletions(-)
create mode 100644 trunk/milena/sandbox/green/demo/clustering/kmean2d/Makefile.am
create mode 100644 trunk/milena/sandbox/green/demo/clustering/kmean2d/kmean2d.cc
create mode 100644 trunk/milena/sandbox/green/mln/clustering/kmean2d.hh
diff --git a/trunk/milena/sandbox/ChangeLog b/trunk/milena/sandbox/ChangeLog
index f3f91d6..d7bce42 100644
--- a/trunk/milena/sandbox/ChangeLog
+++ b/trunk/milena/sandbox/ChangeLog
@@ -1,5 +1,13 @@
2009-10-08 Yann Jacquelet <jacquelet(a)lrde.epita.fr>
+ Add kmean2d demo for theo, work in progress.
+
+ * green/demo/clustering/kmean2d/Makefile.am: New makefile.
+ * green/demo/clustering/kmean2d/kmean2d.cc: New demo code.
+ * green/mln/clustering/kmean2d.hh: New library file.
+
+2009-10-08 Yann Jacquelet <jacquelet(a)lrde.epita.fr>
+
Fix LRDE norm fault in rgb8_to_rgn.hh
* green/mln/fun/v2v/rg8_to_rgn.hh: Correct space location.
diff --git a/trunk/milena/sandbox/green/demo/clustering/kmean2d/Makefile.am
b/trunk/milena/sandbox/green/demo/clustering/kmean2d/Makefile.am
new file mode 100644
index 0000000..91230b6
--- /dev/null
+++ b/trunk/milena/sandbox/green/demo/clustering/kmean2d/Makefile.am
@@ -0,0 +1,148 @@
+#
+# Generic Makefile
+#
+
+#########
+# TOOLS #
+#########
+
+INCLUDES= -I$(HOME)/svn/oln/trunk/milena/sandbox/green
+CXXFLAGS= -ggdb -O0 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+ECHO= echo
+RM= rm
+MKDIR= mkdir -p
+CP= cp
+
+SOURCE_PATTERN= green/demo
+BUILD__PATTERN= green/build/demo
+
+
+ifeq ($(findstring $(BUILD__PATTERN),$(PWD)), $(BUILD__PATTERN))
+# Case where make is done from build directory.
+SOURCE_DIR= $(subst $(BUILD__PATTERN),$(SOURCE_PATTERN),$(PWD))
+BUILD__DIR= $(PWD)/
+else
+# Case where make is done from source directory.
+SOURCE_DIR= $(PWD)/
+BUILD__DIR= $(subst $(SOURCE_PATTERN),$(BUILD__PATTERN),$(PWD))
+endif
+
+SRC= $(notdir $(wildcard $(SOURCE_DIR)/*.cc))
+OLD= $(notdir $(wildcard $(SOURCE_DIR)/*~))
+OBJ= $(patsubst %.cc,%.o,$(SRC))
+SOURCE_MAKEFILE=Makefile.am
+BUILD__MAKEFILE=Makefile
+TARGET_FILE= $(notdir $(PWD))
+SOURCE_FILES= $(notdir $(wildcard $(SOURCE_DIR)/*.*))
+BUILD__FILES= $(filter-out $(SRC) $(SOURCE_MAKEFILE), $(SOURCE_FILES))
+
+BUILD__F_PATH= $(addprefix $(BUILD__DIR)/,$(BUILD__FILES))
+SOURCE_F_PATH= $(addprefix $(SOURCE_DIR)/,$(SOURCE_FILES))
+
+BUILD__M_PATH= $(addprefix $(BUILD__DIR)/,$(BUILD__MAKEFILE))
+SOURCE_M_PATH= $(addprefix $(SOURCE_DIR)/,$(SOURCE_MAKEFILE))
+
+TARGET_F_PATH= $(addprefix $(BUILD__DIR)/,$(TARGET_FILE))
+OBJ_F_PATH= $(addprefix $(BUILD__DIR)/,$(OBJ))
+SRC_F_PATH= $(addprefix $(SOURCE_DIR)/,$(SRC))
+OLD_F_PATH= $(addprefix $(SOURCE_DIR)/,$(OLD))
+
+#############
+# BOOTSTRAP #
+#############
+
+
+bootstrap: $(BUILD__DIR) $(BUILD__F_PATH) $(BUILD__M_PATH)
+
+# Create, if nessary, the destination directory
+$(BUILD__DIR):
+ $(MKDIR) $(BUILD__DIR)
+
+# Copy, if nessary, all the files, except the Makefile.am
+$(BUILD__F_PATH): $(SOURCE_F_PATH)
+ $(CP) $(addprefix $(SOURCE_DIR),$(@F)) $@
+
+# Copy if nessary, the Makefile.am into Makefile
+$(BUILD__M_PATH): $(SOURCE_M_PATH)
+ $(CP) $(SOURCE_M_PATH) $(BUILD__M_PATH)
+
+
+#######
+# ALL #
+#######
+
+# We assume that the call is done from the build directory.
+# With the directive vpath, hidden files are found in the source directory.
+
+all: $(TARGET_F_PATH)
+
+
+$(TARGET_F_PATH): $(OBJ_F_PATH)
+ $(LINK.cc) $< $(LOADLIBES) $(LDLIBS) -o $@
+
+$(OBJ_F_PATH):$(SRC_F_PATH)
+ $(COMPILE.cc) $(OUTPUT_OPTION) $<
+
+
+#########
+# CLEAN #
+#########
+
+# Force every time the deletion
+clean: clean_target clean_obj clean_dst clean_old #clean_make
+
+
+clean_target:
+ -@$(RM) $(TARGET_F_PATH) &> /dev/null
+
+clean_obj:
+ -@$(RM) $(OBJ_F_PATH) &> /dev/null
+
+clean_dst:
+ -@$(RM) $(BUILD_F_PATH) &> /dev/null
+
+clean_make:
+ -@$(RM) $(BUILD_M_PATH) &> /dev/null
+
+clean_old:
+ -@$(RM) $(OLD_F_PATH) &> /dev/null
+
+
+#########
+# PRINT #
+#########
+
+print: print_tools print_bootstrap
+
+print_tools:
+ @$(ECHO) "HOME = $(HOME)"
+ @$(ECHO) "INCLUDES = $(INCLUDES)"
+ @$(ECHO) "CXXFLAGS = $(CXXFLAGS)"
+ @$(ECHO) "ECHO = $(ECHO)"
+ @$(ECHO) "RM = $(RM)"
+ @$(ECHO) "MKDIR = $(MKDIR)"
+ @$(ECHO) "CP = $(CP)"
+ @$(ECHO)
+
+print_bootstrap:
+ @$(ECHO) "PWD = $(PWD)"
+ @$(ECHO) "SOURCE_PATTERN = $(SOURCE_PATTERN)"
+ @$(ECHO) "BUILD__PATTERN = $(BUILD__PATTERN)"
+ @$(ECHO) "SOURCE_DIR = $(SOURCE_DIR)"
+ @$(ECHO) "BUILD__DIR = $(BUILD__DIR)"
+ @$(ECHO) "SOURCE_MAKEFILE = $(SOURCE_MAKEFILE)"
+ @$(ECHO) "BUILD__MAKEFILE = $(BUILD__MAKEFILE)"
+ @$(ECHO) "TARGET_FILE = $(TARGET_FILE)"
+ @$(ECHO) "SOURCE_FILES = $(SOURCE_FILES)"
+ @$(ECHO) "SOURCE_F_PATH = $(SOURCE_F_PATH)"
+ @$(ECHO) "BUILD__FILES = $(BUILD__FILES)"
+ @$(ECHO) "BUILD__F_PATH = $(BUILD__F_PATH)"
+ @$(ECHO) "BUILD__M_PATH = $(BUILD__M_PATH)"
+ @$(ECHO) "SOURCE_M_PATH = $(SOURCE_M_PATH)"
+ @$(ECHO) "SRC = $(SRC)"
+ @$(ECHO) "OBJ = $(OBJ)"
+ @$(ECHO) "OLD = $(OLD)"
+ @$(ECHO) "SRC_F_PATH = $(SRC_F_PATH)"
+ @$(ECHO) "OBJ_F_PATH = $(OBJ_F_PATH)"
+ @$(ECHO) "OLD_F_PATH = $(OLD_F_PATH)"
+ @$(ECHO)
diff --git a/trunk/milena/sandbox/green/demo/clustering/kmean2d/kmean2d.cc
b/trunk/milena/sandbox/green/demo/clustering/kmean2d/kmean2d.cc
new file mode 100644
index 0000000..ebb5981
--- /dev/null
+++ b/trunk/milena/sandbox/green/demo/clustering/kmean2d/kmean2d.cc
@@ -0,0 +1,237 @@
+// DEMO ON KMEAN2D
+
+#include <mln/clustering/kmean2d.hh>
+
+#include <iostream>
+#include <sstream>
+
+#include <mln/img_path.hh>
+#include <mln/pw/value.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/value/label_8.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/value/value_array.hh>
+
+#include <mln/core/macros.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+
+#include <mln/data/transform.hh>
+#include <mln/fun/v2v/rgb8_to_rgbn.hh>
+#include <mln/fun/v2v/component.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/ppm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/value/rg.hh>
+#include <mln/fun/v2v/rgb_to_rg.hh>
+#include <mln/fun/v2v/rg_to_rgb.hh>
+
+#include <mln/accu/stat/histo2d.hh>
+#include <mln/data/compute.hh>
+
+
+
+void do_demo(const std::string& image,
+ const unsigned k_center,
+ const unsigned n_times,
+ const unsigned watch_dog)
+{
+ typedef mln::clustering::kmean2d<double,8> t_kmean;
+ typedef mln::value::rg<8> t_rg8;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::algebra::vec<2,t_int_u8> t_vec_rg8;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ typedef mln::fun::v2v::component<t_rgb8, 0> t_comp_red;
+ typedef mln::fun::v2v::component<t_rgb8, 1> t_comp_green;
+ typedef mln::fun::v2v::component<t_rgb8, 2> t_comp_blue;
+ typedef mln::fun::v2v::rgb_to_rg<8> t_rgb_to_rg;
+ typedef mln::fun::v2v::rg_to_rgb<8> t_rg_to_rgb;
+ typedef mln::image2d<t_vec_rg8> t_image2d_vec_rg8;
+ typedef mln::image2d<t_rg8> t_image2d_rg8;
+ typedef mln::image2d<unsigned> t_histo2d;
+
+ t_image2d_rgb8 house_rgb8;
+ t_image2d_int_u8 house_red;
+ t_image2d_int_u8 house_blue;
+ t_image2d_int_u8 house_green;
+ //t_image2d_vec_rg8 house_rg8;
+ t_image2d_rgb8 house_cast;
+ t_image2d_rg8 house_rg8;
+ t_histo2d house_histo;
+
+
+ mln::io::ppm::load(house_rgb8, image.c_str());
+ house_red = mln::data::transform(house_rgb8, t_comp_red());
+ house_green = mln::data::transform(house_rgb8, t_comp_green());
+ house_blue = mln::data::transform(house_rgb8, t_comp_blue());
+
+ house_rg8 = mln::data::transform(house_rgb8, t_rgb_to_rg());
+ house_histo = mln::data::compute(mln::accu::meta::stat::histo2d(), house_rg8);
+
+ house_cast = mln::data::transform(house_rg8, t_rg_to_rgb());
+
+ t_kmean kmean(house_rg8, k_center, watch_dog, n_times);
+
+ mln::io::pgm::save(house_red, "red.pgm");
+ mln::io::pgm::save(house_green, "green.pgm");
+ mln::io::pgm::save(house_blue, "blue.pgm");
+ mln::io::ppm::save(house_cast, "red_green.ppm");
+ mln::io::pgm::save(house_histo, "histo.pgm");
+ mln::io::plot::save_image_sh(house_histo, "histo.sh");
+
+/*
+ mln::io::plot::save_image_sh(mean_img, "mean.sh");
+ mln::io::plot::save_image_sh(mean_cnv, "mean_cnv.sh");
+ mln::io::plot::save_image_sh(variance_cnv, "variance_cnv.sh");
+*/
+}
+/*
+void do_demo(const std::string& image,
+ const unsigned k_center,
+ const unsigned n_times,
+ const unsigned watch_dog)
+{
+ typedef mln::clustering::kmean3d<double,5> t_kmean;
+ typedef mln::value::label_8 t_label_8;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::rgb<5> t_rgb5;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_rgb5> t_image2d_rgb5;
+
+ t_image2d_rgb8 house_rgb8;
+ t_image2d_rgb5 house_rgb5;
+
+ mln::io::ppm::load(house_rgb8, image.c_str());
+ house_rgb5=mln::data::transform(house_rgb8,mln::fun::v2v::rgb8_to_rgbn<5>());
+
+ t_kmean kmean(house_rgb5, k_center, watch_dog, n_times);
+
+ mln::trace::quiet = false;
+
+ //kmean.launch_one_time();
+ kmean.launch_n_times();
+
+ // Not safe because we don't test kmean.is_valid()
+
+ t_kmean::t_color_dbg color_img = kmean.get_color_dbg();
+ t_kmean::t_mean_dbg mean_img = kmean.get_mean_dbg();
+ t_kmean::t_label_dbg label_img = kmean.get_label_dbg();
+ t_kmean::t_variance_cnv variance_cnv = kmean.get_variance_cnv();
+ t_kmean::t_mean_cnv mean_cnv = kmean.get_mean_cnv();
+
+ mln::io::ppm::save(mean_img, "mean.ppm");
+ mln::io::ppm::save(color_img, "color.ppm");
+ mln::io::pgm::save(label_img, "label.pgm");
+
+ mln::io::plot::save_image_sh(mean_img, "mean.sh");
+ mln::io::plot::save_image_sh(mean_cnv, "mean_cnv.sh");
+ mln::io::plot::save_image_sh(variance_cnv, "variance_cnv.sh");
+}
+*/
+void demo(const std::string& image = OLENA_IMG_PATH"/house.ppm",
+ const unsigned k_center = 3,
+ const unsigned n_times = 10,
+ const unsigned watch_dog = 10)
+{
+ std::cout << "----------------------------------------" <<
std::endl;
+ std::cout << "Launching the demo with these parameters" <<
std::endl;
+ std::cout << "image : " << image <<
std::endl;
+ std::cout << "k_center : " << k_center <<
std::endl;
+ std::cout << "n_times : " << n_times <<
std::endl;
+ std::cout << "watch_dog : " << watch_dog <<
std::endl;
+ std::cout << "----------------------------------------" <<
std::endl;
+
+ do_demo(image, k_center, n_times, watch_dog);
+}
+
+void usage(const int argc, const char *args[])
+{
+ std::cout << "----------------------------------------" <<
std::endl;
+ std::cout << "argc : " << argc <<
std::endl;
+
+ for (int i = 0; i < argc; ++i)
+ std::cout << "args[" << i << "] : " <<
args[i] << std::endl;
+
+ std::cout << "----------------------------------------" <<
std::endl;
+ std::cout << "usage: kmean1d [image [k_center [n_times [watch_dog]]]]"
+ << std::endl;
+ std::cout << "pbm image (points to work with)" <<
std::endl;
+ std::cout << "unsigned k_center (number of centers)" <<
std::endl;
+ std::cout << "unsigned n_times (number of launching)" <<
std::endl;
+ std::cout << "unsigned watch_dog (convergence loop)" <<
std::endl;
+ std::cout << "----------------------------------------" <<
std::endl;
+}
+
+bool char_to_unsigned(const bool status, const char *arg, unsigned& val)
+{
+ bool result = false;
+
+ if (status)
+ {
+ std::istringstream arg_stream(arg);
+
+ arg_stream >> val;
+
+ result = !arg_stream.fail();
+ }
+
+ return result;
+}
+
+bool char_to_string(const bool status, const char *arg, std::string& val)
+{
+ bool result = false;
+
+ if (status)
+ {
+ std::istringstream arg_stream(arg);
+
+ arg_stream >> val;
+
+ return !arg_stream.fail();
+ }
+
+ return result;
+}
+
+int main(const int argc, const char *args[])
+{
+ std::string image("top");
+ unsigned k_center;
+ unsigned watch_dog;
+ unsigned n_times;
+ bool status = true;
+
+ switch (argc)
+ {
+ case 5: status = char_to_unsigned(status, args[4], watch_dog);
+ case 4: status = char_to_unsigned(status, args[3], n_times);
+ case 3: status = char_to_unsigned(status, args[2], k_center);
+ case 2: status = char_to_string(status, args[1], image); break;
+ case 1: status = true; break;
+ default: status = false;
+ }
+
+ if (status)
+ {
+ switch (argc)
+ {
+ case 1: demo(); break;
+ case 2: demo(image); break;
+ case 3: demo(image, k_center); break;
+ case 4: demo(image, k_center, n_times); break;
+ case 5: demo(image, k_center, n_times, watch_dog); break;
+ }
+ }
+ else
+ usage(argc, args);
+
+ return 0;
+}
diff --git a/trunk/milena/sandbox/green/mln/clustering/kmean2d.hh
b/trunk/milena/sandbox/green/mln/clustering/kmean2d.hh
new file mode 100644
index 0000000..4ff2e6d
--- /dev/null
+++ b/trunk/milena/sandbox/green/mln/clustering/kmean2d.hh
@@ -0,0 +1,1340 @@
+// Copyright (C) 2008,2009 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena 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, version 2 of the License.
+//
+// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef MLN_CLUSTERING_KMEAN2D_HH
+#define MLN_CLUSTERING_KMEAN2D_HH
+
+/// \file
+///
+/// \brief Implements the optimized kmean algorithm.
+///
+/// This algorithm is optimized in the way it proceeds directly with
+/// the greylevel attribute inspite of the pixel attribute. The
+/// algorithm is independant from the image dimension. But, we have to
+/// compute one time the histogram. In fact, we move a recurrent cost
+/// to a fix cost in the complexity. This version is very adapted to
+/// images with small quantification.
+
+#include <limits.h>
+#include <iostream>
+#include <mln/trace/entering.hh>
+#include <mln/trace/exiting.hh>
+
+#include <mln/core/contract.hh>
+#include <mln/trait/value_.hh>
+#include <mln/accu/stat/histo2d.hh>
+
+#include <mln/math/min.hh>
+#include <mln/math/sqr.hh>
+#include <mln/norm/l2.hh>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/concept/image.hh>
+#include <mln/value/int_u.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/value/rg.hh>
+#include <mln/core/macros.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/debug/println.hh>
+#include <mln/data/fill.hh>
+#include <mln/literal/zero.hh>
+#include <mln/literal/one.hh>
+#include <mln/labeling/colorize.hh>
+#include <mln/labeling/mean_values.hh>
+
+#include <mln/io/ppm/save.hh>
+#include <mln/io/pgm/save.hh>
+
+#include <mln/util/array.hh>
+#include <mln/algebra/vec.hh>
+
+namespace mln
+{
+
+ namespace clustering
+ {
+
+ // Forward declaration.
+ template <typename T, unsigned n>
+ struct kmean2d;
+
+ } // end of namespace mln::clustering
+
+ namespace clustering
+ {
+ /// \brief Implements the kmean algorithm in a specific way.
+ ///
+ /// This version of the kmean algorithm uses a greyscale image as input,
+ /// temporary images for computations and produces images as result. Images
+ /// play the role of matrix or vector in standard statistic algoritm.
+ ///
+ /// T is the type used for computations (float or double).
+ /// n is the quantification for the image grayscale.
+ template <typename T, unsigned n>
+ struct kmean2d
+ {
+ /// Type definitions.
+ /// \brief A few type definitions to limit the refactoring impact.
+ ///{
+
+ typedef value::rgb<8> t_rgb;
+ typedef value::label<8> t_label;
+ typedef value::rg<n> t_value;
+ typedef mln_trait_value_comp(t_value,0) t_value_comp0;
+ typedef mln_trait_value_comp(t_value,1) t_value_comp1;
+ typedef T t_result1d;
+ typedef algebra::vec<2,T> t_result2d;
+
+ /// FIXME t_point n'est pas forcément une image 2d, bien au contraire.
+ typedef image2d<t_value> t_point_img;
+ typedef image2d<unsigned> t_histo_img;
+ typedef util::array<t_result1d> t_number_img;
+ typedef util::array<t_result2d> t_mean_img;
+ typedef util::array<t_result1d> t_variance_img;
+
+ typedef image2d<t_label> t_group_img;
+ typedef image2d<t_result1d> t_distance_val;
+ typedef util::array<t_distance_val> t_distance_img;
+
+ typedef image2d<t_label> t_label_dbg;
+ typedef image2d<t_rgb> t_color_dbg;
+ typedef image2d<t_value> t_mean_dbg;
+
+ typedef image1d<t_result2d> t_mean_val;
+ typedef util::array<t_mean_val> t_mean_set;
+ typedef util::array<t_mean_set> t_mean_cnv;
+ typedef image1d<t_result1d> t_variance_val;
+ typedef util::array<t_variance_val> t_variance_cnv;
+
+ ///}
+
+ //------------------------------------------------------------------------
+ // Constructor
+ //------------------------------------------------------------------------
+
+ /// \brief Constructor
+ /// \param[in] point : the image as the population of pixels.
+ /// \param[in] k_center : the number of centers.
+ /// \param[in] watch_dog : the limit to observe the convergence (10).
+ /// \param[in] n_times : the number of times that we executed kmean(10).
+
+ kmean2d(const t_point_img& point,
+ const unsigned k_center,
+ const unsigned watch_dog = 10,
+ const unsigned n_times = 10);
+
+ //------------------------------------------------------------------------
+ // Accessors
+ //------------------------------------------------------------------------
+
+ /// Mutator and accessors.
+ /// \{
+ /// \brief Mutator and accessors are required for debugging and testing.
+ ///
+ /// Testing needs to hack the kmean loop process in order to verify each
+ /// step of the algorithm.
+
+ void set_point(t_point_img& point);
+ void set_histo(t_histo_img& histo);
+ void set_number(t_number_img& number);
+ void set_mean(t_mean_img& mean);
+ void set_variance(t_variance_img& variance);
+ void set_group(t_group_img& group);
+ void set_distance(t_distance_img& distance);
+
+ // Hacking outputs
+ t_point_img& get_point();
+ t_histo_img& get_histo();
+ t_number_img& get_number();
+ t_mean_img& get_mean();
+ t_variance_img& get_variance();
+ t_group_img& get_group();
+ t_distance_img& get_distance();
+
+ // Testing outputs
+ t_color_dbg& get_color_dbg();
+ t_mean_dbg& get_mean_dbg();
+ t_label_dbg& get_label_dbg();
+
+ t_mean_cnv& get_mean_cnv();
+ t_variance_cnv& get_variance_cnv();
+
+ // Normal outputs
+ t_mean_img& to_result();
+
+ /// \}
+
+ //------------------------------------------------------------------------
+ // Printing temporary results
+ //------------------------------------------------------------------------
+
+ void print_mean();
+ void print_number();
+ void print_variance();
+ void print_distance();
+ void print_group();
+ void print_point();
+ void print_histo();
+
+ //------------------------------------------------------------------------
+ // Initializations of centers
+ //------------------------------------------------------------------------
+
+ /// Initialization of centers.
+ /// \{
+ /// \brief Two ways: Regular greylevel tick or random greylevel value or.
+ ///
+ /// There is two way to proceed the initialization. First of all, we
+ /// divide the greyscale in regular tick and we assigne them to the mean
+ /// of the centers. Finaly, we can ask random initialization along the
+ /// greyscale axis. The second process is needed to launch_n_times the
+ /// kmean and converge to the best descent.
+
+ void init_mean();
+ void init_mean_regular();
+ void init_mean_random();
+
+ /// \}
+
+
+ //------------------------------------------------------------------------
+ // Computations of distance, group, center, within variance
+ //------------------------------------------------------------------------
+
+ /// Computations of distance, group, center, within variance.
+ /// \{
+ /// \brief Update the statistical information needed by the kmean process.
+ ///
+ /// The kmean process is a loop where distance from centers to pixels are
+ /// first compute. Then we assign the pixels to their nearest center.
+ /// The new location of each center can then update. Finaly, hommogeneity
+ /// in group is observed by the within variance.
+
+ void update_distance();
+ void update_group();
+ void update_mean();
+ void update_variance();
+
+ /// \}
+
+ //------------------------------------------------------------------------
+ // Main loop
+ //------------------------------------------------------------------------
+
+ /// kmean main loop
+ /// \{
+ /// \brief User interface to launch the kmean process.
+ ///
+ /// There are two ways to launch the kmean process. The first one allow to
+ /// run it one time until convergence. As the process is a descent, it
+ /// depends on the initial center locations. The second call allow us to
+ /// rerun the process many times and to keep the best result (the one
+ /// with the smallest within variance).
+
+ void launch_one_time();
+ void launch_n_times();
+
+ /// \}
+
+ //------------------------------------------------------------------------
+ // Checking the validiy of the results
+ //------------------------------------------------------------------------
+
+ /// Checking the validity of the results.
+ /// \{
+ /// \brief These methods help us to determine the validity of the results.
+ ///
+ /// After each launching the kmean process one time, we need to know if
+ /// the descent was successfull or not. The method is_valid_descent do it
+ /// for us. The method looks for a bad center (a class with no greylevel
+ /// associate to it) and a failure in the convergence.
+
+ bool is_descent_valid();
+
+ /// \}
+
+ //------------------------------------------------------------------------
+ // Debugging tools
+ //------------------------------------------------------------------------
+
+ /// Debugging tools
+ /// \{
+ /// \brief These methods help to interpret results.
+ ///
+ /// The methods build_label_dbg and build_all_dbg work in the input data
+ /// space. The first one build the 2d image of labels. The second call the
+ /// first one and then builds the colorize label' image and the mean
+ /// greylevel image. The update_cnv and finalize_cnv methods are used to
+ /// trace the convergence. They fill two images with the mean info and
+ /// the within variance info along the convergence and the tries.
+
+ void build_label_dbg();
+ void build_mean_dbg();
+ void build_all_dbg();
+ void update_cnv();
+ void finalize_cnv();
+
+ /// \}
+
+
+ private:
+ /// Parameters.
+ /// \{
+ /// \brief These parameters control the convergence of the process.
+ ///
+ /// The first parameter, k_center, defines the number of center for kmean.
+ /// In fact, watch_dog limit the number of iteration that a simple kmean
+ /// loop can do. If the process reaches the watch_dog limit, it means
+ /// that the process will not converge at all. The second parameter
+ /// n_times is the number of times we launch again and again the simple
+ /// kmean loop. As the kmean process is a descent, restarting the process
+ /// from different location will confort us in that we found a global
+ /// minima, not just a local one.
+
+ unsigned _k_center;
+ unsigned _watch_dog;
+ unsigned _n_times;
+
+ /// \}
+
+ /// Convergence information.
+ /// \{
+ /// \brief This information is used to follow the convergence.
+ ///
+ /// The within_variance is the homogeniety indicator for the
+ /// kmean process. The ideal situation is to find the center
+ /// with the minimum variance around them. The within variance
+ /// is just the sum of all variance around the centers. The
+ /// current_step variable allows us to remember the current
+ /// iteration in the kmean loop. This information is needed by
+ /// is_descent_valid routine which decide if convergence occurs
+ /// or not. The current_step info explicit where we are in the
+ /// kmean iteration. The last information, current_launching,
+ /// traces the progress while iterates kmean loop again and
+ /// again. The flag is_number_valid is set when a empty class
+ /// appears. This flag inhibit the process and force to restart
+ /// a try.
+
+ t_result1d _within_variance;
+ unsigned _current_step;
+ unsigned _current_launching;
+ bool _is_number_valid;
+
+ static const unsigned _N_TRIES = 3;
+
+ /// \}
+
+ /// Result of the kmean process.
+ /// \{
+ /// \brief The center location are the major results of the kmean process.
+ ///
+ /// The kmean process result is composed by three information. The best
+ /// launching iteration, the best within variance obtained and the
+ /// location of the centers associated.
+
+ unsigned _launching_min;
+ t_result1d _variance_min;
+ t_mean_img _mean_min;
+
+ /// Inputs.
+ /// \{
+ /// \brief The inputs are the distribution of the values and the values.
+ ///
+ /// The point image is a saving data for the real inputs. In fact, we use
+ /// the histogram information in the optimized kmean process.
+
+ t_point_img _point;
+ t_histo_img _histo;
+
+ ///\}
+
+ /// Centers description.
+ /// \{
+ /// \brief Centers are described by the first moment of their group.
+ ///
+ /// Centers are describe by their group attributes like the number of
+ /// pixels wich are relying on, the mass center of the group and the
+ /// homogeneity of the group. The variance is used as indicator for the
+ /// convergence. The number of pixels is used as integrity indicator.
+ /// A center with no point is a non sense. Theses informations are updated
+ /// after each kmean iteration.
+
+ t_number_img _number; // k x 1
+ t_mean_img _mean; // k x 1
+ t_variance_img _variance; // k x 1 within group
+
+ /// \}
+
+ /// Greylevels description.
+ /// \{
+ /// \brief The information are concerned with the greylevel input image.
+ ///
+ /// The group image allow us to decide which greylevel (and of course
+ /// which pixel) is assigned to a center. The distance image give us a
+ /// clue on how a greylevel could contribute to a center. The summation
+ /// over the greylevels of a center give us the within variance.
+
+ t_group_img _group; // g x 1 because dim(t_value) = 1
+ t_distance_img _distance; // label x graylevel
+
+ /// \}
+
+ /// Debugging, calibrating and testing results.
+ /// \{
+ /// \brief Some exports information to control the results.
+ ///
+ /// We come back in the input space. Label is the image which associates
+ /// each pixel to its center. Color is the image which gives a random rgb
+ /// color to each label. We can then visualize the regions of the same
+ /// label (assigned to the same center) in the image. The mean image
+ /// associate the mean of each pixel center to each pixel. We obtain thus
+ /// a rebuilded image.
+
+ t_label_dbg _label_dbg;
+ t_color_dbg _color_dbg;
+ t_mean_dbg _mean_dbg;
+
+ /// \}
+
+ /// Debugging, calibrating and testing convergence.
+ /// \{
+ /// \brief Trace the variance and the center evolution.
+ ///
+ /// The mean_cnv image is a trace of the evolution of the mean' signal.
+ /// We can observe the variation of the mean of each center along the
+ /// kmean loop or along the different launch. The variance_cnv is a trace
+ /// of the within variance along the kmean loop or along the different
+ /// launch.
+
+ t_mean_cnv _mean_cnv;
+ t_variance_cnv _variance_cnv;
+
+ /// \}
+ };
+
+#ifndef MLN_INCLUDE_ONLY
+
+ //--------------------------------------------------------------------------
+ // Constructor
+ //--------------------------------------------------------------------------
+
+ template <typename T, unsigned n>
+ inline
+ kmean2d<T,n>::kmean2d(const t_point_img& point,
+ const unsigned k_center,
+ const unsigned watch_dog,
+ const unsigned n_times)
+ {
+ trace::entering("mln::clustering::kmean2d::kmean2d");
+ mln_precondition(point.is_valid());
+
+ _k_center = k_center;
+ _watch_dog = watch_dog;
+ _n_times = n_times;
+ _point = point;
+ _histo = data::compute(accu::meta::stat::histo2d(),_point);
+
+ // Results aren't valid since they aren't available
+ _is_number_valid = false;
+ _current_step = 0;
+ _current_launching = 0;
+
+ for (unsigned i = 0; i < _k_center; ++i)
+ {
+ _number.append(literal::zero);
+ _mean.append(literal::zero);
+ _variance.append(literal::zero);
+ }
+
+ _group.init_(box2d(point2d(mln_min(t_value_comp0),
+ mln_min(t_value_comp1)),
+ point2d(mln_max(t_value_comp0),
+ mln_max(t_value_comp1))));
+
+ for (unsigned i = 0; i < _k_center; ++i)
+ {
+ t_distance_val img(box2d(point2d(mln_min(t_value_comp0),
+ mln_min(t_value_comp1)),
+ point2d(mln_max(t_value_comp0),
+ mln_max(t_value_comp1))));
+
+ _distance.append(img);
+ }
+
+ // Debugging, calibrating and testing
+ initialize(_label_dbg, _point);
+ initialize(_color_dbg, _point);
+ initialize(_mean_dbg, _point);
+
+ // Observing the convergence
+
+ for (unsigned i = 0; i < _n_times; ++i)
+ {
+ t_variance_val img(box1d(point1d(0), point1d(_watch_dog-1)));
+
+ data::fill(img, literal::zero);
+
+ _variance_cnv.append(img);
+ }
+
+ for (unsigned i = 0; i < _k_center; ++i)
+ {
+ t_mean_set mean_set;
+
+ for (unsigned j = 0; j < _n_times; ++j)
+ {
+ t_mean_val img(box1d(point1d(0), point1d(_watch_dog-1)));
+
+ data::fill(img, literal::zero);
+
+ mean_set.append(img);
+ }
+
+ _mean_cnv.append(mean_set);
+ }
+
+ trace::exiting("mln::clustering::kmean2d::kmean2d");
+ }
+
+ //--------------------------------------------------------------------------
+ // Mutators and accessors
+ //--------------------------------------------------------------------------
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::set_point(t_point_img& point)
+ {
+ trace::entering("mln::clustering::kmean2d::set_point");
+
+ _point = point;
+
+ trace::exiting("mln::clustering::kmean2d::set_point");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::set_histo(t_histo_img& histo)
+ {
+ trace::entering("mln::clustering::kmean2d::set_histo");
+
+ _histo = histo;
+
+ trace::exiting("mln::clustering::kmean2d::set_histo");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::set_number(t_number_img& number)
+ {
+ trace::entering("mln::clustering::kmean2d::set_number");
+
+ _number = number;
+
+ trace::exiting("mln::clustering::kmean2d::set_number");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::set_mean(t_mean_img& mean)
+ {
+ trace::entering("mln::clustering::kmean2d::set_mean");
+
+ _mean = mean;
+
+ trace::exiting("mln::clustering::kmean2d::set_mean");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::set_variance(t_variance_img& variance)
+ {
+ trace::entering("mln::clustering::kmean2d::set_variance");
+
+ _variance = variance;
+
+ trace::exiting("mln::clustering::kmean2d::set_variance");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::set_group(t_group_img& group)
+ {
+ trace::entering("mln::clustering::kmean2d::set_group");
+
+ _group = group;
+
+ trace::exiting("mln::clustering::kmean2d::set_group");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::set_distance(t_distance_img& distance)
+ {
+ trace::entering("mln::clustering::kmean2d::set_distance");
+
+ _distance = distance;
+
+ trace::exiting("mln::clustering::kmean2d::set_distance");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_point_img& kmean2d<T,n>::get_point()
+ {
+ trace::entering("mln::clustering::kmean2d::get_point");
+
+ trace::exiting("mln::clustering::kmean2d::get_point");
+ return _point;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_histo_img& kmean2d<T,n>::get_histo()
+ {
+ trace::entering("mln::clustering::kmean2d::get_histo");
+
+ trace::exiting("mln::clustering::kmean2d::get_histo");
+ return _histo;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_number_img& kmean2d<T,n>::get_number()
+ {
+ trace::entering("mln::clustering::kmean2d::get_number");
+
+ trace::exiting("mln::clustering::kmean2d::get_number");
+ return _number;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_mean_img& kmean2d<T,n>::get_mean()
+ {
+ trace::entering("mln::clustering::kmean2d::get_mean");
+
+ trace::exiting("mln::clustering::kmean2d::get_mean");
+ return _mean;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_variance_img& kmean2d<T,n>::get_variance()
+ {
+ trace::entering("mln::clustering::kmean2d::get_variance");
+
+ trace::exiting("mln::clustering::kmean2d::get_variance");
+ return _variance;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_group_img& kmean2d<T,n>::get_group()
+ {
+ trace::entering("mln::clustering::kmean2d::get_group");
+
+ trace::exiting("mln::clustering::kmean2d::get_group");
+ return _group;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_distance_img& kmean2d<T,n>::get_distance()
+ {
+ trace::entering("mln::clustering::kmean2d::get_distance");
+
+ trace::exiting("mln::clustering::kmean2d::get_distance");
+ return _distance;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_color_dbg& kmean2d<T,n>::get_color_dbg()
+ {
+ trace::entering("mln::clustering::kmean2d::get_color_dbg");
+
+ trace::exiting("mln::clustering::kmean2d::get_color_dbg");
+ return _color_dbg;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_mean_dbg& kmean2d<T,n>::get_mean_dbg()
+ {
+ trace::entering("mln::clustering::kmean2d::get_mean_dbg");
+
+ trace::exiting("mln::clustering::kmean2d::get_mean_dbg");
+ return _mean_dbg;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_label_dbg& kmean2d<T,n>::get_label_dbg()
+ {
+ trace::entering("mln::clustering::kmean2d::get_label_dbg");
+
+ trace::exiting("mln::clustering::kmean2d::get_label_dbg");
+ return _label_dbg;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_mean_cnv& kmean2d<T,n>::get_mean_cnv()
+ {
+ trace::entering("mln::clustering::kmean2d::get_mean_cnv");
+
+ trace::exiting("mln::clustering::kmean2d::get_mean_cnv");
+ return _mean_cnv;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_variance_cnv&
kmean2d<T,n>::get_variance_cnv()
+ {
+ trace::entering("mln::clustering::kmean2d::get_variance_cnv");
+
+ trace::exiting("mln::clustering::kmean2d::get_variance_cnv");
+ return _variance_cnv;
+ }
+
+ template <typename T, unsigned n>
+ inline
+ typename kmean2d<T,n>::t_mean_img& kmean2d<T,n>::to_result()
+ {
+ trace::entering("mln::clustering::kmean2d::to_result");
+
+ trace::exiting("mln::clustering::kmean2d::to_result");
+ return _mean_min;
+ }
+
+ //--------------------------------------------------------------------------
+ // Printing temporary results
+ //--------------------------------------------------------------------------
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::print_mean()
+ {
+ trace::entering("mln::clustering::kmean2d::print_mean");
+
+ mln_eiter(t_mean_img) l(_mean);
+
+ for_all(l)
+ {
+ std::cout << "mean(" << l.index_();
+ std::cout << ") = [r=" << _mean[l.index_()][0];
+ std::cout << ", g=" << _mean[l.index_()][1];
+ std::cout << ", b=" << _mean[l.index_()][2];
+ std::cout << "]" << std::endl;
+ }
+
+ trace::exiting("mln::clustering::kmean2d::print_mean");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::print_number()
+ {
+ trace::entering("mln::clustering::kmean2d::print_number");
+
+ mln_eiter(t_number_img) l(_number);
+
+ for_all(l)
+ {
+ std::cout << "number(" << l.index_();
+ std::cout << ") = " << _number[l.index_()];
+ std::cout << std::endl;
+ }
+
+ trace::exiting("mln::clustering::kmean2d::print_number");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::print_variance()
+ {
+ trace::entering("mln::clustering::kmean2d::print_variance");
+
+ mln_eiter(t_variance_img) l(_number);
+
+ for_all(l)
+ {
+ std::cout << "variance(" << l.index_();
+ std::cout << ") = " << _variance[l.index_()];
+ std::cout << std::endl;
+ }
+
+ trace::exiting("mln::clustering::kmean2d::print_variance");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::print_histo()
+ {
+ trace::entering("mln::clustering::kmean2d::print_histo");
+
+ mln_piter(t_histo_img) rgb(_histo.domain());
+
+ for_all(rgb)
+ {
+ if (0 < _histo(rgb))
+ {
+ std::cout << "histo(r=" << rgb.row();
+ std::cout << ", g=" << rgb.col();
+ std::cout << ")= " << _histo(rgb);
+ std::cout << std::endl;
+ }
+ }
+
+ trace::exiting("mln::clustering::kmean2d::print_histo");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::print_group()
+ {
+ trace::entering("mln::clustering::kmean2d::print_group");
+
+ mln_piter(t_group_img) rgb(_group.domain());
+
+ for_all(rgb)
+ {
+ if (0 < _histo(rgb))
+ {
+ std::cout << "group(r=" << rgb.row();
+ std::cout << ", g=" << rgb.col();
+ std::cout << ")= " << _group(rgb);
+ std::cout << std::endl;
+ }
+ }
+
+ trace::exiting("mln::clustering::kmean2d::print_group");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::print_distance()
+ {
+ trace::entering("mln::clustering::kmean2d::print_distance");
+
+ mln_eiter(t_distance_img) l(_distance);
+
+ for_all(l)
+ {
+ mln_piter(t_distance_val) rgb(_distance[l.index_()].domain());
+
+ for_all(rgb)
+ {
+ if (0 < _histo(rgb))
+ {
+ std::cout << "distance(l=" << l.index_();
+ std::cout << ",r=" << rgb.row();
+ std::cout << ", g=" << rgb.col();
+ std::cout << ")= " << _distance[l.index_()](rgb);
+ std::cout << std::endl;
+ }
+ }
+ }
+
+ trace::exiting("mln::clustering::kmean2d::print_distance");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::print_point()
+ {
+ trace::entering("mln::clustering::kmean2d::print_point");
+
+ mln_piter(t_point_img) p(_point.domain());
+
+ for_all(p)
+ {
+ std::cout << "point(r=" << p.row();
+ std::cout << ", c=" << p.col();
+ std::cout << ")= " << _point(p);
+ std::cout << std::endl;
+ }
+
+ trace::exiting("mln::clustering::kmean2d::print_point");
+ }
+
+
+
+ //--------------------------------------------------------------------------
+ // Initialization of centers
+ //--------------------------------------------------------------------------
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::init_mean_random()
+ {
+ trace::entering("mln::clustering::kmean2d::init_mean_random");
+
+ t_value_comp0 min_comp0 = mln_min(t_value_comp0);
+ t_value_comp0 max_comp0 = mln_max(t_value_comp0);
+ t_value_comp1 min_comp1 = mln_min(t_value_comp1);
+ t_value_comp1 max_comp1 = mln_max(t_value_comp1);
+
+ mln_eiter(t_mean_img) l(_mean);
+
+ for_all(l)
+ {
+ _mean[l.index_()][0] = (rand() % (max_comp0-min_comp0)) + min_comp0;
+ _mean[l.index_()][1] = (rand() % (max_comp1-min_comp1)) + min_comp1;
+ }
+
+ trace::exiting("mln::clustering::kmean2d::init_mean_random");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::init_mean()
+ {
+ trace::entering("mln::clustering::kmean2d::init_mean");
+
+ init_mean_random();
+
+ trace::exiting("mln::clustering::kmean2d::init_mean");
+ }
+
+ //--------------------------------------------------------------------------
+ // Computations of distance, group, center, within variance
+ //--------------------------------------------------------------------------
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::update_distance()
+ {
+ trace::entering("mln::clustering::kmean2d::update_distance");
+
+ for (unsigned i = 0; i < _k_center; ++i)
+ {
+ mln_piter(t_distance_val) d(_distance[i].domain());
+
+ for_all(d)
+ {
+ // the square distance
+ t_result1d diff2_row = math::sqr(d.row() - _mean[i][0]);
+ t_result1d diff2_col = math::sqr(d.col() - _mean[i][1]);
+ t_result1d diff2_sli = math::sqr(d.sli() - _mean[i][2]);
+ _distance[i](d) = _histo(d)*(diff2_row + diff2_col + diff2_sli);
+ /*
+ std::cout << "row : " << d.row()
<< std::endl;
+ std::cout << "col : " << d.col()
<< std::endl;
+ std::cout << "histo : " << _histo(point1d(d.row()))
<< std::endl;
+ std::cout << "center : " << _mean(point1d(d.col()))
<< std::endl;
+ std::cout << "distance : " << _distance(d)
<< std::endl;
+ std::cout << "--------------------------------------" <<
std::endl;
+ */
+ }
+ }
+
+ trace::exiting("mln::clustering::kmean2d::update_distance");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::update_group()
+ {
+ trace::entering("mln::clustering::kmean2d::update_group");
+
+ mln_piter(t_group_img) rgb(_group.domain());
+
+ for_all(rgb)
+ {
+ mln_eiter(t_distance_img) l(_distance);
+ t_result1d min = mln_max(t_result1d);
+ t_label label = mln_max(t_label);
+
+ //std::cout << "g = " << g << std::endl;
+
+ for_all(l)
+ {
+ if (min > _distance[l.index_()](rgb))
+ {
+ min = _distance[l.index_()](rgb);
+ label = l.index_();
+ }
+
+ //std::cout << "d" << l << " = " <<
+ // _distance(point2d(g.ind(), l.ind())) << std::endl;
+ }
+
+ //std::cout << "g = " << g << std::endl;
+
+ _group(rgb) = label;
+ //std::cout << "group = " << _group(g) << std::endl;
+ //std::cout << "-----------" << std::endl;
+ }
+
+ trace::exiting("mln::clustering::kmean2d::update_group");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::update_mean()
+ {
+ trace::entering("mln::clustering::kmean2d::update_mean");
+
+ /// FIXME VERIFIER QUE L'ON PEUT OBTENIR UNE IMAGE EN NDG SIGNE
+
+ // avec g le niveau de gris (signed or not signed)
+ // w[g] la classe de g sous forme d'image
+ // h[g] l'histogramme de l'image sous forme d'image
+ //
+ // Vg in [0..255]
+ // si w[g] = l
+ // c[l] += h(g) * g
+ // n[l] += h(g)
+ //
+ // c[l] /= n
+
+
+ mln_eiter(t_number_img) en(_number);
+ mln_eiter(t_mean_img) em(_mean);
+
+ for_all_2(en,em)
+ {
+ _number[en.index_()] = literal::zero;
+ _mean[em.index_()] = literal::zero;
+ }
+
+ mln_piter(t_group_img) rgb(_group.domain());
+
+ for_all(rgb)
+ {
+ // peut ĂȘtre faut-il le decomposer par composantes
+ _mean[_group(rgb)][0] += rgb.row() * _histo(rgb);
+ _mean[_group(rgb)][1] += rgb.col() * _histo(rgb);
+ _number(_group(rgb)) += _histo(rgb);
+ }
+
+ mln_eiter(t_mean_img) l(_mean);
+
+ /*
+ for_all(l)
+ {
+ std::cout << "c(" << l << ") = " << _mean(l)
<< std::endl;
+ std::cout << "n(" << l << ") = " <<
_number(l) << std::endl;
+ }
+ */
+ for_all(l)
+ {
+ // State the stopping propagation Nan flag
+ _is_number_valid = (0 != _number[l.index_()]);
+
+ // Emergency exit
+ if (!_is_number_valid)
+ break;
+
+ // Compute the mean
+ _mean[l.index_()] /= _number[l.index_()];
+
+ // Debugging
+ //std::cout << "c" << l << " = " << _mean(l)
<< std::endl;
+ }
+
+ trace::exiting("mln::clustering::kmean2d::update_mean");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::update_variance()
+ {
+ trace::entering("mln::clustering::kmean2d::update_variance");
+
+ _within_variance = literal::zero;
+ mln_eiter(t_variance_img) l(_variance);
+
+ for_all(l)
+ {
+ _variance[l.index_()] = literal::zero;
+
+ mln_piter(t_group_img) rgb(_group.domain());
+
+ for_all(rgb)
+ {
+ if (l.index_() == _group(rgb))
+ _variance[l.index_()] += _distance[l.index_()](rgb);
+ }
+
+ _within_variance += _variance[l.index_()];
+ //std::cout << "v(" << l << ") = " <<
_variance(l) << std::endl;
+ }
+
+ //std::cout << "result" << result << std::endl;
+
+ trace::exiting("mln::clustering::kmean2d::update_variance");
+ }
+
+ //--------------------------------------------------------------------------
+ // Debugging tools
+ //--------------------------------------------------------------------------
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::build_label_dbg()
+ {
+ trace::entering("mln::clustering::kmean2d::build_label_dbg");
+
+ mln_piter(t_point_img) pi(_point.domain());
+ mln_piter(t_label_dbg) po(_label_dbg.domain());
+
+ for_all_2(pi, po)
+ {
+ t_value val = _point(pi);
+ t_label grp = _group(point2d(val.red(), val.green()));
+
+ // As label zero has got a particular semantic, the first label is one
+ _label_dbg(po) = ++grp;
+ }
+
+ trace::exiting("mln::clustering::kmean2d::build_label_dbg");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::build_mean_dbg()
+ {
+ trace::entering("mln::clustering::kmean2d::build_mean_dbg");
+
+ mln_piter(t_mean_dbg) p(_mean_dbg.domain());
+
+ for_all(p)
+ {
+ _mean_dbg(p).red() = static_cast<unsigned>(_mean[_label_dbg(p)][0]);
+ _mean_dbg(p).green() = static_cast<unsigned>(_mean[_label_dbg(p)][1]);
+ _mean_dbg(p).blue() = static_cast<unsigned>(_mean[_label_dbg(p)][2]);
+ }
+
+ trace::exiting("mln::clustering::kmean2d::build_mean_dbg");
+ }
+
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::build_all_dbg()
+ {
+ trace::entering("mln::clustering::kmean2d::build_all_dbg");
+ build_label_dbg();
+ //build_mean_dbg();
+ _mean_dbg = labeling::mean_values(_point, _label_dbg, _k_center);
+ _color_dbg = labeling::colorize(value::rgb8(), _label_dbg);
+
+ trace::exiting("mln::clustering::kmean2d::build_all_dbg");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::update_cnv()
+ {
+ trace::entering("mln::clustering::kmean2d::update_cnv");
+
+ _variance_cnv[_current_launching](point1d(_current_step))
+ = _within_variance;
+
+ mln_eiter(t_mean_img) l(_mean);
+
+ for_all(l)
+ {
+ _mean_cnv[l.index_()][_current_launching](point1d(_current_step))
+ = _mean[l.index_()];
+ }
+
+ trace::exiting("mln::clustering::kmean2d::update_cnv");
+ }
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::finalize_cnv()
+ {
+ trace::entering("mln::clustering::kmean2d::finalize_cnv");
+
+ // saturate the curv with the within variance
+ for (unsigned i = _current_step; i < _watch_dog; ++i)
+ _variance_cnv[_current_launching](point1d(i)) = _within_variance;
+
+ for (unsigned i = _current_step; i < _watch_dog; ++i)
+ {
+ mln_eiter(t_mean_img) l(_mean);
+
+ for_all(l)
+ {
+ _mean_cnv[l.index_()][_current_launching](point1d(i))
+ = _mean[l.index_()];
+ }
+ }
+
+ trace::exiting("mln::clustering::kmean2d::finalize_cnv");
+ }
+
+
+ //--------------------------------------------------------------------------
+ // Checking the validity of the results
+ //--------------------------------------------------------------------------
+
+ template <typename T, unsigned n>
+ inline
+ bool kmean2d<T,n>::is_descent_valid()
+ {
+ trace::entering("mln::clustering::kmean2d::is_descent_valid");
+
+ bool result = _is_number_valid && (_current_step < _watch_dog);
+
+ trace::exiting("mln::clustering::kmean2d::is_descent_valid");
+ return result;
+ }
+
+
+ //--------------------------------------------------------------------------
+ // Main loop
+ //--------------------------------------------------------------------------
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::launch_one_time()
+ {
+ trace::entering("mln::clustering::kmean2d::launch_one_time");
+
+ //std::cout << "----------------------------------------" <<
std::endl;
+
+ // Initialization to start the descent
+ t_result1d old_variance = mln_max(t_result1d);
+ _within_variance = mln_max(t_result1d);
+ _current_step = 0;
+
+ // Build the first group and evaluate its caharacteristics
+ init_mean();
+ update_distance();
+
+ //print_point();
+ //print_histo();
+ //print_mean();
+ //print_distance();
+
+ //std::cout << "first_variance : " << old_variance <<
std::endl;
+
+ // Execute the descent
+ do
+ {
+ old_variance = _within_variance;
+
+ update_group();
+
+ //print_group();
+
+ update_mean(); // update _is_number_valid
+
+ //print_mean();
+
+ // Stopping Nan propagation
+ if (!_is_number_valid)
+ break;
+
+ update_distance();
+
+ //print_distance();
+
+ update_variance(); // update _within_variance
+
+ //print_variance();
+
+ // Debugging code
+ update_cnv();
+
+ std::cout << "_current_step : " << _current_step <<
std::endl;
+ std::cout << "_within_variance : " << _within_variance <<
std::endl;
+
+ ++_current_step;
+ }
+ while (_current_step < _watch_dog && _within_variance <
old_variance);
+
+ //std::cout << "----------------------------------------" <<
std::endl;
+
+ finalize_cnv();
+ //build_all_dbg();
+
+ trace::exiting("mln::clustering::kmean2d::launch_one_time");
+ }
+
+
+ template <typename T, unsigned n>
+ inline
+ void kmean2d<T,n>::launch_n_times()
+ {
+ trace::entering("mln::clustering::kmean2d::launch_n_times");
+
+ //std::cout << "watch_dog : " << _watch_dog <<
std::endl;
+ //std::cout << "n_times : " << _n_times <<
std::endl;
+
+ // number of times we reexecute launch_one_time without any success
+ unsigned tries = 0;
+
+ _variance_min = mln_max(t_result1d);
+ _current_launching = 0;
+
+ // Execute the descent n times
+ while (_current_launching < _n_times)
+ {
+ launch_one_time();
+
+ if (is_descent_valid() || _N_TRIES < tries)
+ {
+ if (_within_variance < _variance_min)
+ {
+ _variance_min = _within_variance;
+ _mean_min = _mean;
+ _launching_min = _current_launching;
+ }
+
+ // Reinitialize the number of echecs possible
+ tries = 0;
+
+ //std::cout << "_current_launching : " << _current_launching
+ // << std::endl;
+
+ //std::cout << "within_variance[" << _current_launching <<
"] = "
+ // << _within_variance << std::endl;
+
+ ++_current_launching;
+ }
+ else
+ ++tries;
+ }
+
+ //Debugging code
+ build_all_dbg();
+
+ trace::exiting("mln::clustering::kmean2d::launch_n_times");
+ }
+
+#endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::clustering
+
+} // end of namespace mln
+
+#endif // ! MLN_CLUSTERING_KMEAN2D_HH
--
1.5.6.5