Implement the first version with vectors and matrices.
* mln/clustering/k_mean.hh: New library component.
* use/clustering/k_mean: New directory.
* use/clustering/k_mean/Makefile.am: New makefile.
* use/clustering/k_mean/k_mean.cc: New source file.
* tests/clustering/k_mean: New directory.
* tests/clustering/k_mean/Makefile.am: New makefile.
* tests/clustering/k_mean/k_mean.cc: New source file.
Implement the second version with image and working in 1d.
* mln/clustering/kmean1d.hh: New library component.
* use/clustering/kmean1d: New directory.
* use/clustering/kmean1d/Makefile.am: New makefile.
* use/clustering/kmean1d/kmean1d.cc: New source file.
* demo/clustering/kmean1d: New directory.
* demo/clustering/kmean1d/Makefile.am: New makefile.
* demo/clustering/kmean1d/kmean1d.cc: New source file.
Implement transformation between RG space and RGB space.
* mln/fun/v2v/rg_to_rgb.hh: New library component.
* use/fun/v2v/rg_to_rgb: New directory.
* use/fun/v2v/rg_to_rgb/Makefile.am: New makefile.
* use/fun/v2v/rg_to_rgb/rg_to_rgb.cc: New source file.
Implement the third version working in 2d (r/g).
* mln/clustering/kmean2d.hh: New library component.
* use/clustering/kmean2d: New directory.
* use/clustering/kmean2d/Makefile.am: New makefile.
* use/clustering/kmean2d/kmean2d.cc: New source file.
* demo/clustering/kmean2d: New directory.
* demo/clustering/kmean2d/Makefile.am: New makefile.
* demo/clustering/kmean2d/kmean2d.cc: New source file.
Implement the fourth version working in 3d (rgb).
* mln/clustering/kmean3d.hh: New library component.
* use/clustering/kmean3d: New directory.
* use/clustering/kmean3d/Makefile.am: New makefile.
* use/clustering/kmean3d/kmean3d.cc: New source file.
* demo/clustering/kmean3d: New directory.
* demo/clustering/kmean3d/Makefile.am: New makefile.
* demo/clustering/kmean3d/kmean3d.cc: New source file.
Implement the fith version as a function (working in rgb space).
* mln/clustering/kmean_rgb.hh: New library component.
* use/clustering/kmean_rgb: New directory.
* use/clustering/kmean_rgb/Makefile.am: New makefile.
* use/clustering/kmean_rgb/kmean_rgb.cc: New source file.
* demo/clustering/kmean_rgb: New directory.
* demo/clustering/kmean_rgb/Makefile.am: New makefile.
* demo/clustering/kmean_rgb/kmean_rgb.cc: New source file.
Benchmark distance algorithm for the kmean algorithm.
* bench/clustering/distance: New directory.
* bench/clustering/distance/Makefile.am: New makefile.
* bench/clustering/distance/distance.cc: New source file.
---
scribo/sandbox/green/ChangeLog | 77 ++
scribo/sandbox/green/README.green | 150 ++++-
.../green/bench/clustering/distance/Makefile.am | 153 ++++
.../green/bench/clustering/distance/distance.cc | 842 ++++++++++++++++++++
.../green/demo/clustering/kmean1d/Makefile.am | 153 ++++
.../green/demo/clustering/kmean1d/kmean1d.cc | 258 ++++++
.../green/demo/clustering/kmean2d/Makefile.am | 153 ++++
.../green/demo/clustering/kmean2d/kmean2d.cc | 278 +++++++
.../green/demo/clustering/kmean3d/Makefile.am | 153 ++++
.../green/demo/clustering/kmean3d/kmean3d.cc | 265 ++++++
.../green/demo/clustering/kmean_rgb/Makefile.am | 153 ++++
.../green/demo/clustering/kmean_rgb/kmean_rgb.cc | 239 ++++++
scribo/sandbox/green/mln/clustering/k_mean.hh | 365 ++++++---
scribo/sandbox/green/mln/clustering/kmean1d.hh | 194 ++---
scribo/sandbox/green/mln/clustering/kmean2d.hh | 329 ++++----
scribo/sandbox/green/mln/clustering/kmean3d.hh | 246 +++---
scribo/sandbox/green/mln/clustering/kmean_rgb.hh | 87 ++-
scribo/sandbox/green/mln/fun/v2v/rg_to_rgb.hh | 59 ++-
.../green/tests/clustering/k_mean/Makefile.am | 13 +-
.../green/tests/clustering/k_mean/k_mean.cc | 395 ++++++----
.../stat/histo1d => clustering/k_mean}/Makefile.am | 0
.../sandbox/green/use/clustering/k_mean/k_mean.cc | 55 ++
.../histo1d => clustering/kmean1d}/Makefile.am | 0
.../green/use/clustering/kmean1d/kmean1d.cc | 50 ++
.../histo1d => clustering/kmean2d}/Makefile.am | 0
.../green/use/clustering/kmean2d/kmean2d.cc | 61 ++
.../histo1d => clustering/kmean3d}/Makefile.am | 0
.../green/use/clustering/kmean3d/kmean3d.cc | 63 ++
.../histo1d => clustering/kmean_rgb}/Makefile.am | 0
.../green/use/clustering/kmean_rgb/kmean_rgb.cc | 63 ++
.../stat/histo1d => fun/v2v/rg_to_rgb}/Makefile.am | 0
.../green/use/fun/v2v/rg_to_rgb/rg_to_rgb.cc | 68 ++
32 files changed, 4224 insertions(+), 698 deletions(-)
create mode 100644 scribo/sandbox/green/bench/clustering/distance/Makefile.am
create mode 100644 scribo/sandbox/green/bench/clustering/distance/distance.cc
create mode 100644 scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
create mode 100644 scribo/sandbox/green/demo/clustering/kmean1d/kmean1d.cc
create mode 100644 scribo/sandbox/green/demo/clustering/kmean2d/Makefile.am
create mode 100644 scribo/sandbox/green/demo/clustering/kmean2d/kmean2d.cc
create mode 100644 scribo/sandbox/green/demo/clustering/kmean3d/Makefile.am
create mode 100644 scribo/sandbox/green/demo/clustering/kmean3d/kmean3d.cc
create mode 100644 scribo/sandbox/green/demo/clustering/kmean_rgb/Makefile.am
create mode 100644 scribo/sandbox/green/demo/clustering/kmean_rgb/kmean_rgb.cc
copy scribo/sandbox/green/use/{accu/stat/histo1d => clustering/k_mean}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/use/clustering/k_mean/k_mean.cc
copy scribo/sandbox/green/use/{accu/stat/histo1d => clustering/kmean1d}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/use/clustering/kmean1d/kmean1d.cc
copy scribo/sandbox/green/use/{accu/stat/histo1d => clustering/kmean2d}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/use/clustering/kmean2d/kmean2d.cc
copy scribo/sandbox/green/use/{accu/stat/histo1d => clustering/kmean3d}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/use/clustering/kmean3d/kmean3d.cc
copy scribo/sandbox/green/use/{accu/stat/histo1d => clustering/kmean_rgb}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/use/clustering/kmean_rgb/kmean_rgb.cc
copy scribo/sandbox/green/use/{accu/stat/histo1d => fun/v2v/rg_to_rgb}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/use/fun/v2v/rg_to_rgb/rg_to_rgb.cc
diff --git a/scribo/sandbox/green/ChangeLog b/scribo/sandbox/green/ChangeLog
index b557ccf..7106b22 100644
--- a/scribo/sandbox/green/ChangeLog
+++ b/scribo/sandbox/green/ChangeLog
@@ -1,3 +1,80 @@
+2010-06-28 Yann Jacquelet <jacquelet(a)lrde.epita.fr>
+
+ Implement the kmean algorithh and start to optimize it.
+
+ Implement the first version with vectors and matrices.
+
+ * mln/clustering/k_mean.hh: New library component.
+
+ * use/clustering/k_mean: New directory.
+ * use/clustering/k_mean/Makefile.am: New makefile.
+ * use/clustering/k_mean/k_mean.cc: New source file.
+
+ * tests/clustering/k_mean: New directory.
+ * tests/clustering/k_mean/Makefile.am: New makefile.
+ * tests/clustering/k_mean/k_mean.cc: New source file.
+
+ Implement the second version with image and working in 1d.
+
+ * mln/clustering/kmean1d.hh: New library component.
+
+ * use/clustering/kmean1d: New directory.
+ * use/clustering/kmean1d/Makefile.am: New makefile.
+ * use/clustering/kmean1d/kmean1d.cc: New source file.
+
+ * demo/clustering/kmean1d: New directory.
+ * demo/clustering/kmean1d/Makefile.am: New makefile.
+ * demo/clustering/kmean1d/kmean1d.cc: New source file.
+
+ Implement transformation between RG space and RGB space.
+
+ * mln/fun/v2v/rg_to_rgb.hh: New library component.
+ * use/fun/v2v/rg_to_rgb: New directory.
+ * use/fun/v2v/rg_to_rgb/Makefile.am: New makefile.
+ * use/fun/v2v/rg_to_rgb/rg_to_rgb.cc: New source file.
+
+ Implement the third version working in 2d (r/g).
+
+ * mln/clustering/kmean2d.hh: New library component.
+
+ * use/clustering/kmean2d: New directory.
+ * use/clustering/kmean2d/Makefile.am: New makefile.
+ * use/clustering/kmean2d/kmean2d.cc: New source file.
+
+ * demo/clustering/kmean2d: New directory.
+ * demo/clustering/kmean2d/Makefile.am: New makefile.
+ * demo/clustering/kmean2d/kmean2d.cc: New source file.
+
+ Implement the fourth version working in 3d (rgb).
+
+ * mln/clustering/kmean3d.hh: New library component.
+
+ * use/clustering/kmean3d: New directory.
+ * use/clustering/kmean3d/Makefile.am: New makefile.
+ * use/clustering/kmean3d/kmean3d.cc: New source file.
+
+ * demo/clustering/kmean3d: New directory.
+ * demo/clustering/kmean3d/Makefile.am: New makefile.
+ * demo/clustering/kmean3d/kmean3d.cc: New source file.
+
+ Implement the fith version as a function (working in rgb space).
+
+ * mln/clustering/kmean_rgb.hh: New library component.
+
+ * use/clustering/kmean_rgb: New directory.
+ * use/clustering/kmean_rgb/Makefile.am: New makefile.
+ * use/clustering/kmean_rgb/kmean_rgb.cc: New source file.
+
+ * demo/clustering/kmean_rgb: New directory.
+ * demo/clustering/kmean_rgb/Makefile.am: New makefile.
+ * demo/clustering/kmean_rgb/kmean_rgb.cc: New source file.
+
+ Benchmark distance algorithm for the kmean algorithm.
+
+ * bench/clustering/distance: New directory.
+ * bench/clustering/distance/Makefile.am: New makefile.
+ * bench/clustering/distance/distance.cc: New source file.
+
2010-06-24 Yann Jacquelet <jacquelet(a)lrde.epita.fr>
Define documentation files.
diff --git a/scribo/sandbox/green/README.green b/scribo/sandbox/green/README.green
index 3f3c9a9..02d8654 100644
--- a/scribo/sandbox/green/README.green
+++ b/scribo/sandbox/green/README.green
@@ -33,8 +33,7 @@ n'y a rien à copier. Rendons-nous dans le répertoire de compilation
et lançon
le makefile.
#:~/git/olena/scribo/sandbox/green/demo/annotating/hsv$
-cd ../../../build/demo/annotating/hsv
-
+#:cd ../../../build/demo/annotating/hsv
#:~/git/olena/scribo/sandbox/green/build/demo/annotating/hsv$ make clean all
L'exécutable est généré par le makefile, il porte le nom du
@@ -168,6 +167,14 @@ de comptage puisqu'il est décrit sous la forme de triplets de
float
contient une séquence d'appels pour les routines permettant de
considérer la dimension de la teinte comme circulaire.
+Après réflexion, le code des histogrammes et tous les accumulateurs
+qui en découlent devraient être rangés dans l'espace de nommage
+mln::accu::histo. Cela permettrait de ne pas parasiter mln::accu::stat
+avec tous les éléments propres aux histogrammes et de ne pas faire un
+espace de nommage à rallonge en introduisant histo dans stat. Donc
+mln::accu::stat semble être une bonne postion pour le rangement final
+du code relatif aux histogrammes.
+
a) version 1d
@@ -198,7 +205,6 @@ c) version 3d RGB
* use/accu/stat/histo3_rgb: Code minimal utilisant un histogramme 3d RGB.
-
d) version 3d HSL
* mln/accu/stat/histo3d_hsl.hh: Accumulateur histogramme image3d HSL.
@@ -245,23 +251,145 @@ IX KMEANS
Ce travail m'avait été demandé par théo. Je le laisse inachevé, quelque part
perdu pendant l'optimisation du code et sa transformation en canevas.
+
+a) Première implémentation avec matrices et vecteurs
+
+Cette version est bien documentée et permet de mieux comprendre les autres
+versions. Par ailleurs, elle n'est pas spécialement optimisée ce qui fait
+qu'elle colle davantage au modèle de l'algorithme kmean traditionnel.
+
* mln/clustering/k_mean.hh: Première implémentation avec matrices et vecteurs.
+* use/clustering/k_mean: Code minimal utilisant cette première implémentation.
+* tests/clustering/k_mean: Tests unitaires sur la permière version.
+
+
+b) Seconde implémentation avec image en 1d
+
+Cette seconde version intègre une optimisation testée par théo il y a
+longtemps. Je me demande si ce n'étais pas pendant sa thèse qu'il
+avait travaillé sur cette version. Bref, dans la mesure où
+l'optimisation passe par la création d'un histogramme, cette version
+devient dépendante des histogrammes réalisés plutôt (il est aussi
+dépendant de la sauvegarde au format gnuplot shell). L'idée générale
+de l'optimisation est de ne plus raisonner sur l'image, mais sur
+l'histogramme. Car à un moment donné, la classification ne tient
+compte que de la valeur du pixel en intensité (pas de ses coordonnées
+dans l'image). Donc tout pixel de même intensité sera classé de
+manière identique. D'où l'intérêt de travailler avec les
+histogrammes. Les limites de cette optimisation se trouvent dans la
+taille des histogrammes. L'optimisation marche à merveille pour de
+faibles quantifications (8 bits c'est parfait). Par contre, lorsque
+l'on passe à un histogramme couleur, la taille de l'histogramme
+devient problématique et peut dépasser la taille de l'image. Cette
+optimisation n'a alors plus aucun sens.
+
* mln/clustering/kmean1d.hh: Implémentation 1d avec des images.
+* use/clustering/kmean1d : Code minimal utilisant cette seconde implémentation.
+* demo/clustering/kmean1d : Demonstrateur.
+
+La visualisation de la convergence des moyennes, générée par le
+démonstrateur, n'est pas très lisible. La lecture textuelle du fichier
+gnuplot shell (mean_cnv.sh) permet d'interpréter ce qui se passe, par
+contre le graphique est à refaire.
+
+
+c) kmean2d
+
+Cette troisième version est identique à la seconde, sauf qu'elle
+permet de faire la classification dans un espace à deux
+dimensions. Malheureusement, un tel travail dans cet espace coûte
+beaucoup plus cher à l'exécution.
+
+* mln/fun/v2v/rg_to_rgb.hh: Transformation de l'espace RG vers l'espace RGB.
+* use/fun/v2v/rg_to_rgb: Exemple de code pour l'utilisation de rg_to_rgb.
+
* mln/clustering/kmean2d.hh: Implémentation 2d avec des images.
-* mln/clustering/kmean3d.hh: Implémentation 3d avec des images.
-* mln/clustering/kmean_rgb.hh: Impl. 3d aplatie et en cours de mise en canevas.
+* use/clustering/kmean2d : Code minimal utilisant cette seconde implémentation.
+* demo/clustering/kmean2d : Demonstrateur.
-* tests/clustering/k_mean: Tests unitaires sur la permière version.
-* tests/clustering/kmean1d: Tests unitaire sur la version 1d.
+La visualisation de la convergence des moyennes est cette fois-ci
+complètement aboutie. Le fichier semble avoir quelques soucis, il
+manque des lignes dans le splot initial, en remettre pour qu'il y en
+ait autant que les blocs de données. L'espace des couleurs étant le
+bicanal r/g, on peut visualiser sur une troisième dimension
+l'évolution des centres dans l'espace initial. L'effet est très réussi
+et aussi très parlant. Chaque run, correspond alors à une trajectoire
+particulière. L'affichage des variations des variances a été rénové et
+est lui aussi beaucoup plus lisible.
+
+
+d) kmean3d
+
+Cette quatrième version est la copie conforme de la version
+précédente. Les problèmes de visualisation sur les fichiés générés
+sont les mêmes. L'affichage des convergences est identique. Le recours
+à une dégradation de l'image d'entrée est impérative pour avoir des
+temps encore acceptables.
-* demo/clustering/kmean1d: Utilisation de la version 1d.
-* demo/clustering/kmean2d: Utilisation de la version 2d.
-* demo/clustering/kmean3d: Utilisation de la version 3d.
+* mln/clustering/kmean3d.hh: Implémentation 3d avec des images.
+* use/clustering/kmean3d : Code minimal utilisant cette quatrième impl.
+* demo/clustering/kmean3d : Demonstrateur.
+
+
+e) kmean aplati
+
+Cette cinquième version est très spéciale. Elle doit permettre de
+gagner du temps d'exécution. Le concept est simple au départ, tout
+écrire d'un seul tenant. L'exercice est fastidieux et difficile
+(intellectuellement). Une fois fait, il faut réfléchir à ce qui peut
+être mis sous forme de canevas. Par exemple, la manière de calculer
+les distances peut être une information paramétrable. Cela pemettrait
+de faire un benchmark in situ. La transcription actuelle compile. Elle
+n'intègre pas tous les outils de debuggage que nous pouvions avoir sur
+les autres versions. Par ailleurs, comme le code est réuni en une
+seule fonction, nous avons pour l'instant une seule sortie, l'image de
+labels de la classification réalisée. A partir de cette image, nous
+pouvons en reconstruire d'autres. Il manque quand même la possibilité
+d'observer les convergences. Le travail était en cours, à prendre donc
+avec beaucoup de pincettes. La dernière exécution house.ppm, 3
+centres, 10 itérations et 10 runs fonctionne parfaitement sur les
+premiers runs puis l'affichage s'emballe sans que l'on y comprenne
+rien. Un dump dans un fichier révèle le non appariement de certaines
+traces (entering/exiting). Une piste à suivre est la sortie anticipée
+d'une de mes boucles sans pour autant fermer une trace ... ???
+
+* mln/clustering/kmean_rgb.hh: Implémentation 3d avec des images.
+* use/clustering/kmean_rgb : Code minimal utilisant cette quatrième impl.
* demo/clustering/kmean_rgb: Utilisation de la version aplatie.
+
+f) optimisation possible
+
+Le calcul des distances entre les points et les différents centres
+peut être réalisé par des transformées. Certes, les distances ne seront
+pas les mêmes que la distance euclidienne, mais elles s'en approchent
+et cela constitue très certainement une très bonne approximation pour
+l'objectif que nous cherchons à atteindre. Le but de ce benchmark est
+de regarder quel type de transformation est le plus rapide pour
+arriver à nos fins en fonction des données d'entrée. Cette
+optimisation n'a pas encore été intégrée dans le code, et reste une
+piste à exploiter.
+
* bench/clustering/distance: Comparaison algorithmes d'évaluation des distances.
-==> to do
+Une routine du benchmark ne compile plus. Il semble qu'il y ait un
+mauvais appel à la fonction at_ dans la routine
+influence_zone_geodesic.hh ligne 127. Le but du benchmark est de
+tester les distances en 2d et 3d pour des voisinages différents (c04,
+c08, c06, c18, c26) sur les routines distance euclidienne classique,
+zone d'influence geodesique et zone d'influence "front". La première
+serie de test vise à garder une taille d' image constante et
+d'augmenter le nombre de centres pour voir comment se comporte les
+algorithmes et la seconde serie, vise à garder un nombre constant de
+centres et à agrandir progressivement l'image. Attention, le benchmark
+essaye d'être assez exhaustif et donc se paye par un temps d'execution
+assez long. Les différents fichiers générés reprennent les différents
+tests effectués et montrent l'évolution du temps de calcul suivant la
+progression du paramètre observé (taille de l'image ou nombre de
+centres).
+
+==> to do : le changelog + commit + give it to scribo-z branch
+
X REGIONAL MAXIMA
-----------------
diff --git a/scribo/sandbox/green/bench/clustering/distance/Makefile.am
b/scribo/sandbox/green/bench/clustering/distance/Makefile.am
new file mode 100644
index 0000000..ca5e187
--- /dev/null
+++ b/scribo/sandbox/green/bench/clustering/distance/Makefile.am
@@ -0,0 +1,153 @@
+#
+# Generic Makefile
+#
+
+#########
+# TOOLS #
+#########
+
+#LOADLIBES= -lboost_filesystem
+INCLUDES1= -I$(HOME)/git/olena/scribo/sandbox/green
+INCLUDES2= -I$(HOME)/git/olena/milena
+INCLUDES= $(INCLUDES1) $(INCLUDES2)
+#CXXFLAGS= -ggdb -O0 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O1 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+CXXFLAGS= -DNDEBUG -O3 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+ECHO= echo
+RM= rm
+MKDIR= mkdir -p
+CP= cp
+
+SOURCE_PATTERN= green/bench
+BUILD__PATTERN= green/build/bench
+
+
+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/scribo/sandbox/green/bench/clustering/distance/distance.cc
b/scribo/sandbox/green/bench/clustering/distance/distance.cc
new file mode 100644
index 0000000..4daea44
--- /dev/null
+++ b/scribo/sandbox/green/bench/clustering/distance/distance.cc
@@ -0,0 +1,842 @@
+// Copyright (C) 2007,2008,2009,2010 EPITA 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.
+
+#include <mln/core/alias/box3d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/alias/neighb3d.hh>
+#include <mln/core/alias/point3d.hh>
+#include <mln/core/alias/w_window2d_int.hh>
+#include <mln/core/alias/w_window3d_int.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/image3d.hh>
+#include <mln/core/routine/initialize.hh>
+
+#include <mln/data/fill.hh>
+
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/literal/zero.hh>
+
+#include <mln/make/w_window2d_int.hh>
+#include <mln/make/w_window3d_int.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/transform/influence_zone_geodesic.hh>
+#include <mln/transform/influence_zone_front.hh>
+
+#include <mln/util/array.hh>
+#include <mln/util/timer.hh>
+
+#include <mln/value/label_8.hh>
+
+
+/// Build inputs, build seeds, count distance.
+/// \{
+/// \brief Build 2d/3d input image and 2d/3d seed image.
+///
+/// Building seeds means making a rectangular grid over a virtual image with
+/// a specific size and collects together in a array each node of this grid.
+/// In the context of the kmean algorithm, seeds are equavalent to centers.
+/// Building input means creating a label image and associates to each seed
+/// a unique label id.
+/// Distance are square euclidian distance in 2d and in 3d.
+mln::image2d<mln::value::label_8> build_input2d(unsigned nb_seed, unsigned size)
+{
+ typedef mln::value::label_8 t_lbl;
+ mln::image2d<t_lbl> input(mln::box2d(mln::point2d(0,0),
+ mln::point2d(size,size)));
+
+ mln::data::fill(input, mln::literal::zero);
+
+ unsigned top = size / nb_seed;
+ unsigned lbl = 0;
+
+ for (unsigned i = top/2; i < size; i += top)
+ for (unsigned j = top/2; j < size; j += top)
+ input(mln::point2d(i,j)) = ++lbl;
+
+ //mln::io::pgm::save(input, "input.pgm");
+
+ return input;
+}
+
+mln::image3d<mln::value::label_8> build_input3d(unsigned nb_seed, unsigned size)
+{
+ typedef mln::value::label_8 t_lbl;
+ mln::image3d<t_lbl> input(mln::box3d(mln::point3d(0,0,0),
+ mln::point3d(size,size,size)));
+
+ mln::data::fill(input, mln::literal::zero);
+
+ unsigned top = size / nb_seed;
+ unsigned lbl = 0;
+
+ for (unsigned i = top/2; i < size; i += top)
+ for (unsigned j = top/2; j < size; j += top)
+ for (unsigned k = top/2; k < size; k += top)
+ input(mln::point3d(k,i,j)) = ++lbl;
+
+ //mln::io::pgm::save(input, "input.pgm");
+
+ return input;
+}
+
+mln::util::array<mln::point3d> build_seed3d(unsigned nb_seed, unsigned size)
+{
+ mln::util::array<mln::point3d> result;
+ unsigned top = size / nb_seed;
+
+ for (unsigned i = top/2; i < size; i += top)
+ for (unsigned j = top/2; j < size; j += top)
+ for (unsigned k = top/2; k < size; k += top)
+ result.append(mln::point3d(k,i,j));
+
+ // std::cout << result << std::endl;
+
+ return result;
+}
+
+mln::util::array<mln::point2d> build_seed2d(unsigned nb_seed, unsigned size)
+{
+ mln::util::array<mln::point2d> result;
+ unsigned top = size / nb_seed;
+
+ for (unsigned i = top/2; i < size; i += top)
+ for (unsigned j = top/2; j < size; j += top)
+ result.append(mln::point2d(j,i));
+
+ // std::cout << result << std::endl;
+
+ return result;
+}
+
+unsigned distance(mln::point3d p1, mln::point3d p2)
+{
+ unsigned row2 = (p1.row() - p2.row())*(p1.row() - p2.row());
+ unsigned col2 = (p1.col() - p2.col())*(p1.col() - p2.col());
+ unsigned sli2 = (p1.sli() - p2.sli())*(p1.sli() - p2.sli());
+ unsigned res = row2 + col2 + sli2;
+
+ return res;
+}
+
+unsigned distance(mln::point2d p1, mln::point2d p2)
+{
+ unsigned row2 = (p1.row() - p2.row())*(p1.row() - p2.row());
+ unsigned col2 = (p1.col() - p2.col())*(p1.col() - p2.col());
+ unsigned res = row2 + col2;
+
+ return res;
+}
+/// \}
+
+/// Benchmark geodesic distance.
+/// \{
+/// \brief The geodesic material for the benchmark process.
+///
+/// This part of the file contains all we need to benchmarck the
+/// geodesic distance. First of all, we have the calling functions
+/// that encapsulate the real call to geodesic routine. They bring us
+/// a clean place where starting and stopping the timer without any
+/// other code interference. Printing results could be done at this step.
+/// At least, we have the test routine that call the previous functions
+/// by passing arguments like different size of inputs and different
+/// neighbouring. The test routines save their results in gnuplot script shell
+/// file that enable to show charts.
+void influence_zone_geodesic_2d(mln::util::timer& timer,
+ const mln::image2d<mln::value::label_8>& input,
+ const mln::neighb2d & neighb)
+{
+ mln::image2d<mln::value::label_8> output;
+
+ timer.start();
+ output = mln::transform::influence_zone_geodesic(input, neighb);
+ timer.stop();
+
+ //mln::io::pgm::save(output, "output.pgm");
+}
+
+/// \fixme influence_zone_geodesic_3d doesn't compile!
+void influence_zone_geodesic_3d(mln::util::timer& timer,
+ const mln::image3d<mln::value::label_8>& input,
+ const mln::neighb3d & neighb)
+{
+ mln::image3d<mln::value::label_8> output;
+
+ timer.start();
+ // FIXME : Problem with the influence_zone_geodesic in 3d (bad call to at_).
+ // output = mln::transform::influence_zone_geodesic(input, neighb);
+ timer.stop();
+
+ //mln::io::pgm::save(output, "output.pgm");
+}
+
+
+int test_influence_zone_geodesic_2d()
+{
+ mln::util::timer timer;
+
+// Test the label c4
+ mln::image1d<float> chart_seed_c04(16*16+2);
+
+ mln::data::fill(chart_seed_c04, mln::literal::zero);
+
+ for (unsigned i = 1; i < 16+1; ++i)
+ {
+ influence_zone_geodesic_2d(timer,build_input2d(i,256),mln::c4());
+ std::cout << "c04|256x256|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed_c04, i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed_c04, "geodesic.c04.2d.seed.sh");
+
+ // Test the label c8
+ mln::image1d<float> chart_seed_c08(16*16+2);
+
+ mln::data::fill(chart_seed_c08, mln::literal::zero);
+
+ for (unsigned i = 1; i < 16+1; ++i)
+ {
+ influence_zone_geodesic_2d(timer,build_input2d(i,256),mln::c8());
+ std::cout << "c08|256x256|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed_c08, i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed_c08, "geodesic.c08.2d.seed.sh");
+
+ // Test the size of the image
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size_c04(256+1);
+
+ mln::data::fill(chart_size_c04, mln::literal::zero);
+
+ for (unsigned i = 16; i < 256+1; ++i)
+ {
+ influence_zone_geodesic_2d(timer, build_input2d(4,i),mln::c4());
+ std::cout << "c04|" << i << "x" << i
<< "|16 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size_c04, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size_c04, "geodesic.c04.2d.size.sh");
+
+ // Test the size of the image
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size_c08(256+1);
+
+ mln::data::fill(chart_size_c08, mln::literal::zero);
+
+ for (unsigned i = 16; i < 256+1; ++i)
+ {
+ influence_zone_geodesic_2d(timer, build_input2d(4,i),mln::c8());
+ std::cout << "c08|" << i << "x" << i
<< "|16 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size_c08, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size_c08, "geodesic.c08.2d.size.sh");
+
+
+ return 0;
+}
+
+
+void test_influence_zone_geodesic_3d()
+{
+ mln::util::timer timer;
+
+ // Test the number of labels c06
+ mln::image1d<float> chart_seed_c06(5*5*5+2);
+
+ mln::data::fill(chart_seed_c06, mln::literal::zero);
+
+ for (unsigned i = 1; i < 5+1; ++i)
+ {
+ influence_zone_geodesic_3d(timer, build_input3d(i,128), mln::c6());
+ std::cout << "c06|128x128x128|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed_c06, i*i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed_c06, "geodesic.c06.3d.seed.sh");
+
+ // Test the number of labels c18
+ mln::image1d<float> chart_seed_c18(5*5*5+2);
+
+ mln::data::fill(chart_seed_c18, mln::literal::zero);
+
+ for (unsigned i = 1; i < 5+1; ++i)
+ {
+ influence_zone_geodesic_3d(timer, build_input3d(i,128), mln::c18());
+ std::cout << "c18|128x128x128|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed_c18, i*i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed_c18, "geodesic.c18.3d.seed.sh");
+
+ // Test the number of labels c26
+ mln::image1d<float> chart_seed_c26(5*5*5+2);
+
+ mln::data::fill(chart_seed_c26, mln::literal::zero);
+
+ for (unsigned i = 1; i < 5+1; ++i)
+ {
+ influence_zone_geodesic_3d(timer, build_input3d(i,128), mln::c26());
+ std::cout << "c26|128x128x128|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed_c26, i*i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed_c26, "geodesic.c26.3d.seed.sh");
+
+ // Test the size of the image c06
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size_c06(128+1);
+
+ mln::data::fill(chart_size_c06, mln::literal::zero);
+
+ for (unsigned i = 6; i < 128+1; ++i)
+ {
+ influence_zone_geodesic_3d(timer, build_input3d(2,i), mln::c6());
+ std::cout << "c06|" << i << "x" << i
<< "x" << i << "|8 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size_c06, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size_c06, "geodesic.c06.3d.size.sh");
+
+ // Test the size of the image c18
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size_c18(128+1);
+
+ mln::data::fill(chart_size_c18, mln::literal::zero);
+
+ for (unsigned i = 6; i < 128+1; ++i)
+ {
+ influence_zone_geodesic_3d(timer, build_input3d(2,i), mln::c18());
+ std::cout << "c18|" << i << "x" << i
<< "x" << i << "|8 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size_c18, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size_c18, "geodesic.c18.3d.size.sh");
+
+ // Test the size of the image c26
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size_c26(128+1);
+
+ mln::data::fill(chart_size_c26, mln::literal::zero);
+
+ for (unsigned i = 6; i < 128+1; ++i)
+ {
+ influence_zone_geodesic_3d(timer, build_input3d(2,i), mln::c26());
+ std::cout << "c26|" << i << "x" << i
<< "x" << i << "|8 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size_c26, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size_c26, "geodesic.c26.3d.size.sh");
+}
+/// \}
+
+/// Benchmark front distance.
+/// \{
+/// \brief The front material for the benchmark process.
+///
+/// This part of the file contains all we need to benchmarck the
+/// front distance. First of all, we have the calling functions
+/// that encapsulate the real call to geodesic routine. They bring us
+/// a clean place where starting and stopping the timer without any
+/// other code interference. Printing results could be done at this step.
+/// At least, we have the test routine that call the previous functions
+/// by passing arguments like different size of inputs and different
+/// neighbouring. The test routines save their results in gnuplot script shell
+/// file that enable to show charts.
+void influence_zone_front_2d(mln::util::timer& timer,
+ const mln::image2d<mln::value::label_8>& input,
+ const mln::neighb2d& neighb,
+ const mln::w_window2d_int& w2d)
+{
+ mln::image2d<mln::value::label_8> output;
+
+ timer.start();
+ output = mln::transform::influence_zone_front(input, neighb, w2d);
+ timer.stop();
+
+ //mln::io::pgm::save(output, "output.pgm");
+}
+
+
+void influence_zone_front_3d(mln::util::timer& timer,
+ const mln::image3d<mln::value::label_8>& input,
+ const mln::neighb3d& neighb,
+ const mln::w_window3d_int& w3d)
+{
+ mln::image3d<mln::value::label_8> output;
+
+ timer.start();
+ output = mln::transform::influence_zone_front(input, neighb, w3d);
+ timer.stop();
+
+ //mln::io::pgm::save(output, "output.pgm");
+}
+
+
+void test_influence_zone_front_3d()
+{
+ mln::util::timer timer;
+
+ int ws_c06[] = {
+ // Internal slice
+ 0, 0, 0,
+ 0, 2, 0,
+ 0, 0, 0,
+ // Middle slice
+ 0, 2, 0,
+ 2, 0, 2,
+ 0, 2, 0,
+ // External slice
+ 0, 0, 0,
+ 0, 2, 0,
+ 0, 0, 0 };
+
+ int ws_c18[] = {
+ // Internal slice
+ 0, 6, 0,
+ 6, 4, 6,
+ 0, 6, 0,
+ // Middle slice
+ 6, 4, 6,
+ 4, 0, 4,
+ 6, 4, 6,
+ // External slice
+ 0, 6, 0,
+ 6, 4, 6,
+ 0, 6, 0 };
+
+ int ws_c26[] = {
+ // Internal slice
+ 7, 6, 7,
+ 6, 4, 6,
+ 7, 6, 7,
+ // Middle slice
+ 6, 4, 6,
+ 4, 0, 4,
+ 6, 4, 6,
+ // External slice
+ 7, 6, 7,
+ 6, 4, 6,
+ 7, 6, 7 };
+
+ mln::w_window3d_int w3d_c06 = mln::make::w_window3d_int(ws_c06);
+ mln::w_window3d_int w3d_c18 = mln::make::w_window3d_int(ws_c18);
+ mln::w_window3d_int w3d_c26 = mln::make::w_window3d_int(ws_c26);
+
+ // Test the number of labels c06
+ mln::image1d<float> chart_seed_c06(5*5*5+2);
+
+ mln::data::fill(chart_seed_c06, mln::literal::zero);
+
+ for (unsigned i = 1; i < 5+1; ++i)
+ {
+ influence_zone_front_3d(timer, build_input3d(i,128), mln::c6(), w3d_c06);
+ std::cout << "c06|128x128x128|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed_c06, i*i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed_c06, "front.c06.3d.seed.sh");
+
+ // Test the number of labels c18
+ mln::image1d<float> chart_seed_c18(5*5*5+2);
+
+ mln::data::fill(chart_seed_c18, mln::literal::zero);
+
+ for (unsigned i = 1; i < 5+1; ++i)
+ {
+ influence_zone_front_3d(timer, build_input3d(i,128), mln::c18(), w3d_c18);
+ std::cout << "c18|128x128x128|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed_c18, i*i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed_c18, "front.c18.3d.seed.sh");
+
+ // Test the number of labels c26
+ mln::image1d<float> chart_seed_c26(5*5*5+2);
+
+ mln::data::fill(chart_seed_c26, mln::literal::zero);
+
+ for (unsigned i = 1; i < 5+1; ++i)
+ {
+ influence_zone_front_3d(timer, build_input3d(i,128), mln::c26(), w3d_c26);
+ std::cout << "c26|128x128x128|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed_c26, i*i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed_c26, "front.c26.3d.seed.sh");
+
+ // Test the size of the image c06
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size_c06(128+1);
+
+ mln::data::fill(chart_size_c06, mln::literal::zero);
+
+ for (unsigned i = 6; i < 128+1; ++i)
+ {
+ influence_zone_front_3d(timer, build_input3d(2,i), mln::c6(), w3d_c06);
+ std::cout << "c06|" << i << "x" << i
<< "x" << i << "|8 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size_c06, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size_c06, "front.c06.3d.size.sh");
+
+ // Test the size of the image c18
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size_c18(128+1);
+
+ mln::data::fill(chart_size_c18, mln::literal::zero);
+
+ for (unsigned i = 6; i < 128+1; ++i)
+ {
+ influence_zone_front_3d(timer, build_input3d(2,i), mln::c18(), w3d_c18);
+ std::cout << "c18|" << i << "x" << i
<< "x" << i << "|8 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size_c18, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size_c18, "front.c18.3d.size.sh");
+
+ // Test the size of the image c26
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size_c26(128+1);
+
+ mln::data::fill(chart_size_c26, mln::literal::zero);
+
+ for (unsigned i = 6; i < 128+1; ++i)
+ {
+ influence_zone_front_3d(timer, build_input3d(2,i), mln::c26(), w3d_c26);
+ std::cout << "c26|" << i << "x" << i
<< "x" << i << "|8 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size_c26, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size_c26, "front.c26.3d.size.sh");
+}
+
+void test_influence_zone_front_2d()
+{
+ mln::util::timer timer;
+
+ int ws_c04[] = {
+ 0, 2, 0,
+ 2, 0, 2,
+ 0, 2, 0};
+
+ int ws_c08[] = {
+ 6, 4, 6,
+ 4, 0, 4,
+ 6, 4, 6};
+
+ mln::w_window2d_int w2d_c04 = mln::make::w_window2d_int(ws_c04);
+ mln::w_window2d_int w2d_c08 = mln::make::w_window2d_int(ws_c08);
+
+ // Test the label c4
+ mln::image1d<float> chart_seed_c04(16*16+2);
+
+ mln::data::fill(chart_seed_c04, mln::literal::zero);
+
+ for (unsigned i = 1; i < 16+1; ++i)
+ {
+ influence_zone_front_2d(timer,build_input2d(i,256),mln::c4(),w2d_c04);
+ std::cout << "c04|256x256|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed_c04, i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed_c04, "front.c04.2d.seed.sh");
+
+ // Test the label c8
+ mln::image1d<float> chart_seed_c08(16*16+2);
+
+ mln::data::fill(chart_seed_c08, mln::literal::zero);
+
+ for (unsigned i = 1; i < 16+1; ++i)
+ {
+ influence_zone_front_2d(timer,build_input2d(i,256),mln::c8(),w2d_c08);
+ std::cout << "c08|256x256|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed_c08, i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed_c08, "front.c08.2d.seed.sh");
+
+ // Test the size of the image
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size_c04(256+1);
+
+ mln::data::fill(chart_size_c04, mln::literal::zero);
+
+ for (unsigned i = 16; i < 256+1; ++i)
+ {
+ influence_zone_front_2d(timer, build_input2d(4,i),mln::c4(),w2d_c04);
+ std::cout << "c04|" << i << "x" << i
<< "|16 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size_c04, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size_c04, "front.c04.2d.size.sh");
+
+ // Test the size of the image
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size_c08(256+1);
+
+ mln::data::fill(chart_size_c08, mln::literal::zero);
+
+ for (unsigned i = 16; i < 256+1; ++i)
+ {
+ influence_zone_front_2d(timer, build_input2d(4,i),mln::c8(),w2d_c08);
+ std::cout << "c08|" << i << "x" << i
<< "|16 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size_c08, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size_c08, "front.c08.2d.size.sh");
+}
+/// \}
+
+
+
+/// Benchmark euclidian distance.
+/// \{
+/// \brief The euclidian material for the benchmark process.
+///
+/// This part of the file contains all we need to benchmarck the
+/// euclidian distance. First of all, we have the calling functions
+/// that encapsulate the real call to geodesic routine. They bring us
+/// a clean place where starting and stopping the timer without any
+/// other code interference. Printing results could be done at this step.
+/// At least, we have the test routine that call the previous functions
+/// by passing arguments like different size of inputs and different
+/// neighbouring. The test routines save their results in gnuplot script shell
+/// file that enable to show charts.
+void influence_zone_euclidian_2d(mln::util::timer& timer,
+ const mln::image2d<mln::value::label_8>& input,
+ const mln::util::array<mln::point2d>& seed)
+{
+ mln::image2d<mln::value::label_8> output;
+
+ timer.start();
+
+ mln::initialize(output, input);
+
+ mln_piter_(mln::image2d<mln::value::label_8>) p(output.domain());
+ mln_eiter_(mln::util::array<mln::point2d>) e(seed);
+
+ for_all(p)
+ {
+ unsigned d = 0;
+ unsigned min_d = mln_max(unsigned);
+ unsigned min_l = 0;
+
+ for_all(e)
+ {
+ d = distance(p, seed(e.index_()));
+
+ if (min_d > d)
+ {
+ min_d = d;
+ min_l = input(e);
+ }
+ }
+
+ output(p) = min_l;
+ }
+
+ timer.stop();
+
+ //mln::io::pgm::save(output, "output.pgm");
+}
+
+
+void influence_zone_euclidian_3d(mln::util::timer& timer,
+ const mln::image3d<mln::value::label_8>& input,
+ const mln::util::array<mln::point3d>& seed)
+{
+ mln::image3d<mln::value::label_8> output;
+
+ timer.start();
+
+ mln::initialize(output, input);
+
+ mln_piter_(mln::image3d<mln::value::label_8>) p(output.domain());
+ mln_eiter_(mln::util::array<mln::point3d>) e(seed);
+
+ for_all(p)
+ {
+ unsigned d = 0;
+ unsigned min_d = mln_max(unsigned);
+ unsigned min_l = 0;
+
+ for_all(e)
+ {
+ d = distance(p, seed(e.index_()));
+
+ if (min_d > d)
+ {
+ min_d = d;
+ min_l = input(e);
+ }
+ }
+
+ output(p) = min_l;
+ }
+
+ timer.stop();
+}
+
+void test_influence_zone_euclidian_2d()
+{
+ mln::util::timer timer;
+/*
+ // Global test
+ mln::image2d<float> chart(mln::box2d(mln::point2d(0,0),
+ mln::point2d(16*16+2,256+1)));
+
+ mln::data::fill(chart, mln::literal::zero);
+
+ for (unsigned i = 1; i < 256+1; ++i) // size
+ for (unsigned j = 1; j < i*i && j < 16+1; ++j) // seed
+ {
+ influence_zone_euclidian_2d(timer,build_input2d(j,i),build_seed2d(j,i));
+ std::cout << "xxx|" << i << "x" << i
<< "|" << j << " = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart, j*j,i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart, "chart.sh");
+*/
+
+ // Test the number of labels
+ mln::image1d<float> chart_seed(16*16+2);
+
+ mln::data::fill(chart_seed, mln::literal::zero);
+
+ for (unsigned i = 1; i < 16+1; ++i)
+ {
+ influence_zone_euclidian_2d(timer,build_input2d(i,256),build_seed2d(i,256));
+ std::cout << "xxx|256x256|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed, i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed, "euclidian.2d.seed.sh");
+
+ // Test the size of the image
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size(256+1);
+
+ mln::data::fill(chart_size, mln::literal::zero);
+
+ for (unsigned i = 16; i < 256+1; ++i)
+ {
+ influence_zone_euclidian_2d(timer, build_input2d(4,i), build_seed2d(4,i));
+ std::cout << "xxx|" << i << "x" << i
<< "|16 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size, "euclidian.2d.size.sh");
+}
+
+void test_influence_zone_euclidian_3d()
+{
+ mln::util::timer timer;
+
+ // Test the number of labels
+ mln::image1d<float> chart_seed(5*5*5+2);
+
+ mln::data::fill(chart_seed, mln::literal::zero);
+
+ for (unsigned i = 1; i < 5+1; ++i)
+ {
+ influence_zone_euclidian_3d(timer,build_input3d(i,128),build_seed3d(i,128));
+ std::cout << "xxx|128x128x128|" << i << " = "
<< timer.read() << std::endl;
+ mln::opt::at(chart_seed, i*i*i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_seed, "euclidian.3d.seed.sh");
+
+ // Test the size of the image
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256
+ mln::image1d<float> chart_size(128+1);
+
+ mln::data::fill(chart_size, mln::literal::zero);
+
+ for (unsigned i = 6; i < 128+1; ++i)
+ {
+ influence_zone_euclidian_3d(timer, build_input3d(2,i), build_seed3d(2,i));
+ std::cout << "xxx|" << i << "x" << i
<< "x" << i << "|8 = "
+ << timer.read() << std::endl;
+ mln::opt::at(chart_size, i) = timer.read();
+ }
+
+ mln::io::plot::save_image_sh(chart_size, "euclidian.3d.size.sh");
+}
+/// \}
+
+//------------------------------------------------------------------------------
+// Main
+//
+// Point de fonctionnement du système [image de taille entre 1 et 256]
+// Moins de 16 labels
+//
+//------------------------------------------------------------------------------
+
+/// \brief The main routine that call all the benchmark tests.
+///
+/// This benchmark aim at comparing different kind of distance. It
+/// looks after the influence geodesic, the influence front and
+/// euclidian distance. Many files are generated. Some rules exist to
+/// build the name of the file:
+/// distance.neighbouring.dimension.(size|seed). The distance could be
+/// the front distance (front), the geodesic distance (geodesic) or
+/// the euclidian distance (euclidian). The neighbouring could be c04
+/// or c08 in 2d, c06, c18 or c26 in 3d. The dimension could be 2d or 3d.
+/// Finally, the flag size or seed precises the nature of that test, increasing
+/// gradualy the size of the image or increasing gradualy the number of seeds.
+/// The file contains the time benchmark of the distance studied.
+///
+/// \fixme test_influence_zone_geodesic_3d doesn't compile.
+int main()
+{
+ test_influence_zone_euclidian_2d();
+ test_influence_zone_front_2d();
+ test_influence_zone_geodesic_2d();
+
+ // FIXME : It doesn't compile because of a bad calling function at_ in
+ // FIXME : the influence_zone_geodesic.hh line 127.
+ // test_influence_zone_geodesic_3d();
+ test_influence_zone_front_3d();
+ test_influence_zone_euclidian_3d();
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
b/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
new file mode 100644
index 0000000..4455a07
--- /dev/null
+++ b/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
@@ -0,0 +1,153 @@
+#
+# Generic Makefile
+#
+
+#########
+# TOOLS #
+#########
+
+#LOADLIBES= -lboost_filesystem
+INCLUDES1= -I$(HOME)/git/olena/scribo/sandbox/green
+INCLUDES2= -I$(HOME)/git/olena/milena
+INCLUDES= $(INCLUDES1) $(INCLUDES2)
+CXXFLAGS= -ggdb -O0 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O1 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O3 -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/scribo/sandbox/green/demo/clustering/kmean1d/kmean1d.cc
b/scribo/sandbox/green/demo/clustering/kmean1d/kmean1d.cc
new file mode 100644
index 0000000..22eae91
--- /dev/null
+++ b/scribo/sandbox/green/demo/clustering/kmean1d/kmean1d.cc
@@ -0,0 +1,258 @@
+// Copyright (C) 2007,2008,2009,2010 EPITA 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.
+
+/// \file
+///
+/// \brief This is a demonstrator for kmean1d.
+///
+/// The demonstrator produces five kind of results. The file
+/// "color.ppm" allow us to localize the different center in the
+/// image. There is an equivalent file "label.pgm" that's do the same
+/// thing but inplace of a specific color, it gives the label of each
+/// center. It's quit easy with xv, to transform the label image in
+/// the color one. The file "mean.pgm" replaces each label by the mean
+/// of the points that contributate to their center. It is a kind of
+/// abstraction of the reality of the image, of its complexity. In
+/// file "variance_cnv.sh" abscissa axis stands for the convergence
+/// evolution and the ordinate axis for each runs. The "mean_cnv.sh"
+/// file shows the evolution of the centers, whatever the run. The
+/// x-axis represents the id of the center, the y-axis the iteration
+/// in the convergence process and the z-axis the id of the particular
+/// run. The graphic is very bad, but textual interpretation is still
+/// available.
+
+#include <iostream>
+#include <sstream>
+
+#include <mln/img_path.hh>
+
+#include <mln/clustering/kmean1d.hh>
+
+#include <mln/core/image/image2d.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/int_u8.hh>
+
+
+/// \brief The real code for launching the kmean optimised algorithm.
+///
+/// \param[in] image : the 8 bits greylevel image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// This is the real lauching code. In fact, the stuff consists in loading the
+/// image, setting the parameters, calling the routine, extracting the results
+/// and saving them for the user.
+///
+/// \fixme The result is not safe because we don't test kmean.is_valid()
+
+void do_demo(const std::string& image,
+ const unsigned k_center,
+ const unsigned n_times,
+ const unsigned watch_dog)
+{
+ typedef mln::clustering::kmean1d<double,8> t_kmean;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+
+ t_image2d_int_u8 img;
+
+ mln::io::pgm::load(img, image.c_str());
+
+ t_kmean kmean(img,
+ k_center,
+ watch_dog,
+ n_times);
+
+ //mln::trace::quiet = false;
+
+ kmean.launch_n_times();
+
+ // FIXME : 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 var_cnv = kmean.get_variance_cnv();
+ t_kmean::t_mean_cnv mean_cnv = kmean.get_mean_cnv();
+
+ mln::io::pgm::save(mean_img, "mean.pgm");
+ mln::io::ppm::save(color_img, "color.ppm");
+ mln::io::pgm::save(label_img, "label.pgm");
+
+ mln::io::plot::save_image_sh(mean_cnv, "mean_cnv.sh");
+ mln::io::plot::save_image_sh(var_cnv, "variance_cnv.sh");
+}
+
+
+/// \brief Front hand for the demonstrator.
+///
+/// \param[in] image : the 8 bits greylevel image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// The front hand enables the setting of the default values for the
+/// parameters. it allows us to print the real parameter set used by
+/// the demonstrator.
+void demo(const std::string& image = OLENA_IMG_PATH"/house.pgm",
+ 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);
+}
+
+
+/// \brief Convert character get in the input stream to unsigned integer.
+///
+/// \param[in] status : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+/// \param[out] val : the converted value to output.
+///
+/// \return a flag that tell us if every thing is ok, if the result can be used.
+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;
+}
+
+
+/// \brief Convert character get in the input stream to string.
+///
+/// \param[in] status : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+/// \param[out] val : the converted value to output.
+///
+/// \return a flag that tell us if every thing is ok, if the result can be used.
+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;
+}
+
+
+/// \brief Print usage recommandation for this binary.
+///
+/// \param[in] argc : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+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;
+}
+
+
+/// \brief The main routine launchs the kmean optimised algoritm.
+///
+/// \param[in] image : the 8 bits greylevel image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// All the parameters are optional, but we must respect strictly a
+/// specific order. In fact, we can launch five programs with some
+/// default parameters: demo(), demo(image), demo(image,k_center),
+/// demo(image,k_center,n_times) and
+/// demo(image,k_center,n_times,watch_dog).
+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/scribo/sandbox/green/demo/clustering/kmean2d/Makefile.am
b/scribo/sandbox/green/demo/clustering/kmean2d/Makefile.am
new file mode 100644
index 0000000..4455a07
--- /dev/null
+++ b/scribo/sandbox/green/demo/clustering/kmean2d/Makefile.am
@@ -0,0 +1,153 @@
+#
+# Generic Makefile
+#
+
+#########
+# TOOLS #
+#########
+
+#LOADLIBES= -lboost_filesystem
+INCLUDES1= -I$(HOME)/git/olena/scribo/sandbox/green
+INCLUDES2= -I$(HOME)/git/olena/milena
+INCLUDES= $(INCLUDES1) $(INCLUDES2)
+CXXFLAGS= -ggdb -O0 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O1 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O3 -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/scribo/sandbox/green/demo/clustering/kmean2d/kmean2d.cc
b/scribo/sandbox/green/demo/clustering/kmean2d/kmean2d.cc
new file mode 100644
index 0000000..2538dce
--- /dev/null
+++ b/scribo/sandbox/green/demo/clustering/kmean2d/kmean2d.cc
@@ -0,0 +1,278 @@
+// Copyright (C) 2007,2008,2009,2010 EPITA 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.
+
+/// \file
+///
+/// \brief This is a demonstrator for kmean2d.
+///
+/// The demonstrator produces five kind of results. The file
+/// "color.ppm" allow us to localize the different center in the
+/// image. There is an equivalent file "label.pgm" that's do the same
+/// thing but inplace of a specific color, it gives the label of each
+/// center. It's quit easy with xv, to transform the label image in
+/// the color one. The file "mean.pgm" replaces each label by the mean
+/// of the points that contributate to their center. It is a kind of
+/// abstraction of the reality of the image, of its complexity. The
+/// "variance_cnv.sh" changes its representation and becomes more
+/// readable. The "mean_cnv.sh" have got a generation problem. We can
+/// bypass it by adding printing lines in the 'splot'
+/// instruction. However, the graphic is correct and mainly shows the
+/// convergence of the center value. Finally, as the work takes place in
+/// the r/g space, the "point.ppm" file shows us the exact input space.
+
+#include <iostream>
+#include <sstream>
+
+#include <mln/img_path.hh>
+
+#include <mln/clustering/kmean2d.hh>
+
+#include <mln/core/image/image2d.hh>
+
+#include <mln/data/transform.hh>
+
+#include <mln/fun/v2v/rgb_to_rg.hh>
+#include <mln/fun/v2v/rg_to_rgb.hh>
+
+#include <mln/io/pgm/save.hh>
+#include <mln/io/ppm/load.hh>
+#include <mln/io/ppm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/value/rg.hh>
+#include <mln/value/rgb8.hh>
+
+
+/// \brief The real code for launching the kmean optimised algorithm.
+///
+/// \param[in] image : the color image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// This is the real lauching code. In fact, the stuff consists in loading the
+/// image, setting the parameters, calling the routine, extracting the results
+/// and saving them for the user.
+///
+/// \fixme The result is not safe because we don't test kmean.is_valid()
+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::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_rg8> t_image2d_rg8;
+ typedef mln::fun::v2v::rgb_to_rg<8> t_rgb_to_rg;
+ typedef mln::fun::v2v::rg_to_rgb<8> t_rg_to_rgb;
+
+ t_image2d_rgb8 img_rgb8;
+ t_image2d_rgb8 point_img_rgb8;
+ t_image2d_rgb8 mean_img_rgb8;
+ t_image2d_rgb8 mean_dbg_rgb8;
+ t_image2d_rg8 img_rg8;
+
+ // Read input.
+ mln::io::ppm::load(img_rgb8, image.c_str());
+ img_rg8 = mln::data::transform(img_rgb8, t_rgb_to_rg());
+
+ // Call kmean.
+ t_kmean kmean(img_rg8, k_center, watch_dog, n_times);
+
+ mln::trace::quiet = false;
+ kmean.launch_n_times();
+
+ // FIXME : Not safe because we don't test kmean.is_valid()
+
+ // Get outputs.
+ t_kmean::t_point_img point_img = kmean.get_point();
+ 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();
+
+ // Convert outputs.
+ point_img_rgb8 = mln::data::transform(point_img, t_rg_to_rgb());
+ mean_img_rgb8 = mln::data::transform(mean_img, t_rg_to_rgb());
+
+ mln::io::ppm::save(mean_img_rgb8, "mean.ppm");
+ mln::io::ppm::save(color_img, "color.ppm");
+ mln::io::pgm::save(label_img, "label.pgm");
+ mln::io::ppm::save(point_img_rgb8, "point.ppm");
+
+ mln::io::plot::save_image_sh(mean_cnv, "mean_cnv.sh");
+ mln::io::plot::save_image_sh(variance_cnv, "variance_cnv.sh");
+}
+
+
+/// \brief Front hand for the demonstrator.
+///
+/// \param[in] image : the color image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// The front hand enables the setting of the default values for the
+/// parameters. it allows us to print the real parameter set used by
+/// the demonstrator.
+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);
+}
+
+
+/// \brief Convert character get in the input stream to unsigned integer.
+///
+/// \param[in] status : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+/// \param[out] val : the converted value to output.
+///
+/// \return a flag that tell us if every thing is ok, if the result can be used.
+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;
+}
+
+
+/// \brief Convert character get in the input stream to string.
+///
+/// \param[in] status : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+/// \param[out] val : the converted value to output.
+///
+/// \return a flag that tell us if every thing is ok, if the result can be used.
+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;
+}
+
+
+/// \brief Print usage recommandation for this binary.
+///
+/// \param[in] argc : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+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: kmean2d [image [k_center [n_times [watch_dog]]]]"
+ << std::endl;
+ std::cout << "ppm 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;
+}
+
+
+/// \brief The main routine launchs the kmean optimised algoritm.
+///
+/// \param[in] image : the color image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// All the parameters are optional, but we must respect strictly a
+/// specific order. In fact, we can launch five programs with some
+/// default parameters: demo(), demo(image), demo(image,k_center),
+/// demo(image,k_center,n_times) and
+/// demo(image,k_center,n_times,watch_dog).
+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/scribo/sandbox/green/demo/clustering/kmean3d/Makefile.am
b/scribo/sandbox/green/demo/clustering/kmean3d/Makefile.am
new file mode 100644
index 0000000..4455a07
--- /dev/null
+++ b/scribo/sandbox/green/demo/clustering/kmean3d/Makefile.am
@@ -0,0 +1,153 @@
+#
+# Generic Makefile
+#
+
+#########
+# TOOLS #
+#########
+
+#LOADLIBES= -lboost_filesystem
+INCLUDES1= -I$(HOME)/git/olena/scribo/sandbox/green
+INCLUDES2= -I$(HOME)/git/olena/milena
+INCLUDES= $(INCLUDES1) $(INCLUDES2)
+CXXFLAGS= -ggdb -O0 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O1 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O3 -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/scribo/sandbox/green/demo/clustering/kmean3d/kmean3d.cc
b/scribo/sandbox/green/demo/clustering/kmean3d/kmean3d.cc
new file mode 100644
index 0000000..0e2b16e
--- /dev/null
+++ b/scribo/sandbox/green/demo/clustering/kmean3d/kmean3d.cc
@@ -0,0 +1,265 @@
+// Copyright (C) 2007,2008,2009,2010 EPITA 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.
+
+/// \file
+///
+/// \brief This is a demonstrator for kmean3d.
+///
+/// The demonstrator produces five kind of results. The file
+/// "color.ppm" allow us to localize the different center in the
+/// image. There is an equivalent file "label.pgm" that's do the same
+/// thing but inplace of a specific color, it gives the label of each
+/// center. It's quit easy with xv, to transform the label image in
+/// the color one. The file "mean.pgm" replaces each label by the mean
+/// of the points that contributate to their center. It is a kind of
+/// abstraction of the reality of the image, of its complexity. The
+/// "variance_cnv.sh" changes its representation and becomes more
+/// readable. The "mean_cnv.sh" have got a generation problem. We can
+/// bypass it by adding printing lines in the 'splot'
+/// instruction. However, the graphic is correct and mainly shows the
+/// convergence of the center value.
+
+#include <iostream>
+#include <sstream>
+
+#include <mln/clustering/kmean3d.hh>
+
+#include <mln/core/macros.hh>
+#include <mln/core/image/image2d.hh>
+
+#include <mln/data/transform.hh>
+
+#include <mln/fun/v2v/rgb8_to_rgbn.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/img_path.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/value/label_8.hh>
+#include <mln/value/rgb8.hh>
+
+
+/// \brief The real code for launching the kmean optimised algorithm.
+///
+/// \param[in] image : the color image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// This is the real lauching code. In fact, the stuff consists in loading the
+/// image, setting the parameters, calling the routine, extracting the results
+/// and saving them for the user.
+///
+/// \fixme The result is not safe because we don't test kmean.is_valid()
+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_n_times();
+
+ // FIXME : 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");
+}
+
+/// \brief Front hand for the demonstrator.
+///
+/// \param[in] image : the color image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// The front hand enables the setting of the default values for the
+/// parameters. it allows us to print the real parameter set used by
+/// the demonstrator.
+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);
+}
+
+
+/// \brief Convert character get in the input stream to unsigned integer.
+///
+/// \param[in] status : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+/// \param[out] val : the converted value to output.
+///
+/// \return a flag that tell us if every thing is ok, if the result can be used.
+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;
+}
+
+
+/// \brief Convert character get in the input stream to string.
+///
+/// \param[in] status : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+/// \param[out] val : the converted value to output.
+///
+/// \return a flag that tell us if every thing is ok, if the result can be used.
+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;
+}
+
+
+/// \brief Print usage recommandation for this binary.
+///
+/// \param[in] argc : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+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;
+}
+
+
+/// \brief The main routine launchs the kmean optimised algoritm.
+///
+/// \param[in] image : the color image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// All the parameters are optional, but we must respect strictly a
+/// specific order. In fact, we can launch five programs with some
+/// default parameters: demo(), demo(image), demo(image,k_center),
+/// demo(image,k_center,n_times) and
+/// demo(image,k_center,n_times,watch_dog).
+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/scribo/sandbox/green/demo/clustering/kmean_rgb/Makefile.am
b/scribo/sandbox/green/demo/clustering/kmean_rgb/Makefile.am
new file mode 100644
index 0000000..4455a07
--- /dev/null
+++ b/scribo/sandbox/green/demo/clustering/kmean_rgb/Makefile.am
@@ -0,0 +1,153 @@
+#
+# Generic Makefile
+#
+
+#########
+# TOOLS #
+#########
+
+#LOADLIBES= -lboost_filesystem
+INCLUDES1= -I$(HOME)/git/olena/scribo/sandbox/green
+INCLUDES2= -I$(HOME)/git/olena/milena
+INCLUDES= $(INCLUDES1) $(INCLUDES2)
+CXXFLAGS= -ggdb -O0 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O1 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O3 -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/scribo/sandbox/green/demo/clustering/kmean_rgb/kmean_rgb.cc
b/scribo/sandbox/green/demo/clustering/kmean_rgb/kmean_rgb.cc
new file mode 100644
index 0000000..d02c497
--- /dev/null
+++ b/scribo/sandbox/green/demo/clustering/kmean_rgb/kmean_rgb.cc
@@ -0,0 +1,239 @@
+// Copyright (C) 2007,2008,2009,2010 EPITA 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.
+
+/// \file
+///
+/// \brief This is a demonstrator for kmean_rgb.
+///
+/// The code is provided as is. It is an alpha version, so very very
+/// experimental. Take care !!
+
+#include <iostream>
+#include <sstream>
+
+#include <mln/clustering/kmean_rgb.hh>
+
+#include <mln/core/macros.hh>
+#include <mln/core/image/image2d.hh>
+
+#include <mln/data/transform.hh>
+
+#include <mln/fun/v2v/rgb8_to_rgbn.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/img_path.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/value/label_8.hh>
+#include <mln/value/rgb8.hh>
+
+
+/// \brief The real code for launching the kmean optimised algorithm.
+///
+/// \param[in] image : the color image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// This is the real lauching code. In fact, the stuff consists in loading the
+/// image, setting the parameters, calling the routine, extracting the results
+/// and saving them for the user.
+///
+/// \fixme The result is not safe because we don't test kmean.is_valid()
+void do_demo(const std::string& image,
+ const unsigned k_center,
+ const unsigned n_times,
+ const unsigned watch_dog)
+{
+ typedef mln::value::label_8 t_lbl8;
+ 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;
+ typedef mln::image2d<t_lbl8> t_image2d_lbl8;
+
+ t_image2d_rgb8 img_rgb8;
+ t_image2d_rgb5 img_rgb5;
+ t_image2d_lbl8 img_lbl8;
+
+ mln::io::ppm::load(img_rgb8, image.c_str());
+ img_rgb5 = mln::data::transform(img_rgb8,mln::fun::v2v::rgb8_to_rgbn<5>());
+ img_lbl8 = mln::clustering::kmean_rgb<double,5>(img_rgb5,
+ k_center,
+ watch_dog,
+ n_times);
+
+ mln::io::pgm::save(img_lbl8, "label.pgm");
+}
+
+/// \brief Front hand for the demonstrator.
+///
+/// \param[in] image : the color image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// The front hand enables the setting of the default values for the
+/// parameters. it allows us to print the real parameter set used by
+/// the demonstrator.
+void demo(const std::string& image = OLENA_IMG_PATH"/house.ppm",
+ const unsigned k_center = 3,
+ const unsigned n_times = 3,
+ const unsigned watch_dog = 3)
+{
+ 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);
+}
+
+
+/// \brief Convert character get in the input stream to unsigned integer.
+///
+/// \param[in] status : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+/// \param[out] val : the converted value to output.
+///
+/// \return a flag that tell us if every thing is ok, if the result can be used.
+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;
+}
+
+
+/// \brief Convert character get in the input stream to string.
+///
+/// \param[in] status : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+/// \param[out] val : the converted value to output.
+///
+/// \return a flag that tell us if every thing is ok, if the result can be used.
+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;
+}
+
+
+/// \brief Print usage recommandation for this binary.
+///
+/// \param[in] argc : the exiting flag tell us to exit without doing any job.
+/// \param[in] arg : the input argument to convert.
+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;
+}
+
+
+/// \brief The main routine launchs the kmean optimised algoritm.
+///
+/// \param[in] image : the color image.
+/// \param[in] k_center : the number of centers.
+/// \param[in] n_times : the number of launching.
+/// \param[in] watch_dog : the number of iterations to manage the convergence.
+///
+/// All the parameters are optional, but we must respect strictly a
+/// specific order. In fact, we can launch five programs with some
+/// default parameters: demo(), demo(image), demo(image,k_center),
+/// demo(image,k_center,n_times) and
+/// demo(image,k_center,n_times,watch_dog).
+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/scribo/sandbox/green/mln/clustering/k_mean.hh
b/scribo/sandbox/green/mln/clustering/k_mean.hh
index db3f34c..74acda7 100644
--- a/scribo/sandbox/green/mln/clustering/k_mean.hh
+++ b/scribo/sandbox/green/mln/clustering/k_mean.hh
@@ -1,6 +1,4 @@
-// Copyright (C) 2007 EPITA Research and Development Laboratory (LRDE)
-// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2007,2008,2009,2010 EPITA LRDE
//
// This file is part of Olena.
//
@@ -26,43 +24,89 @@
// executable file might be covered by the GNU General Public License.
#ifndef MLN_CLUSTERING_K_MEAN_HH
-#define MLN_CLUSTERING_K_MEAN_HH
+# define MLN_CLUSTERING_K_MEAN_HH
/// \file
///
-/// \brief Implements the K MEAN algorithm.
-/// DO
-/// - ASSIGNEMENT STEP
-/// - UPDATE STEP
-/// LOOP UNTIL CONVERGENCE
+/// \brief Implement the K MEAN algorithm with matrix and vectors.
///
-/// ASSIGNEMENT STEP
+/// This is the first impementation of the kmean algorithm. There is no
+/// specific optimisation but every part of the algorithm is here and
+/// it works. As it used vectors and matrices, it is not very convenient to
+/// work with this version.
+///
+/// \verbatim
+/// This is the main lines of the kmean algorithm:
+///
+/// PROCEDURE MAIN
+/// BEGIN
+/// DO
+/// - CALL ASSIGNEMENT STEP
+/// - CALL UPDATE STEP
+/// LOOP UNTIL CONVERGENCE
+/// END
+///
+/// PROCEDURE ASSIGNEMENT STEP
/// BEGIN
-/// - COMPUTE THE DISTANCE MATRIX FROM POINTS TO CENTERS
-/// - COMPUTE GROUP MATRIX WHERE EACH POINT IS ASSIGNED TO NEAREST CENTER
+/// - COMPUTE THE DISTANCE MATRIX FROM POINTS TO CENTERS
+/// - COMPUTE GROUP MATRIX WHERE EACH POINT IS ASSIGNED TO THE NEAREST CENTER
/// END
///
-/// UPDATE STEP
+/// PROCEDURE UPDATE STEP
/// BEGIN
-/// - COMPUTE THE MEAN OF THE GROUPS WHICH ARE THE NEW CENTERS
+/// - COMPUTE THE MEAN OF THE GROUPS WHICH ARE NOW THE NEW CENTERS
/// END
+/// \endvarbitim
+///
+/// The following sample is the standard use of this first
+/// implementation. The number of centers is a decision left to the
+/// final user. As the representation uses vectors and matices, size
+/// of each objects must be known at compile time, and so NB_POINT must be
+/// a constant expression (mln::geom::nsites couldn't be called).
+///
+/// #include <mln/clustering/k_mean.hh>
+/// #include <mln/core/image/image2d.hh>
+/// #include <mln/img_path.hh>
+/// #include <mln/io/ppm/load.hh>
+/// #include <mln/trait/value_.hh>
+/// #include <mln/value/rgb8.hh>
+///
+/// #define NB_CENTER 9
+/// #define NB_POINT (128*128)
+/// #define POINT_SIZE mln_dim(mln::value::rgb8)
+/// #define POINT_TYPE double
+///
+/// int main()
+/// {
+/// typedef mln::value::rgb8 t_rgb8;
+/// mln::image2d<t_rgb8> img_rgb8;
+///
+/// mln::io::ppm::load(img_ref, OLENA_IMG_PATH"/house.ppm");
+/// mln::clustering::k_mean<NB_POINT,NB_CENTER,POINT_SIZE,POINT_TYPE> kmean;
+///
+/// kmean.init_point(img_rgb8);
+/// kmean.loop(img_rgb8);
+///
+/// return 0;
+/// }
+
+# include <limits.h>
+# include <iostream>
-#include <limits.h>
-#include <iostream>
-#include <mln/trace/entering.hh>
-#include <mln/trace/exiting.hh>
+# include <mln/algebra/mat.hh>
+# include <mln/algebra/vec.hh>
-#include <mln/core/contract.hh>
-#include <mln/trait/value_.hh>
+# include <mln/core/concept/image.hh>
+# include <mln/core/contract.hh>
+# include <mln/core/macros.hh>
-#include <mln/algebra/mat.hh>
-#include <mln/algebra/vec.hh>
+# include <mln/math/min.hh>
+# include <mln/norm/l2.hh>
-#include <mln/math/min.hh>
-#include <mln/norm/l2.hh>
+# include <mln/trace/entering.hh>
+# include <mln/trace/exiting.hh>
-#include <mln/core/concept/image.hh>
-#include <mln/core/macros.hh>
+# include <mln/trait/value_.hh>
namespace mln
{
@@ -78,149 +122,221 @@ namespace mln
namespace clustering
{
-
- //
- // PARAM : DIM VECTOR, NUMBER OF CLASSES
- // INPUT : MATRIX 1..N (SAMPLE)
- // WORK
- //
-
- // n is the size of the sample.
- // k is the number of centers.
- // p is the number of attributes for a point.
- // T is the type for computations.
+
+ /// \brief Implements the K MEAN algorithm with matrix and vectors.
+ ///
+ /// Param n is the size of the sample (the number of point to be
+ /// classified). Param k is the number of centers, at the end,
+ /// each point is link to one the nearest center. Param p is the
+ /// number of attributes of a point, in fact its dimension (int_u8
+ /// = 1, rgb8 = 3, etc ...). Param T is the type used for
+ /// computations, the type of the point, typiccaly float or
+ /// double.
+ ///
+ /// \ingroup modclustering
template <unsigned n, unsigned k, unsigned p, typename T>
struct k_mean
{
- //------------------------------------------------------------------------
- // Constructor and destructor
- //------------------------------------------------------------------------
-
+ /// Constructors and destructors.
+ /// \{
+ /// \brief Allocate or deallocate the data structure.
+ ///
+ /// Allocate or deallocate the _point, _distance, _group,
+ /// _center, _variance data structure with the correct size.
k_mean();
~k_mean();
+ /// \}
- //------------------------------------------------------------------------
- // Accessors
- //------------------------------------------------------------------------
-
+ /// Accessors.
+ /// \{
+ /// \brief Hack to view temporary results of the kmean algorithm.
+ ///
+ /// These methods are necessary for unitary testing and debugging.
algebra::mat<n, p, T>& get_point();
algebra::mat<k, p, T>& get_center();
algebra::mat<n, k, T>& get_distance();
algebra::mat<n, k, T>& get_group();
algebra::vec<k, T>& get_variance();
+ /// \}
-
- //------------------------------------------------------------------------
- // Tools
- //------------------------------------------------------------------------
+ /// Tools.
+ /// \{
+ /// \brief Define elementary function that are not available from milena.
+ ///
+ /// These methods are not interesting from the kmean'point of
+ /// view but are required for the gluing process.
- /// \brief Return the euclidian distance beetween vector x and vector y.
+ /// \brief Return the euclidian distance beetween two vectors x and y.
///
/// Compute the f$\sqrt(\sum_{i=0}^P ((x_i - y_i)^2)$f
///
- /// \param[in] x a vector of dimension 1xP.
- /// \param[in] y a second vector of dimension 1xP.
+ /// \param[in] x a vector of dimension p.
+ /// \param[in] y a second vector of dimension p.
/// \return the distance between x and y.
-
mln_sum_product(T,T) euclidian_distance(const algebra::vec<p,T>& x,
const algebra::vec<p,T>& y) const;
- /// \brief Return the ith column.
- ///
- /// \param[in] m a matrix of dimension {N or K}xP.
- /// \return the ith column as a vector of dimension 1xP.
-
- /// \brief Return the ith column.
+ /// \brief Return a stack copy of the ith column.
///
- /// \param[in] m a matrix of dimension {N or K}xP.
- /// \return the ith column as a vector of dimension 1xP.
+ /// \param[in] m a matrix of dimension r x q.
+ /// \param[in] _col the index of the selected column.
+ /// \return a stack copy of the ith column as a vector of dimension q.
template <unsigned q, unsigned r>
algebra::vec<q,T> col(const algebra::mat<r, q, T>& m,
const unsigned _col) const;
+
+ /// \brief Return a heap copy of the ith col.
+ ///
+ /// \param[in] m a matrix of dimension r x q.
+ /// \param[in] _col the index of the selected column.
+ /// \return a heap copy of the ith column as a vector of dimension q.
template <unsigned q, unsigned r>
algebra::vec<q,T>* ptr_col(const algebra::mat<r, q, T>& m,
const unsigned _col) const;
+
+ /// \brief Return a stack copy of the ith row.
+ ///
+ /// \param[in] m a matrix of dimension r x q.
+ /// \param[in] _row the index of the selected row.
+ /// \return a stack copy of the ith row as a vector of dimension q.
template <unsigned q, unsigned r>
algebra::vec<r,T> row(const algebra::mat<r, q, T>& m,
const unsigned _row) const;
+
+ /// \brief Divide inplace a column of the matrix by a scalar.
+ ///
+ /// \param[in] m a matrix of dimension r x q.
+ /// \param[in] _col the index of the selected column.
+ /// \param[in] value the scalar by which dividing the column.
template <unsigned q, unsigned r>
void div_col(algebra::mat<r, q, T>& m,
const unsigned _col,
const T value);
+
+ /// \brief Sum all the elements of one row.
+ ///
+ /// \param[in] m a matrix of dimension r x q.
+ /// \param[in] _row the index of the selected row.
+ /// \return the sum of every attributes of the row.
template <unsigned q, unsigned r>
mln_sum(T) sum_row(const algebra::mat<r, q, T>& m,
const unsigned _row) const;
+
+ /// \brief Return the minimum of a vector.
+ ///
+ /// \param[in] x a vector of dimension q.
+ /// \return the mininum of that input vector.
template <unsigned q, typename M>
M min_col(const algebra::vec<q, M>& x) const;
+ /// \}
- //------------------------------------------------------------------------
- // Initializations of points and centers
- //------------------------------------------------------------------------
-
- /// \brief Initialize the matrix _point with the pixels of an image.
+ /// Initializations.
+ /// \{
+ /// \brief Initialize the _point and _center data structure.
///
- /// \param[in] input an image which contains the data points.
+ /// The _point data structure is fed with the value of the input
+ /// image. The _center data structure is fed with random points
+ /// taken from the input image.
template <typename I>
void init_point(const Image<I>& _input);
void init_center();
+ /// \}
-
- //------------------------------------------------------------------------
- // Computations of distance, group, center, within variance
- //------------------------------------------------------------------------
+ /// Computations.
+ /// \{
+ /// \brief Define the core routines of the kmean algorithm.
+ ///
+ /// The update_distance, update_group, update_center and update_variance
+ /// define the core kmean routines. If some optimization muste be done,
+ /// one may looks here.
+
+
+ /// \brief Update the _distance data structure.
+ ///
+ /// Compute the square distance between each point of the data
+ /// cloud and each center.
void update_distance();
+
+ /// \brief Update the _group data structure.
+ ///
+ /// For each point of the data cloud, find the group which has
+ /// the minimum distance from it.
void update_group();
- void update_center();
- T update_variance();
+ /// \brief Update the _center data structure.
+ ///
+ /// For each group, compute the center of mass in therm of
+ /// points of the data cloud.
+ void update_center();
- //------------------------------------------------------------------------
- // Main loop
- //------------------------------------------------------------------------
+ /// \brief Update the _variance.
+ ///
+ /// Compute the within variance. Sum every shortest distance.
+ T update_variance();
+ /// \}
+ /// \brief Define the orchestration of the kmean core routines.
+ ///
+ /// \param[in] _input the initial image which initialize the data cloud.
+ ///
+ /// The orchestration is in a fact a loop which call one after
+ /// each other the core routines. Ending the loop means managing
+ /// the statistical convergence or having some clues of
+ /// divergence (watch_dog).
template <typename I>
void loop(const Image<I>& _input);
- //void loop();
private:
+ /// \brief watch_dog define the maximum of iterations that can be done.
+ ///
+ /// That constant help us to decide if divergence has been
+ /// occurred or not.
static const unsigned watch_dog = 100;
-
+
+
/// \brief _points contains the concatenation of every data points.
///
- /// One data point is a vector 1xP where P is the number of attributes.
- /// _points is a matrix NxP where N is the number of data points.
+ /// One data point is a vector 1 x p where p is the number of attributes.
+ /// So _points is a matrix n x P where n is the number of data points.
algebra::mat<n, p, T>* _point;
+
/// \brief _distance contains all the euclidian distances between points
/// and the centers.
///
- /// _distance is a matrix NxK where N is the number of data points and
- /// K the number of centers.
+ /// _distance is a matrix n x k where n is the number of data points and
+ /// k the number of centers.
algebra::mat<n, k, mln_sum_product(T,T)>* _distance;
+
/// \brief _group contains the point assignement to one center.
///
- /// _group is a boolean matrix NxK where N is the number of data points
- /// and K the number of centers.
+ /// _group is a boolean matrix n x k where n is the number of data points
+ /// and k the number of centers.
algebra::mat<n, k, T>* _group;
- /// \brief _center contains the coordonnate of the K centers.
+
+ /// \brief _center contains the coordonnate of the k centers.
///
- /// _center is a matrix KxP where K is the number of centers and P is the
- /// number of attributes.
+ /// _center is a matrix k x p where k is the number of centers
+ /// and p is the number of attributes.
algebra::mat<k, p, T>* _center;
+
+ /// \brief _variance contains the variance of each group.
+ ///
+ /// _variance is a vector 1 x k where k is the number of centers.
algebra::vec<k, T>* _variance;
};
@@ -234,7 +350,7 @@ namespace mln
inline
k_mean<n,k,p,T>::k_mean()
{
- trace::entering("mln::clustering::k_mean::k_mean");
+ trace::entering("mln::clustering::k_mean::cstor");
_point = new algebra::mat<n, p, T>();
_distance = new algebra::mat<n, k, mln_sum_product(T,T)>();
@@ -248,14 +364,14 @@ namespace mln
mln_postcondition(_center != 0);
mln_postcondition(_variance != 0);
- trace::exiting("mln::clustering::k_mean::k_mean");
+ trace::exiting("mln::clustering::k_mean::cstor");
}
template <unsigned n, unsigned k, unsigned p, typename T>
inline
k_mean<n,k,p,T>::~k_mean()
{
- trace::entering("mln::clustering::k_mean::~k_mean");
+ trace::entering("mln::clustering::k_mean::dstor");
delete _point;
delete _distance;
@@ -263,7 +379,7 @@ namespace mln
delete _center;
delete _variance;
- trace::exiting("mln::clustering::k_mean::~k_mean");
+ trace::exiting("mln::clustering::k_mean::dstor");
}
//--------------------------------------------------------------------------
@@ -350,7 +466,7 @@ namespace mln
template <unsigned n, unsigned k, unsigned p, typename T>
template <unsigned q, unsigned r>
inline
- algebra::vec<q,T> k_mean<n,k,p,T>::col(const algebra::mat<r, q,
T>& m,
+ algebra::vec<q,T> k_mean<n,k,p,T>::col(const algebra::mat<r, q,
T>& m,
const unsigned _col) const
{
trace::entering("mln::clustering::k_mean::col");
@@ -368,7 +484,7 @@ namespace mln
template <unsigned n, unsigned k, unsigned p, typename T>
template <unsigned q, unsigned r>
inline
- algebra::vec<q,T>* k_mean<n,k,p,T>::ptr_col(const algebra::mat<r, q,
T>& m,
+ algebra::vec<q,T>* k_mean<n,k,p,T>::ptr_col(const algebra::mat<r, q,
T>& m,
const unsigned _col) const
{
trace::entering("mln::clustering::k_mean::ptr_col");
@@ -386,7 +502,7 @@ namespace mln
template <unsigned n, unsigned k, unsigned p, typename T>
template <unsigned q, unsigned r>
inline
- mln_sum(T) k_mean<n,k,p,T>::sum_row(const algebra::mat<r, q, T>& m,
+ mln_sum(T) k_mean<n,k,p,T>::sum_row(const algebra::mat<r, q, T>& m,
const unsigned _row) const
{
trace::entering("mln::clustering::k_mean::sum_row");
@@ -404,7 +520,7 @@ namespace mln
template <unsigned n, unsigned k, unsigned p, typename T>
template <unsigned q, unsigned r>
inline
- void k_mean<n,k,p,T>::div_col(algebra::mat<r, q, T>& m,
+ void k_mean<n,k,p,T>::div_col(algebra::mat<r, q, T>& m,
const unsigned _col,
const T value)
{
@@ -422,21 +538,21 @@ namespace mln
inline
M k_mean<n,k,p,T>::min_col(const algebra::vec<q, M>& x) const
{
- trace::entering("mln::clustering::k_mean<n,k,p,T>::min_col");
-
+ trace::entering("mln::clustering::k_mean::min_col");
+
M result = x[0];
for (unsigned i = 1; i < q; ++i)
result = math::min(result, x[i]);
- trace::exiting("mln::clustering::k_mean<n,k,p,T>::min_col");
+ trace::exiting("mln::clustering::k_mean::min_col");
return result;
}
template <unsigned n, unsigned k, unsigned p, typename T>
inline
mln_sum_product(T,T)
- k_mean<n,k,p,T>::euclidian_distance(const algebra::vec<p, T>& x,
+ k_mean<n,k,p,T>::euclidian_distance(const algebra::vec<p, T>& x,
const algebra::vec<p, T>& y) const
{
trace::entering("mln::clustering::k_mean::euclidian_distance");
@@ -458,8 +574,8 @@ namespace mln
inline
void k_mean<n,k,p,T>::init_point(const Image<I>& _input)
{
- trace::entering("mln::clustering::k_mean<n,k,p,T>::init");
-
+ trace::entering("mln::clustering::k_mean::init");
+
const I& input = exact(_input);
algebra::mat<n, p, T>& point = *_point;
@@ -474,28 +590,28 @@ namespace mln
for_all(pi)
{
//std::cout << pi << std::endl;
-
+
++i;
for (unsigned j = 0; j < p; ++j)
{
-
+
point(i,j) = input(pi).comp(j);
//point(i,j) = input(pi);
}
}
- trace::exiting("mln::clustering::k_mean<n,k,p,T>::init");
+ trace::exiting("mln::clustering::k_mean::init");
}
template <unsigned n, unsigned k, unsigned p, typename T>
inline
void k_mean<n,k,p,T>::init_center()
{
- trace::entering("mln::clustering::k_mean<n,k,p,T>::init_center");
-
+ trace::entering("mln::clustering::k_mean::init_center");
+
algebra::mat<n, p, T>& point = *_point;
algebra::mat<k, p, T>& center = *_center;
-
+
// A random point is choosen to be the initial value for a center.
for (unsigned i = 0; i < k; ++i)
{
@@ -503,16 +619,16 @@ namespace mln
for (unsigned j = 0; j < p; ++j)
{
- center(i,j) = point(random, j);
+ center(i,j) = point(random, j);
}
//std::cout << "center(" << i << ")" <<
col(center, i) << std::endl;
}
- trace::exiting("mln::clustering::k_mean<n,k,p,T>::init_center");
+ trace::exiting("mln::clustering::k_mean::init_center");
}
-
+
//--------------------------------------------------------------------------
// Computations of distance, group, center, within variance
//--------------------------------------------------------------------------
@@ -528,7 +644,7 @@ namespace mln
algebra::mat<n, p, T>& point = *_point;
algebra::mat<n, k, T>& distance = *_distance;
algebra::mat<k, p, T>& center = *_center;
-
+
// for all points in the data cloud.
for (unsigned i = 0; i < n; ++i)
{
@@ -546,7 +662,7 @@ namespace mln
inline
void k_mean<n,k,p,T>::update_group()
{
- trace::entering("mln::clustering::k_mean<n,k,p,T>::update_group");
+ trace::entering("mln::clustering::k_mean::update_group");
algebra::mat<n, k, mln_sum_product(T,T)>& distance = *_distance;
algebra::mat<n, k, T>& group = *_group;
@@ -563,14 +679,14 @@ namespace mln
}
// mln_postcondition(sum(col(distance(i,j)) == 1) Vi
- trace::exiting("mln::clustering::k_mean<n,k,p,T>::update_group");
+ trace::exiting("mln::clustering::k_mean::update_group");
}
template <unsigned n, unsigned k, unsigned p, typename T>
inline
void k_mean<n,k,p,T>::update_center()
{
-
trace::entering("mln::clustering::k_mean<n,k,p,T>::update_center");
+ trace::entering("mln::clustering::k_mean::update_center");
algebra::mat<n, p, T>& point = *_point;
algebra::mat<k, p, T>& center = *_center;
@@ -592,14 +708,14 @@ namespace mln
for (unsigned i = 0; i < k; ++i)
div_col(center, i, sum_row(group, i));
- trace::exiting("mln::clustering::k_mean<n,k,p,T>::update_center");
+ trace::exiting("mln::clustering::k_mean::update_center");
}
template <unsigned n, unsigned k, unsigned p, typename T>
inline
T k_mean<n,k,p,T>::update_variance()
{
-
trace::entering("mln::clustering::k_mean<n,k,p,T>::update_variance");
+ trace::entering("mln::clustering::k_mean::update_variance");
algebra::vec<k, T>& variance = *_variance;
algebra::mat<n, k, T>& distance = *_distance;
@@ -613,10 +729,10 @@ namespace mln
result += variance[i];
}
-
trace::exiting("mln::clustering::k_mean<n,k,p,T>::update_variance");
+ trace::exiting("mln::clustering::k_mean::update_variance");
return result;
- }
-
+ }
+
//--------------------------------------------------------------------------
// Main loop
@@ -626,9 +742,8 @@ namespace mln
template <typename I>
inline
void k_mean<n,k,p,T>::loop(const Image<I>& _input)
- //void k_mean<n,k,p,T>::loop()
{
- trace::entering("mln::clustering::k_mean<n,k,p,T>::loop");
+ trace::entering("mln::clustering::k_mean::loop");
T within_variance = INT_MAX-1;
T old_variance = INT_MAX;
@@ -658,12 +773,10 @@ namespace mln
std::cout << i << " : " << within_variance <<
std::endl;
}
- trace::exiting("mln::clustering::k_mean<n,k,p,T>::loop");
- }
-
-
+ trace::exiting("mln::clustering::k_mean::loop");
+ }
-#endif // ! MLN_INCLUDE_ONLY
+# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::clustering
diff --git a/scribo/sandbox/green/mln/clustering/kmean1d.hh
b/scribo/sandbox/green/mln/clustering/kmean1d.hh
index c3c1add..57d246b 100644
--- a/scribo/sandbox/green/mln/clustering/kmean1d.hh
+++ b/scribo/sandbox/green/mln/clustering/kmean1d.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2008,2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2007,2008,2009,2010 EPITA LRDE
//
// This file is part of Olena.
//
@@ -24,7 +24,7 @@
// executable file might be covered by the GNU General Public License.
#ifndef MLN_CLUSTERING_KMEAN1D_HH
-#define MLN_CLUSTERING_KMEAN1D_HH
+# define MLN_CLUSTERING_KMEAN1D_HH
/// \file
///
@@ -34,36 +34,63 @@
/// 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
+/// by a fix cost in the complexity. This version is very adapted to
/// images with small quantification.
+///
+/// The following sample is a typical use of the new kmean implementation.
+///
+/// #include <iostream>
+/// #include <mln/clustering/kmean1d.hh>
+/// #include <mln/core/image/image2d.hh>
+/// #include <mln/img_path.hh>
+/// #include <mln/io/pgm/load.hh>
+/// #include <mln/value/int_u8.hh>
+///
+/// int main()
+/// {
+/// typedef mln::value::int_u8 t_int_u8;
+/// typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+/// t_image2d_int_u8 img_int_u8;
+///
+/// mln::io::pgm::load(img_int_u8, OLENA_IMG_PATH"/house.pgm");
+/// mln::clustering::kmean1d<double, 8> kmean(img_int_u8, 3);
+///
+/// kmean.launch_n_times();
+///
+/// return 0;
+/// }
+
+# include <limits.h>
+# include <iostream>
-#include <limits.h>
-#include <iostream>
-#include <mln/trace/entering.hh>
-#include <mln/trace/exiting.hh>
+# include <mln/accu/stat/histo1d.hh>
-#include <mln/core/contract.hh>
-#include <mln/trait/value_.hh>
-#include <mln/accu/stat/histo1d.hh>
+# include <mln/core/contract.hh>
+# include <mln/core/image/image2d.hh>
+# include <mln/core/macros.hh>
-#include <mln/math/min.hh>
-#include <mln/math/sqr.hh>
-#include <mln/norm/l2.hh>
+# include <mln/data/compute.hh>
+# include <mln/data/fill.hh>
+# include <mln/debug/println.hh>
-#include <mln/core/image/image2d.hh>
-#include <mln/value/int_u.hh>
-#include <mln/value/rgb8.hh>
-#include <mln/core/macros.hh>
+# include <mln/io/ppm/save.hh>
+# include <mln/io/pgm/save.hh>
-#include <mln/data/compute.hh>
-#include <mln/debug/println.hh>
-#include <mln/data/fill.hh>
-#include <mln/literal/zero.hh>
-#include <mln/labeling/colorize.hh>
-#include <mln/labeling/mean_values.hh>
+# include <mln/literal/zero.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/math/min.hh>
+# include <mln/math/sqr.hh>
+# include <mln/norm/l2.hh>
+
+# include <mln/trace/entering.hh>
+# include <mln/trace/exiting.hh>
+
+# include <mln/trait/value_.hh>
+
+# include <mln/value/int_u.hh>
+# include <mln/value/rgb8.hh>
namespace mln
{
@@ -85,8 +112,8 @@ namespace mln
/// 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.
+ /// Param T is the type used for computations (float or double).
+ /// Param n is the quantification for the image grayscale.
template <typename T, unsigned n>
struct kmean1d
{
@@ -117,32 +144,22 @@ namespace mln
///}
- //------------------------------------------------------------------------
- // Constructor
- //------------------------------------------------------------------------
-
- /// \brief 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).
-
kmean1d(const t_point_img& point,
const unsigned k_center,
const unsigned watch_dog = 10,
const unsigned n_times = 10);
- //------------------------------------------------------------------------
- // Accessors
- //------------------------------------------------------------------------
-
- /// Mutator and accessors.
+ /// Mutators 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);
@@ -173,31 +190,21 @@ namespace mln
/// \}
- //------------------------------------------------------------------------
- // Initializations of centers
- //------------------------------------------------------------------------
-
/// Initialization of centers.
/// \{
- /// \brief Two ways: Regular greylevel tick or random greylevel value or.
+ /// \brief Initialize centers by regular tick or random position.
///
/// 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.
@@ -206,36 +213,27 @@ namespace mln
/// 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).
-
+ /// There are two ways to launch the kmean process. The first
+ /// one allows to run it one time until convergence. As the
+ /// process is a descent, it depends on the initial center
+ /// location. 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.
/// \{
@@ -244,15 +242,10 @@ namespace mln
/// 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.
-
+ /// associate to it) or a failure in the convergence.
bool is_descent_valid();
-
/// \}
- //------------------------------------------------------------------------
- // Debugging tools
- //------------------------------------------------------------------------
/// Debugging tools
/// \{
@@ -264,12 +257,10 @@ namespace mln
/// 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_all_dbg();
void update_cnv();
void finalize_cnv();
-
/// \}
@@ -279,20 +270,19 @@ namespace mln
/// \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
+ /// In fact, watch_dog limits 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.
@@ -300,26 +290,25 @@ namespace mln
/// 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.
-
+ /// is just the sum of all ponderated variances 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_result _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.
@@ -327,23 +316,23 @@ namespace mln
/// 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_result _variance_min;
t_mean_img _mean_min;
+ /// \}
+
/// Inputs.
/// \{
- /// \brief The inputs are the distribution of the values and the values.
+ /// \brief The inputs are the distribution of 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.
@@ -354,13 +343,12 @@ namespace mln
/// 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.
@@ -369,15 +357,14 @@ namespace mln
/// 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.
+ /// \brief Some information exports 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
@@ -385,14 +372,13 @@ namespace mln
/// 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.
+
+ /// Variance and center evolutions.
/// \{
/// \brief Trace the variance and the center evolution.
///
@@ -401,10 +387,8 @@ namespace mln
/// 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;
-
/// \}
};
@@ -803,8 +787,6 @@ namespace mln
{
trace::entering("mln::clustering::kmean1d::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
@@ -872,7 +854,7 @@ namespace mln
for_all(g)
{
- if (l.ind() == _group(g))
+ if (static_cast<t_label>(l.ind()) == _group(g))
_variance(l) += _distance(point2d(g.ind(), l.ind()));
}
@@ -1091,7 +1073,7 @@ namespace mln
trace::exiting("mln::clustering::kmean1d::launch_n_times");
}
-#endif // ! MLN_INCLUDE_ONLY
+# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::clustering
diff --git a/scribo/sandbox/green/mln/clustering/kmean2d.hh
b/scribo/sandbox/green/mln/clustering/kmean2d.hh
index e4918db..51aaf49 100644
--- a/scribo/sandbox/green/mln/clustering/kmean2d.hh
+++ b/scribo/sandbox/green/mln/clustering/kmean2d.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2008,2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2007,2008,2009,2010 EPITA LRDE
//
// This file is part of Olena.
//
@@ -24,52 +24,102 @@
// executable file might be covered by the GNU General Public License.
#ifndef MLN_CLUSTERING_KMEAN2D_HH
-#define MLN_CLUSTERING_KMEAN2D_HH
+# define MLN_CLUSTERING_KMEAN2D_HH
/// \file
///
-/// \brief Implements the optimized kmean algorithm.
+/// \brief Implements the optimized kmean algorithm in 2d.
///
/// 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>
+/// by a fix cost in the complexity. This version is very adapted to
+/// images with small quantification. But, in 2d, the execution
+/// becomes very slow. It's just normal because the quantification is
+/// 8 bits per axis. So the actual histogram is bigger than the image.
+///
+/// Take care to the following point: The within variance is still a
+/// scalar value because we take the distance between two points and
+/// the result is a scalar from the geometrical point of view. An
+/// alternative implementation could study the variance/covariance
+/// matrix of each sub data clouds and works with the trace of the
+/// within variance matrix (as we do for the fisher criteria in N-d).
+///
+/// The following sample is a typical use of the new kmean implementation.
+///
+/// #include <iostream>
+/// #include <mln/clustering/kmean2d.hh>
+/// #include <mln/core/image/image2d.hh>
+/// #include <mln/data/transform.hh>
+/// #include <mln/fun/v2v/rgb_to_rg.hh>
+/// #include <mln/img_path.hh>
+/// #include <mln/io/ppm/load.hh>
+/// #include <mln/value/rg.hh>
+/// #include <mln/value/rgb8.hh>
+///
+/// int main()
+/// {
+/// typedef mln::value::rg<8> t_rg8;
+/// typedef mln::value::rgb8 t_rgb8;
+/// typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+/// typedef mln::image2d<t_rg8> t_image2d_rg8;
+/// typedef mln::fun::v2v::rgb_to_rg<8> t_rgb_to_rg;
+///
+/// t_image2d_rgb8 img_rgb8;
+/// t_image2d_rg8 img_rg8;
+///
+/// mln::io::ppm::load(img_rgb8, OLENA_IMG_PATH"/house.ppm");
+///
+/// img_rg8 = mln::data::transform(img_rgb8, t_rgb_to_rg());
+///
+/// mln::clustering::kmean2d<double, 8> kmean(img_rg8, 3);
+///
+/// kmean.launch_n_times();
+///
+/// return 0;
+/// }
+
+# include <limits.h>
+# include <iostream>
+
+# include <mln/accu/stat/histo2d.hh>
+
+# include <mln/algebra/vec.hh>
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/contract.hh>
+# include <mln/core/image/image2d.hh>
+# include <mln/core/macros.hh>
+
+# include <mln/data/compute.hh>
+# include <mln/data/fill.hh>
+
+# include <mln/debug/println.hh>
+
+# include <mln/io/pgm/save.hh>
+# include <mln/io/ppm/save.hh>
+
+# include <mln/labeling/colorize.hh>
+# include <mln/labeling/mean_values.hh>
+
+# include <mln/literal/one.hh>
+# include <mln/literal/zero.hh>
+
+# include <mln/math/min.hh>
+# include <mln/math/sqr.hh>
+# include <mln/norm/l2.hh>
+
+# include <mln/trace/entering.hh>
+# include <mln/trace/exiting.hh>
+
+# include <mln/trait/value_.hh>
+
+# include <mln/util/array.hh>
+
+# include <mln/value/int_u.hh>
+# include <mln/value/rgb8.hh>
+# include <mln/value/rg.hh>
namespace mln
{
@@ -85,21 +135,22 @@ namespace mln
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.
+ /// This version of the kmean algorithm uses a 2-channels
+ /// (red/green channel) 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.
+ /// Param T is the type used for computations (float or double).
+ /// Param 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;
@@ -108,7 +159,7 @@ namespace mln
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.
+ /// \fixme t_point_img is not an image2d ... but it works like this ...
typedef image2d<t_value> t_point_img;
typedef image2d<unsigned> t_histo_img;
typedef util::array<t_result1d> t_number_img;
@@ -128,35 +179,24 @@ namespace mln
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
+ /// \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.
+ /// Mutators 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);
@@ -187,10 +227,10 @@ namespace mln
/// \}
- //------------------------------------------------------------------------
- // Printing temporary results
- //------------------------------------------------------------------------
-
+ /// Show temporary results.
+ /// \{
+ /// \brief Formating temporary outputs for debugging.
+ ///
void print_mean();
void print_number();
void print_variance();
@@ -198,32 +238,18 @@ namespace mln
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.
+ /// \brief Initialize centers by random position.
///
- /// 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.
-
+ /// Assign a random position in the 2-channel space to each center.
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.
@@ -232,36 +258,27 @@ namespace mln
/// 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).
-
+ /// There are two ways to launch the kmean process. The first
+ /// one allows to run it one time until convergence. As the
+ /// process is a descent, it depends on the initial center
+ /// location. 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.
/// \{
@@ -269,16 +286,11 @@ namespace mln
///
/// 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.
-
+ /// for us. The method looks for a bad center (a class with no r/g color
+ /// associate to it) or a failure in the convergence.
bool is_descent_valid();
-
/// \}
- //------------------------------------------------------------------------
- // Debugging tools
- //------------------------------------------------------------------------
/// Debugging tools
/// \{
@@ -290,13 +302,11 @@ namespace mln
/// 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();
-
/// \}
@@ -313,13 +323,12 @@ namespace mln
/// 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.
@@ -337,16 +346,15 @@ namespace mln
/// 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.
@@ -354,10 +362,11 @@ namespace mln
/// 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.
/// \{
@@ -365,12 +374,11 @@ namespace mln
///
/// 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.
@@ -381,27 +389,25 @@ namespace mln
/// 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_mean_img _mean; // k x 2
t_variance_img _variance; // k x 1 within group
-
/// \}
+
/// Greylevels description.
/// \{
- /// \brief The information are concerned with the greylevel input image.
+ /// \brief The information are concerned with the 2-channel input image.
///
- /// The group image allow us to decide which greylevel (and of course
+ /// The group image allow us to decide which r/g value (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
-
+ /// clue on how a r/g value could contribute to a center. The summation
+ /// over the r/g values of a center give us the within variance.
+ t_group_img _group; // g x 2 because dim(t_value) = 2
+ t_distance_img _distance; // label x r/g value
/// \}
+
/// Debugging, calibrating and testing results.
/// \{
/// \brief Some exports information to control the results.
@@ -412,14 +418,13 @@ namespace mln
/// 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.
+
+ /// Variance and center evolutions.
/// \{
/// \brief Trace the variance and the center evolution.
///
@@ -428,10 +433,8 @@ namespace mln
/// 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;
-
/// \}
};
@@ -448,7 +451,7 @@ namespace mln
const unsigned watch_dog,
const unsigned n_times)
{
- trace::entering("mln::clustering::kmean2d::kmean2d");
+ trace::entering("mln::clustering::kmean2d::cstor");
mln_precondition(point.is_valid());
_k_center = k_center;
@@ -516,7 +519,7 @@ namespace mln
_mean_cnv.append(mean_set);
}
- trace::exiting("mln::clustering::kmean2d::kmean2d");
+ trace::exiting("mln::clustering::kmean2d::cstor");
}
//--------------------------------------------------------------------------
@@ -796,15 +799,15 @@ namespace mln
{
trace::entering("mln::clustering::kmean2d::print_histo");
- mln_piter(t_histo_img) rgb(_histo.domain());
+ mln_piter(t_histo_img) rg(_histo.domain());
- for_all(rgb)
+ for_all(rg)
{
- if (0 < _histo(rgb))
+ if (0 < _histo(rg))
{
- std::cout << "histo(r=" << rgb.row();
- std::cout << ", g=" << rgb.col();
- std::cout << ")= " << _histo(rgb);
+ std::cout << "histo(r=" << rg.row();
+ std::cout << ", g=" << rg.col();
+ std::cout << ")= " << _histo(rg);
std::cout << std::endl;
}
}
@@ -818,15 +821,15 @@ namespace mln
{
trace::entering("mln::clustering::kmean2d::print_group");
- mln_piter(t_group_img) rgb(_group.domain());
+ mln_piter(t_group_img) rg(_group.domain());
- for_all(rgb)
+ for_all(rg)
{
- if (0 < _histo(rgb))
+ if (0 < _histo(rg))
{
- std::cout << "group(r=" << rgb.row();
- std::cout << ", g=" << rgb.col();
- std::cout << ")= " << _group(rgb);
+ std::cout << "group(r=" << rg.row();
+ std::cout << ", g=" << rg.col();
+ std::cout << ")= " << _group(rg);
std::cout << std::endl;
}
}
@@ -844,16 +847,16 @@ namespace mln
for_all(l)
{
- mln_piter(t_distance_val) rgb(_distance[l.index_()].domain());
+ mln_piter(t_distance_val) rg(_distance[l.index_()].domain());
- for_all(rgb)
+ for_all(rg)
{
- if (0 < _histo(rgb))
+ if (0 < _histo(rg))
{
std::cout << "distance(l=" << l.index_();
- std::cout << ",r=" << rgb.row();
- std::cout << ", g=" << rgb.col();
- std::cout << ")= " << _distance[l.index_()](rgb);
+ std::cout << ",r=" << rg.row();
+ std::cout << ", g=" << rg.col();
+ std::cout << ")= " << _distance[l.index_()](rg);
std::cout << std::endl;
}
}
@@ -960,9 +963,9 @@ namespace mln
{
trace::entering("mln::clustering::kmean2d::update_group");
- mln_piter(t_group_img) rgb(_group.domain());
+ mln_piter(t_group_img) rg(_group.domain());
- for_all(rgb)
+ for_all(rg)
{
mln_eiter(t_distance_img) l(_distance);
t_result1d min = mln_max(t_result1d);
@@ -972,9 +975,9 @@ namespace mln
for_all(l)
{
- if (min > _distance[l.index_()](rgb))
+ if (min > _distance[l.index_()](rg))
{
- min = _distance[l.index_()](rgb);
+ min = _distance[l.index_()](rg);
label = l.index_();
}
@@ -984,7 +987,7 @@ namespace mln
//std::cout << "g = " << g << std::endl;
- _group(rgb) = label;
+ _group(rg) = label;
//std::cout << "group = " << _group(g) << std::endl;
//std::cout << "-----------" << std::endl;
}
@@ -998,8 +1001,6 @@ namespace mln
{
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
@@ -1021,14 +1022,14 @@ namespace mln
_mean[em.index_()] = literal::zero;
}
- mln_piter(t_group_img) rgb(_group.domain());
+ mln_piter(t_group_img) rg(_group.domain());
- for_all(rgb)
+ for_all(rg)
{
// 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);
+ _mean[_group(rg)][0] += rg.row() * _histo(rg);
+ _mean[_group(rg)][1] += rg.col() * _histo(rg);
+ _number(_group(rg)) += _histo(rg);
}
mln_eiter(t_mean_img) l(_mean);
@@ -1072,12 +1073,12 @@ namespace mln
{
_variance[l.index_()] = literal::zero;
- mln_piter(t_group_img) rgb(_group.domain());
+ mln_piter(t_group_img) rg(_group.domain());
- for_all(rgb)
+ for_all(rg)
{
- if (l.index_() == _group(rgb))
- _variance[l.index_()] += _distance[l.index_()](rgb);
+ if (l.index_() == _group(rg))
+ _variance[l.index_()] += _distance[l.index_()](rg);
}
_within_variance += _variance[l.index_()];
@@ -1334,7 +1335,7 @@ namespace mln
trace::exiting("mln::clustering::kmean2d::launch_n_times");
}
-#endif // ! MLN_INCLUDE_ONLY
+# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::clustering
diff --git a/scribo/sandbox/green/mln/clustering/kmean3d.hh
b/scribo/sandbox/green/mln/clustering/kmean3d.hh
index fb1a8df..c35d2a7 100644
--- a/scribo/sandbox/green/mln/clustering/kmean3d.hh
+++ b/scribo/sandbox/green/mln/clustering/kmean3d.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2008,2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2007,2008,2009,2010 EPITA LRDE
//
// This file is part of Olena.
//
@@ -24,51 +24,102 @@
// executable file might be covered by the GNU General Public License.
#ifndef MLN_CLUSTERING_KMEAN3D_HH
-#define MLN_CLUSTERING_KMEAN3D_HH
+# define MLN_CLUSTERING_KMEAN3D_HH
/// \file
///
-/// \brief Implements the optimized kmean algorithm.
+/// \brief Implements the optimized kmean algorithm in 3d.
///
/// This algorithm is optimized in the way it proceeds directly with
-/// the rgb values inspite of the pixel attribute. The
+/// the rgb value 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 adapted to
-/// image 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/histo3d_rgb.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/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>
+/// by a fix cost in the complexity. This version is very adapted to
+/// images with small quantification. But, in 3d, the execution
+/// becomes very slow. It's just normal because the quantification is
+/// n bits per axis. So the actual histogram may be bigger than the image.
+///
+/// Take care to the following point: The within variance is still a
+/// scalar value because we take the distance between two points and
+/// the result is a scalar from the geometrical point of view. An
+/// alternative implementation could study the variance/covariance
+/// matrix of each sub data clouds and works with the trace of the
+/// within variance matrix (as we do for the fisher criteria in N-d).
+///
+/// The following sample is a typical use of the new kmean implementation.
+///
+/// #include <iostream>
+/// #include <mln/clustering/kmean3d.hh>
+/// #include <mln/core/image/image2d.hh>
+/// #include <mln/data/transform.hh>
+/// #include <mln/fun/v2v/rgb8_to_rgbn.hh>
+/// #include <mln/img_path.hh>
+/// #include <mln/io/ppm/load.hh>
+/// #include <mln/value/rgb.hh>
+/// #include <mln/value/rgb8.hh>
+///
+/// int main()
+/// {
+/// typedef mln::clustering::kmean3d<double,5> t_kmean;
+/// 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;
+/// typedef mln::fun::v2v::rgb8_to_rgbn<5> t_rgb8_to_rgb5;
+///
+/// t_image2d_rgb8 img_rgb8;
+/// t_image2d_rgb5 img_rgb5;
+///
+/// mln::io::ppm::load(img_rgb8, OLENA_IMG_PATH"/house.ppm");
+///
+/// img_rgb5=mln::data::transform(img_rgb8, t_rgb8_to_rgb5());
+///
+/// t_kmean kmean(img_rgb5, 3);
+///
+/// kmean.launch_n_times();
+///
+/// return 0;
+/// }
+
+# include <limits.h>
+# include <iostream>
+
+# include <mln/accu/stat/histo3d_rgb.hh>
+
+# include <mln/algebra/vec.hh>
+
+# include <mln/math/min.hh>
+# include <mln/math/sqr.hh>
+# include <mln/norm/l2.hh>
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/contract.hh>
+# include <mln/core/image/image2d.hh>
+# include <mln/core/macros.hh>
+
+# include <mln/data/compute.hh>
+# include <mln/data/fill.hh>
+# include <mln/debug/println.hh>
+
+# include <mln/labeling/colorize.hh>
+# include <mln/labeling/mean_values.hh>
+
+# include <mln/literal/one.hh>
+# include <mln/literal/zero.hh>
+
+# include <mln/io/ppm/save.hh>
+# include <mln/io/pgm/save.hh>
+
+# include <mln/trace/entering.hh>
+# include <mln/trace/exiting.hh>
+
+# include <mln/trait/value_.hh>
+
+# include <mln/util/array.hh>
+
+# include <mln/value/int_u.hh>
+# include <mln/value/rgb8.hh>
+
namespace mln
{
@@ -98,7 +149,6 @@ namespace mln
/// 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::rgb<n> t_value;
@@ -108,7 +158,7 @@ namespace mln
typedef T t_result1d;
typedef algebra::vec<3,T> t_result3d;
- /// FIXME t_point n'est pas forcément une image 2d, bien au contraire.
+ /// \fixme t_point is not an image2d, it may be something else ...
typedef image2d<t_value> t_point_img;
typedef image3d<unsigned> t_histo_img;
typedef util::array<t_result1d> t_number_img;
@@ -128,35 +178,26 @@ namespace mln
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
+ /// \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).
-
kmean3d(const t_point_img& point,
const unsigned k_center,
const unsigned watch_dog = 10,
const unsigned n_times = 10);
- //------------------------------------------------------------------------
- // Accessors
- //------------------------------------------------------------------------
-
- /// Mutator and accessors.
+ /// Mutators 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);
@@ -184,13 +225,13 @@ namespace mln
// Normal outputs
t_mean_img& to_result();
-
/// \}
- //------------------------------------------------------------------------
- // Printing temporary results
- //------------------------------------------------------------------------
+ /// Show temporary results.
+ /// \{
+ /// \brief Formating temporary outputs for debugging.
+ ///
void print_mean();
void print_number();
void print_variance();
@@ -198,32 +239,19 @@ namespace mln
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.
+ /// \brief Initialize centers by random position.
///
- /// There is two way to proceed the initialization. First of all, we
- /// divide the rgb space 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.
-
+ /// Assign a random position in the rgb space to each center.
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.
@@ -232,36 +260,27 @@ namespace mln
/// 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).
-
+ /// There are two ways to launch the kmean process. The first
+ /// one allows to run it one time until convergence. As the
+ /// process is a descent, it depends on the initial center
+ /// location. 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.
/// \{
@@ -271,32 +290,22 @@ namespace mln
/// 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
+ /// Checking the validity of the results.
/// \{
- /// \brief These methods help to interpret results.
+ /// \brief These methods help us to determine the validity of the 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.
-
+ /// 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 color
+ /// associate to it) or a failure in the convergence.
void build_label_dbg();
void build_mean_dbg();
void build_all_dbg();
void update_cnv();
void finalize_cnv();
-
/// \}
@@ -313,13 +322,12 @@ namespace mln
/// 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.
@@ -337,14 +345,12 @@ namespace mln
/// 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.
@@ -354,10 +360,10 @@ namespace mln
/// 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.
/// \{
@@ -365,12 +371,11 @@ namespace mln
///
/// 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.
@@ -381,11 +386,9 @@ namespace mln
/// 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_mean_img _mean; // k x 3
t_variance_img _variance; // k x 1 within group
-
/// \}
/// rgb image description.
@@ -396,12 +399,11 @@ namespace mln
/// 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 rgb space of a center give us the within variance.
-
t_group_img _group; // g x 3 because dim(t_value) = 3
t_distance_img _distance; // label x rgb space
-
/// \}
+
/// Debugging, calibrating and testing results.
/// \{
/// \brief Some exports information to control the results.
@@ -412,14 +414,12 @@ namespace mln
/// 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.
+ /// Variance and center evolutions.
/// \{
/// \brief Trace the variance and the center evolution.
///
@@ -428,10 +428,8 @@ namespace mln
/// 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;
-
/// \}
};
@@ -448,7 +446,7 @@ namespace mln
const unsigned watch_dog,
const unsigned n_times)
{
- trace::entering("mln::clustering::kmean3d::kmean3d");
+ trace::entering("mln::clustering::kmean3d::cstor");
mln_precondition(point.is_valid());
_k_center = k_center;
@@ -520,7 +518,7 @@ namespace mln
_mean_cnv.append(mean_set);
}
- trace::exiting("mln::clustering::kmean3d::kmean3d");
+ trace::exiting("mln::clustering::kmean3d::cstor");
}
//--------------------------------------------------------------------------
@@ -1338,7 +1336,7 @@ namespace mln
trace::exiting("mln::clustering::kmean3d::launch_n_times");
}
-#endif // ! MLN_INCLUDE_ONLY
+# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::clustering
diff --git a/scribo/sandbox/green/mln/clustering/kmean_rgb.hh
b/scribo/sandbox/green/mln/clustering/kmean_rgb.hh
index 253745b..544066b 100644
--- a/scribo/sandbox/green/mln/clustering/kmean_rgb.hh
+++ b/scribo/sandbox/green/mln/clustering/kmean_rgb.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2008,2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2007,2008,2009,2010 EPITA LRDE
//
// This file is part of Olena.
//
@@ -28,16 +28,68 @@
/// \file
///
-/// \brief Implements the optimized kmean algorithm.
+/// \brief Implements the optimized kmean algorithm in the 3d-RGB space.
///
/// This algorithm is optimized in the way it proceeds directly with
-/// the rgb values inspite of the pixel attribute. The
+/// the rgb value 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 adapted to
-/// image with small quantification.
-
-/// APLATISSEMENT DES KMEAN3D
+/// by a fix cost in the complexity. This version is very adapted to
+/// images with small quantification. But, in 3d, the execution
+/// becomes very slow. It's just normal because the quantification is
+/// n bits per axis. So the actual histogram may be bigger than the image.
+///
+/// Take care to the following point: The within variance is still a
+/// scalar value because we take the distance between two points and
+/// the result is a scalar from the geometrical point of view. An
+/// alternative implementation could study the variance/covariance
+/// matrix of each sub data clouds and works with the trace of the
+/// within variance matrix (as we do for the fisher criteria in N-d).
+///
+/// The following sample is a typical use of the functional (versus
+/// object) kmean implementation.
+///
+/// #include <iostream>
+/// #include <mln/clustering/kmean_rgb.hh>
+/// #include <mln/core/image/image2d.hh>
+/// #include <mln/data/transform.hh>
+/// #include <mln/fun/v2v/rgb8_to_rgbn.hh>
+/// #include <mln/img_path.hh>
+/// #include <mln/io/ppm/load.hh>
+/// #include <mln/value/label_8.hh>
+/// #include <mln/value/rgb.hh>
+/// #include <mln/value/rgb8.hh>
+///
+/// int main()
+/// {
+/// typedef mln::value::label_8 t_lbl8;
+/// 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;
+/// typedef mln::image2d<t_lbl8> t_image2d_lbl8;
+/// typedef mln::fun::v2v::rgb8_to_rgbn<5> t_rgb8_to_rgb5;
+///
+/// t_image2d_rgb8 img_rgb8;
+/// t_image2d_rgb5 img_rgb5;
+/// t_image2d_lbl8 img_lbl8;
+///
+/// mln::io::ppm::load(img_rgb8, OLENA_IMG_PATH"/house.ppm");
+///
+/// img_rgb5 = mln::data::transform(img_rgb8, t_rgb8_to_rgb5());
+/// img_lbl8 = mln::clustering::kmean_rgb<double,5>(img_rgb5, 3);
+///
+/// return 0;
+/// }
+///
+/// \fixme The execution shows a bug in printing outputs and it seems severe.
+///
+/// The last execution with the following set of parameters
+/// {house.ppm,3,10,10} shows that if the binary starts correctly, it
+/// ends before returning the label image and with disturbing outputs.
+/// Dumping the outputs in a file reveals that the number of
+/// trace::entering differs from the number of trace::exiting. May the
+/// program exit from a loop without ending a trace ???
# include <limits.h>
# include <iostream>
@@ -86,7 +138,7 @@
//--------------------------------------------------------------------------
-// CODE APLATI
+// FUNCTIONAL CODE
//--------------------------------------------------------------------------
@@ -95,7 +147,24 @@ namespace mln
namespace clustering
{
-
+ /// \brief Implements the functional kmean algorithm.
+ ///
+ /// This functional version of the kmean is very specific. All the
+ /// code is view as a one-block function. This code is provided as
+ /// is. I (YJ) don't know where i stopped this version. It may not
+ /// work. Debugging tools are not yet provided. This code is just
+ /// the functional transcription of the kmean3d version. The code
+ /// has the very experimental status.
+ ///
+ /// T is the type used for computations (float or double).
+ /// n is the quantification for the rgb image.
+ ///
+ /// \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).
+ ///
+ /// \return an image which represents the pixel classification.
template <typename T, unsigned n, typename I>
inline
image2d<value::label_8>
diff --git a/scribo/sandbox/green/mln/fun/v2v/rg_to_rgb.hh
b/scribo/sandbox/green/mln/fun/v2v/rg_to_rgb.hh
index ca7ba51..e89edad 100644
--- a/scribo/sandbox/green/mln/fun/v2v/rg_to_rgb.hh
+++ b/scribo/sandbox/green/mln/fun/v2v/rg_to_rgb.hh
@@ -1,6 +1,4 @@
-// Copyright (C) 2007 EPITA Research and Development Laboratory (LRDE)
-// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2007,2008,2009,2010 EPITA LRDE
//
// This file is part of Olena.
//
@@ -34,7 +32,51 @@
/// \file
///
-/// \brief Convert rg value to rgb
+/// \brief Convert a rg value to a rgb value.
+///
+/// This source implements the conversion between rg space and rgb space.
+///
+/// The following sample is a typical use of the rg/rgb conversion function.
+///
+/// #include <iostream>
+/// #include <mln/clustering/kmean2d.hh>
+/// #include <mln/core/image/image2d.hh>
+/// #include <mln/data/transform.hh>
+/// #include <mln/fun/v2v/rgb_to_rg.hh>
+/// #include <mln/fun/v2v/rg_to_rgb.hh>
+/// #include <mln/img_path.hh>
+/// #include <mln/io/ppm/load.hh>
+/// #include <mln/value/rg.hh>
+/// #include <mln/value/rgb8.hh>
+///
+/// int main()
+/// {
+/// typedef mln::value::rg<8> t_rg8;
+/// typedef mln::value::rgb8 t_rgb8;
+/// typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+/// typedef mln::image2d<t_rg8> t_image2d_rg8;
+/// typedef mln::fun::v2v::rgb_to_rg<8> t_rgb_to_rg;
+/// typedef mln::fun::v2v::rg_to_rgb<8> t_rg_to_rgb;
+///
+/// t_image2d_rgb8 img_rgb8;
+/// t_image2d_rgb8 point_img_rgb8;
+/// t_image2d_rg8 img_rg8;
+///
+/// mln::io::ppm::load(img_rgb8, OLENA_IMG_PATH"/house.ppm");
+///
+/// img_rg8 = mln::data::transform(img_rgb8, t_rgb_to_rg());
+///
+/// mln::clustering::kmean2d<double, 8> kmean(img_rg8, 3);
+///
+/// kmean.launch_n_times();
+///
+/// mln::clustering::kmean2d<double,8>::t_point_img point_img =
+/// kmean.get_point();
+///
+/// point_img_rgb8 = mln::data::transform(point_img, t_rg_to_rgb());
+///
+/// return 0;
+/// }
namespace mln
{
@@ -47,14 +89,21 @@ namespace mln
/// \brief Convert rg value to rgb.
///
+ /// Param n defines the quantification used for rgb space and rg space.
+ ///
/// \ingroup modfunv2v
-
template <unsigned n>
struct rg_to_rgb : Function_v2v< rg_to_rgb<n> >
{
typedef value::rg<n> argument;
typedef value::rgb<n> result;
+ /// \brief Convert rg value to rgb value.
+ ///
+ /// \param[in] v the rg value to convert.
+ ///
+ /// Conversion is done by calling the rgb constructor and fill
+ /// the empty attirbute by 127.
result operator()(const argument& v) const
{
return value::rgb<n>(v.red(), v.green(), 127);
diff --git a/scribo/sandbox/green/tests/clustering/k_mean/Makefile.am
b/scribo/sandbox/green/tests/clustering/k_mean/Makefile.am
index 5f00678..77f9015 100644
--- a/scribo/sandbox/green/tests/clustering/k_mean/Makefile.am
+++ b/scribo/sandbox/green/tests/clustering/k_mean/Makefile.am
@@ -6,8 +6,13 @@
# TOOLS #
#########
-INCLUDES= -I$(HOME)/svn/oln/trunk/milena/sandbox/green
+#LOADLIBES= -lboost_filesystem
+INCLUDES1= -I$(HOME)/git/olena/scribo/sandbox/green
+INCLUDES2= -I$(HOME)/git/olena/milena
+INCLUDES= $(INCLUDES1) $(INCLUDES2)
CXXFLAGS= -ggdb -O0 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O1 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
+#CXXFLAGS= -DNDEBUG -O3 -Wall -W -pedantic -ansi -pipe $(INCLUDES)
ECHO= echo
RM= rm
MKDIR= mkdir -p
@@ -20,10 +25,10 @@ BUILD__PATTERN= green/build/tests
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)
+BUILD__DIR= $(PWD)/
else
# Case where make is done from source directory.
-SOURCE_DIR= $(PWD)
+SOURCE_DIR= $(PWD)/
BUILD__DIR= $(subst $(SOURCE_PATTERN),$(BUILD__PATTERN),$(PWD))
endif
@@ -89,7 +94,7 @@ $(OBJ_F_PATH):$(SRC_F_PATH)
#########
# Force every time the deletion
-clean: print clean_target clean_obj clean_dst clean_old #clean_make
+clean: clean_target clean_obj clean_dst clean_old #clean_make
clean_target:
diff --git a/scribo/sandbox/green/tests/clustering/k_mean/k_mean.cc
b/scribo/sandbox/green/tests/clustering/k_mean/k_mean.cc
index 27751fd..a839ece 100644
--- a/scribo/sandbox/green/tests/clustering/k_mean/k_mean.cc
+++ b/scribo/sandbox/green/tests/clustering/k_mean/k_mean.cc
@@ -1,34 +1,68 @@
-// UNARY TESTS ON K_MEAN
-
-#include <mln/clustering/k_mean.hh>
+// Copyright (C) 2007, 2008, 2009, 2010 EPITA 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.
+
+/// \file
+///
+/// \brief This source manages unitary testing on the kmean implementation.
+///
+/// Tests are performed from 2 bits up to 8 bits quantification. The goal
+/// is to go through each programmatic flow to verify the conformity of the
+/// code. It sounds like a theoritic model of unitary testing for milena.
+/// The last test enables statistic computations on that component.
#include <iostream>
-#include <mln/pw/value.hh>
-
-#include <mln/value/int_u8.hh>
-#include <mln/value/rgb8.hh>
-
#include <mln/literal/colors.hh>
#include <mln/algebra/vec.hh>
#include <mln/algebra/mat.hh>
+#include <mln/clustering/k_mean.hh>
+
#include <mln/core/macros.hh>
#include <mln/core/contract.hh>
#include <mln/core/image/image2d.hh>
#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/img_path.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/data/transform.hh>
-
#include <mln/trait/value/print.hh>
#include <mln/trait/image/print.hh>
+#include <mln/pw/value.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/value/rgb8.hh>
+
#define SIZE_IMAGE 512
#define SIZE_SAMPLE1 (512*512)
#define SIZE_SAMPLE2 4
@@ -44,20 +78,18 @@
#define MAT_GROUP2 mln::algebra::mat<SIZE_SAMPLE2, NB_CENTER, TYPE_POINT>
#define VEC_VAR mln::algebra::vec<NB_CENTER, TYPE_POINT>
-
-void test_instantiation()
-{
- mln::clustering::k_mean<SIZE_SAMPLE2,NB_CENTER, DIM_POINT, TYPE_POINT> kmean;
-
- // test the compilation
-
- std::cout << "test instantiation : ok" << std::endl;
-}
+/// Tools.
+/// \{
+/// \brief Define some tools which are used in unitary testing.
+///
+/// This kind of tools help to fill an image with only 4 tons or
+/// computing a distance between two colors. Just keep an eye, nothing
+/// really difficult in this code.
struct rgb8_to_4colors : mln::Function_v2v<rgb8_to_4colors>
{
typedef mln::value::rgb8 result;
-
+
mln::value::rgb8 operator()(const mln::value::rgb8& color) const
{
mln::value::rgb8 result;
@@ -78,11 +110,12 @@ struct rgb8_to_4colors : mln::Function_v2v<rgb8_to_4colors>
void print_color(const mln::value::rgb8& color)
{
- std::cout << "{r=" << color.red() << ", ";
+ std::cout << "{r=" << color.red() << ", ";
std::cout << "g=" << color.green() << ", ";
std::cout << "b=" << color.blue() << "}"
<< std::endl;
}
+
void fill_image_with_4colors(mln::image2d<mln::value::rgb8>& img)
{
const mln::value::rgb8 lime = mln::literal::lime;
@@ -98,6 +131,140 @@ void
fill_image_with_4colors(mln::image2d<mln::value::rgb8>& img)
//print_color(purple);
}
+
+double dist(mln::value::rgb8 color1, mln::value::rgb8 color2)
+{
+ double red = color1.red() - color2.red();
+ double green = color1.green() - color2.green();
+ double blue = color1.blue() - color2.blue();
+ double result= red * red + green * green + blue * blue;
+
+ return result;
+}
+
+/// \}
+
+
+/// External mutators.
+/// \{
+/// \brief Replace the kmean data structure values.
+///
+/// This is a hack that provides low level routines to access key data
+/// structure like point, center, distance and group.
+
+void set_point(MAT_POINT2& point,
+ const unsigned index,
+ const mln::value::rgb8& color)
+{
+ point(index,0) = color.red();
+ point(index,1) = color.green();
+ point(index,2) = color.blue();
+}
+
+void set_center(MAT_CENTER& center,
+ const unsigned index,
+ const mln::value::rgb8& color)
+{
+ center(index,0) = color.red();
+ center(index,1) = color.green();
+ center(index,2) = color.blue();
+}
+
+void set_distance(MAT_DISTANCE2& distance,
+ const unsigned index,
+ const double d1,
+ const double d2)
+{
+ distance(index,0) = d1;
+ distance(index,1) = d2;
+}
+
+void set_group(MAT_GROUP2& group,
+ const unsigned index,
+ const unsigned min)
+{
+ group(index, min) = 1.0;
+ group(index, 1-min) = 0.0;
+}
+
+/// \}
+
+/// Fake states.
+/// \{
+/// \brief Help to build from scratch temporary states for the kmean algorithm.
+///
+/// This hack allow us to build temporary results used in the previous step to
+/// make us very the behaviour of the current step. There is a fake state for
+/// every key data structure (point, group, center and distance).
+
+void fake_init_point(MAT_POINT2& point,
+ const mln::value::rgb8& point1,
+ const mln::value::rgb8& point2,
+ const mln::value::rgb8& point3,
+ const mln::value::rgb8& point4)
+{
+ set_point(point, 0, point1);
+ set_point(point, 1, point2);
+ set_point(point, 2, point3);
+ set_point(point, 3, point4);
+}
+
+
+void fake_update_group(MAT_GROUP2& group,
+ const unsigned& point1_min,
+ const unsigned& point2_min,
+ const unsigned& point3_min,
+ const unsigned& point4_min)
+{
+ set_group(group, 0, point1_min);
+ set_group(group, 1, point2_min);
+ set_group(group, 2, point3_min);
+ set_group(group, 3, point4_min);
+}
+
+
+void fake_init_center(MAT_CENTER& center,
+ const mln::value::rgb8 center1,
+ const mln::value::rgb8 center2)
+{
+
+ set_center(center, 0, center1);
+ set_center(center, 1, center2);
+}
+
+
+
+
+void fake_update_distance(MAT_DISTANCE2& distance,
+ const mln::value::rgb8& point1,
+ const mln::value::rgb8& point2,
+ const mln::value::rgb8& point3,
+ const mln::value::rgb8& point4,
+ const mln::value::rgb8& center1,
+ const mln::value::rgb8& center2)
+{
+ set_distance(distance, 0, dist(point1, center1), dist(point1, center2));
+ set_distance(distance, 1, dist(point2, center1), dist(point2, center2));
+ set_distance(distance, 2, dist(point3, center1), dist(point3, center2));
+ set_distance(distance, 3, dist(point4, center1), dist(point4, center2));
+
+ /*
+ for (int i = 0; i < SIZE_SAMPLE2; ++i)
+ for (int j = 0; j < NB_CENTER; ++j)
+ std::cout << "d(" << i << "," << j
<< ") = " << distance(i,j) <<std::endl;
+ */
+}
+
+/// \}
+
+/// Equivalence.
+/// \{
+/// \brief Test equivalence between point and image, center and color.
+///
+/// Two kinds of equivalence are defined here. The first one tests the
+/// equality between the data cloud and the initial image, while the
+/// second one tests the equality between a center and a color.
+
bool is_equivalent(const mln::image2d<mln::value::rgb8>& img,
const MAT_POINT1& point)
{
@@ -118,11 +285,11 @@ bool is_equivalent(const mln::image2d<mln::value::rgb8>&
img,
if (!test)
{
std::cout << pi;
- std::cout << "{r=" << img(pi).red() << ",
";
+ std::cout << "{r=" << img(pi).red() << ",
";
std::cout << "g=" << img(pi).green() << ",
";
std::cout << "b=" << img(pi).blue() <<
"}";
std::cout << index;
- std::cout << "[r=" << point(index,0) << ",
";
+ std::cout << "[r=" << point(index,0) << ",
";
std::cout << "g=" << point(index,1) << ",
";
std::cout << "b=" << point(index,2) << "]"
<< std::endl;
@@ -135,6 +302,44 @@ bool is_equivalent(const mln::image2d<mln::value::rgb8>&
img,
return result;
}
+bool is_equal(const mln::value::rgb8& ref,
+ const MAT_CENTER& center,
+ const unsigned i)
+{
+ bool result = true;
+
+ result = result && (center(i, 0) - ref.red() < 1.0);
+ result = result && (center(i, 1) - ref.green() < 1.0);
+ result = result && (center(i, 2) - ref.blue() < 1.0);
+
+ return result;
+}
+
+/// \}
+
+
+/// kmean unitary testing
+/// \{
+/// \brief This part of the code manages the unitary testing.
+///
+/// Many tests are performed and new kind of unitary testing
+/// appears. In fact, we must simulate the previous steps of the line
+/// currently testing and so making some fake steps. Bad and deep
+/// hacking in data structure are required. We test the instantiation
+/// of the kmean object, its initialization (points and centers), its
+/// core routines (update_center, update_group, update_distance,
+/// update_variance) and the final loop.
+
+void test_instantiation()
+{
+ mln::clustering::k_mean<SIZE_SAMPLE2,NB_CENTER, DIM_POINT, TYPE_POINT> kmean;
+
+ // test the compilation
+
+ std::cout << "test instantiation : ok" << std::endl;
+}
+
+
void test_init_point()
{
typedef mln::value::rgb8 rgb8;
@@ -147,45 +352,12 @@ void test_init_point()
fill_image_with_4colors(img_ref);
kmean.init_point(img_ref);
-
+
mln_assertion(true == is_equivalent(img_ref, kmean.get_point()));
std::cout << "Test init point : ok" << std::endl;
}
-void set_point(MAT_POINT2& point,
- const unsigned index,
- const mln::value::rgb8& color)
-{
- point(index,0) = color.red();
- point(index,1) = color.green();
- point(index,2) = color.blue();
-}
-
-void fake_init_point(MAT_POINT2& point,
- const mln::value::rgb8& point1,
- const mln::value::rgb8& point2,
- const mln::value::rgb8& point3,
- const mln::value::rgb8& point4)
-{
- set_point(point, 0, point1);
- set_point(point, 1, point2);
- set_point(point, 2, point3);
- set_point(point, 3, point4);
-}
-
-bool is_equal(const mln::value::rgb8& ref,
- const MAT_CENTER& center,
- const unsigned i)
-{
- bool result = true;
-
- result = result && (center(i, 0) - ref.red() < 1.0);
- result = result && (center(i, 1) - ref.green() < 1.0);
- result = result && (center(i, 2) - ref.blue() < 1.0);
-
- return result;
-}
void test_init_center()
{
@@ -195,10 +367,10 @@ void test_init_center()
const mln::value::rgb8 brown = mln::literal::brown;
const mln::value::rgb8 teal = mln::literal::teal;
const mln::value::rgb8 purple = mln::literal::purple;
-
+
fake_init_point(kmean.get_point(), lime, brown, teal, purple);
kmean.init_center();
-
+
mln_assertion(is_equal(lime, kmean.get_center(), 0) ||
is_equal(brown, kmean.get_center(), 0) ||
is_equal(teal, kmean.get_center(), 0) ||
@@ -212,34 +384,6 @@ void test_init_center()
std::cout << "Test init center : ok" << std::endl;
}
-void set_center(MAT_CENTER& center,
- const unsigned index,
- const mln::value::rgb8& color)
-{
- center(index,0) = color.red();
- center(index,1) = color.green();
- center(index,2) = color.blue();
-}
-
-void fake_init_center(MAT_CENTER& center,
- const mln::value::rgb8 center1,
- const mln::value::rgb8 center2)
-{
-
- set_center(center, 0, center1);
- set_center(center, 1, center2);
-}
-
-
-double dist(mln::value::rgb8 color1, mln::value::rgb8 color2)
-{
- double red = color1.red() - color2.red();
- double green = color1.green() - color2.green();
- double blue = color1.blue() - color2.blue();
- double result= red * red + green * green + blue * blue;
-
- return result;
-}
void test_update_distance()
{
@@ -269,34 +413,6 @@ void test_update_distance()
std::cout << "Test update distance : ok" << std::endl;
}
-void set_distance(MAT_DISTANCE2& distance,
- const unsigned index,
- const double d1,
- const double d2)
-{
- distance(index,0) = d1;
- distance(index,1) = d2;
-}
-
-void fake_update_distance(MAT_DISTANCE2& distance,
- const mln::value::rgb8& point1,
- const mln::value::rgb8& point2,
- const mln::value::rgb8& point3,
- const mln::value::rgb8& point4,
- const mln::value::rgb8& center1,
- const mln::value::rgb8& center2)
-{
- set_distance(distance, 0, dist(point1, center1), dist(point1, center2));
- set_distance(distance, 1, dist(point2, center1), dist(point2, center2));
- set_distance(distance, 2, dist(point3, center1), dist(point3, center2));
- set_distance(distance, 3, dist(point4, center1), dist(point4, center2));
-
- /*
- for (int i = 0; i < SIZE_SAMPLE2; ++i)
- for (int j = 0; j < NB_CENTER; ++j)
- std::cout << "d(" << i << "," << j
<< ") = " << distance(i,j) <<std::endl;
- */
-}
void test_update_group()
{
@@ -331,26 +447,6 @@ void test_update_group()
std::cout << "Test update group : ok" << std::endl;
}
-void set_group(MAT_GROUP2& group,
- const unsigned index,
- const unsigned min)
-{
- group(index, min) = 1.0;
- group(index, 1-min) = 0.0;
-}
-
-
-void fake_update_group(MAT_GROUP2& group,
- const unsigned& point1_min,
- const unsigned& point2_min,
- const unsigned& point3_min,
- const unsigned& point4_min)
-{
- set_group(group, 0, point1_min);
- set_group(group, 1, point2_min);
- set_group(group, 2, point3_min);
- set_group(group, 3, point4_min);
-}
void test_update_center()
{
@@ -374,13 +470,14 @@ void test_update_center()
fake_update_distance(kmean.get_distance(), lime, brown, teal, purple, c1, c2);
fake_update_group(kmean.get_group(), pt1_min, pt2_min, pt3_min, pt4_min);
kmean.update_center();
-
+
mln_assertion(is_equal(mean_c1, kmean.get_center(), 0));
mln_assertion(is_equal(mean_c2, kmean.get_center(), 1));
std::cout << "Test update center : ok" << std::endl;
}
+
void test_update_variance()
{
mln::clustering::k_mean<SIZE_SAMPLE2, NB_CENTER, DIM_POINT, TYPE_POINT> kmean;
@@ -405,13 +502,15 @@ void test_update_variance()
fake_update_distance(kmean.get_distance(), lime, brown, teal, purple, c1, c2);
fake_update_group(kmean.get_group(), pt1_min, pt2_min, pt3_min, pt4_min);
kmean.update_variance();
-
+
mln_assertion(v1 == var[0]);
mln_assertion(v2 == var[1]);
std::cout << "Test update variance : ok" << std::endl;
}
+
+/// \fixme this procedure tests actually nothing.
void test_loop()
{
typedef mln::value::rgb8 rgb8;
@@ -426,24 +525,22 @@ void test_loop()
kmean.init_point(img_ref);
kmean.loop(img_ref);
-
- // std::cout << "Test update variance: ok" << std::endl;
+ // \FIXME: Which assertion must we define ?
+ // std::cout << "Test loop : ok" << std::endl;
}
+/// \}
int main()
{
- //test_instantiation();
- //test_init_point();
- //test_init_center();
- //test_update_distance();
- //test_update_group();
- //test_update_center();
- //test_update_variance();
-
- // mln::trace::quiet = false;
-
+ test_instantiation();
+ test_init_point();
+ test_init_center();
+ test_update_distance();
+ test_update_group();
+ test_update_center();
+ test_update_variance();
test_loop();
return 0;
diff --git a/scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
b/scribo/sandbox/green/use/clustering/k_mean/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
copy to scribo/sandbox/green/use/clustering/k_mean/Makefile.am
diff --git a/scribo/sandbox/green/use/clustering/k_mean/k_mean.cc
b/scribo/sandbox/green/use/clustering/k_mean/k_mean.cc
new file mode 100644
index 0000000..9b00037
--- /dev/null
+++ b/scribo/sandbox/green/use/clustering/k_mean/k_mean.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2007, 2008, 2009, 2010 EPITA 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.
+
+/// \file
+///
+/// \brief Minimal code to use the first implementation of the kmean algorithm.
+///
+
+#include <mln/clustering/k_mean.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/img_path.hh>
+#include <mln/io/ppm/load.hh>
+#include <mln/trait/value_.hh>
+#include <mln/value/rgb8.hh>
+
+#define NB_CENTER 9
+#define NB_POINT (128*128)
+#define POINT_SIZE mln_dim(mln::value::rgb8)
+#define POINT_TYPE double
+
+int main()
+{
+ typedef mln::value::rgb8 t_rgb8;
+ mln::image2d<t_rgb8> img_rgb8;
+
+ mln::io::ppm::load(img_rgb8, OLENA_IMG_PATH"/house.ppm");
+ mln::clustering::k_mean<NB_POINT, NB_CENTER, POINT_SIZE, POINT_TYPE> kmean;
+
+ kmean.init_point(img_rgb8);
+ kmean.loop(img_rgb8);
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
b/scribo/sandbox/green/use/clustering/kmean1d/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
copy to scribo/sandbox/green/use/clustering/kmean1d/Makefile.am
diff --git a/scribo/sandbox/green/use/clustering/kmean1d/kmean1d.cc
b/scribo/sandbox/green/use/clustering/kmean1d/kmean1d.cc
new file mode 100644
index 0000000..82b13c9
--- /dev/null
+++ b/scribo/sandbox/green/use/clustering/kmean1d/kmean1d.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2007, 2008, 2009, 2010 EPITA 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.
+
+/// \file
+///
+/// \brief Minimal code to use the second implementation of the kmean algorithm.
+///
+
+#include <iostream>
+#include <mln/clustering/kmean1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/img_path.hh>
+#include <mln/io/pgm/load.hh>
+#include <mln/value/int_u8.hh>
+
+int main()
+{
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ t_image2d_int_u8 img_int_u8;
+
+ mln::io::pgm::load(img_int_u8, OLENA_IMG_PATH"/house.pgm");
+ mln::clustering::kmean1d<double, 8> kmean(img_int_u8, 3);
+
+ kmean.launch_n_times();
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
b/scribo/sandbox/green/use/clustering/kmean2d/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
copy to scribo/sandbox/green/use/clustering/kmean2d/Makefile.am
diff --git a/scribo/sandbox/green/use/clustering/kmean2d/kmean2d.cc
b/scribo/sandbox/green/use/clustering/kmean2d/kmean2d.cc
new file mode 100644
index 0000000..d6bf05b
--- /dev/null
+++ b/scribo/sandbox/green/use/clustering/kmean2d/kmean2d.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2007, 2008, 2009, 2010 EPITA 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.
+
+/// \file
+///
+/// \brief Minimal code to use the optimized version of the kmean2d algorithm.
+///
+
+#include <iostream>
+#include <mln/clustering/kmean2d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/data/transform.hh>
+#include <mln/fun/v2v/rgb_to_rg.hh>
+#include <mln/img_path.hh>
+#include <mln/io/ppm/load.hh>
+#include <mln/value/rg.hh>
+#include <mln/value/rgb8.hh>
+
+int main()
+{
+ typedef mln::value::rg<8> t_rg8;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_rg8> t_image2d_rg8;
+ typedef mln::fun::v2v::rgb_to_rg<8> t_rgb_to_rg;
+
+ t_image2d_rgb8 img_rgb8;
+ t_image2d_rg8 img_rg8;
+
+ mln::io::ppm::load(img_rgb8, OLENA_IMG_PATH"/house.ppm");
+
+ img_rg8 = mln::data::transform(img_rgb8, t_rgb_to_rg());
+
+ mln::clustering::kmean2d<double, 8> kmean(img_rg8, 3);
+
+ kmean.launch_n_times();
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
b/scribo/sandbox/green/use/clustering/kmean3d/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
copy to scribo/sandbox/green/use/clustering/kmean3d/Makefile.am
diff --git a/scribo/sandbox/green/use/clustering/kmean3d/kmean3d.cc
b/scribo/sandbox/green/use/clustering/kmean3d/kmean3d.cc
new file mode 100644
index 0000000..c57d48a
--- /dev/null
+++ b/scribo/sandbox/green/use/clustering/kmean3d/kmean3d.cc
@@ -0,0 +1,63 @@
+// Copyright (C) 2007, 2008, 2009, 2010 EPITA 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.
+
+/// \file
+///
+/// \brief Minimal code to use the optimized version of the kmean3d algorithm.
+///
+
+#include <iostream>
+#include <mln/clustering/kmean3d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/data/transform.hh>
+#include <mln/fun/v2v/rgb8_to_rgbn.hh>
+#include <mln/img_path.hh>
+#include <mln/io/ppm/load.hh>
+#include <mln/value/rgb.hh>
+#include <mln/value/rgb8.hh>
+
+
+int main()
+{
+ typedef mln::clustering::kmean3d<double,5> t_kmean;
+ 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;
+ typedef mln::fun::v2v::rgb8_to_rgbn<5> t_rgb8_to_rgb5;
+
+ t_image2d_rgb8 img_rgb8;
+ t_image2d_rgb5 img_rgb5;
+
+ mln::io::ppm::load(img_rgb8, OLENA_IMG_PATH"/house.ppm");
+
+ img_rgb5=mln::data::transform(img_rgb8, t_rgb8_to_rgb5());
+
+ t_kmean kmean(img_rgb5, 3);
+
+ kmean.launch_n_times();
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
b/scribo/sandbox/green/use/clustering/kmean_rgb/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
copy to scribo/sandbox/green/use/clustering/kmean_rgb/Makefile.am
diff --git a/scribo/sandbox/green/use/clustering/kmean_rgb/kmean_rgb.cc
b/scribo/sandbox/green/use/clustering/kmean_rgb/kmean_rgb.cc
new file mode 100644
index 0000000..3bf2241
--- /dev/null
+++ b/scribo/sandbox/green/use/clustering/kmean_rgb/kmean_rgb.cc
@@ -0,0 +1,63 @@
+// Copyright (C) 2007, 2008, 2009, 2010 EPITA 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.
+
+/// \file
+///
+/// \brief Minimal code to use the the functional (versus object) kmean code.
+///
+
+#include <iostream>
+#include <mln/clustering/kmean_rgb.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/data/transform.hh>
+#include <mln/fun/v2v/rgb8_to_rgbn.hh>
+#include <mln/img_path.hh>
+#include <mln/io/ppm/load.hh>
+#include <mln/value/label_8.hh>
+#include <mln/value/rgb.hh>
+#include <mln/value/rgb8.hh>
+
+
+int main()
+{
+ typedef mln::value::label_8 t_lbl8;
+ 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;
+ typedef mln::image2d<t_lbl8> t_image2d_lbl8;
+ typedef mln::fun::v2v::rgb8_to_rgbn<5> t_rgb8_to_rgb5;
+
+ t_image2d_rgb8 img_rgb8;
+ t_image2d_rgb5 img_rgb5;
+ t_image2d_lbl8 img_lbl8;
+
+ mln::io::ppm::load(img_rgb8, OLENA_IMG_PATH"/house.ppm");
+
+ img_rgb5 = mln::data::transform(img_rgb8, t_rgb8_to_rgb5());
+ img_lbl8 = mln::clustering::kmean_rgb<double,5>(img_rgb5, 3, 10, 10);
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
b/scribo/sandbox/green/use/fun/v2v/rg_to_rgb/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/use/accu/stat/histo1d/Makefile.am
copy to scribo/sandbox/green/use/fun/v2v/rg_to_rgb/Makefile.am
diff --git a/scribo/sandbox/green/use/fun/v2v/rg_to_rgb/rg_to_rgb.cc
b/scribo/sandbox/green/use/fun/v2v/rg_to_rgb/rg_to_rgb.cc
new file mode 100644
index 0000000..84ae33f
--- /dev/null
+++ b/scribo/sandbox/green/use/fun/v2v/rg_to_rgb/rg_to_rgb.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2007, 2008, 2009, 2010 EPITA 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.
+
+/// \file
+///
+/// \brief Example of using rg_t_rgb transformation used with kmean2d.
+///
+
+#include <iostream>
+#include <mln/clustering/kmean2d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/data/transform.hh>
+#include <mln/fun/v2v/rgb_to_rg.hh>
+#include <mln/fun/v2v/rg_to_rgb.hh>
+#include <mln/img_path.hh>
+#include <mln/io/ppm/load.hh>
+#include <mln/value/rg.hh>
+#include <mln/value/rgb8.hh>
+
+int main()
+{
+ typedef mln::value::rg<8> t_rg8;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_rg8> t_image2d_rg8;
+ typedef mln::fun::v2v::rgb_to_rg<8> t_rgb_to_rg;
+ typedef mln::fun::v2v::rg_to_rgb<8> t_rg_to_rgb;
+
+ t_image2d_rgb8 img_rgb8;
+ t_image2d_rgb8 point_img_rgb8;
+ t_image2d_rg8 img_rg8;
+
+ mln::io::ppm::load(img_rgb8, OLENA_IMG_PATH"/house.ppm");
+
+ img_rg8 = mln::data::transform(img_rgb8, t_rgb_to_rg());
+
+ mln::clustering::kmean2d<double, 8> kmean(img_rg8, 3);
+
+ kmean.launch_n_times();
+
+ mln::clustering::kmean2d<double,8>::t_point_img point_img = kmean.get_point();
+
+ point_img_rgb8 = mln::data::transform(point_img, t_rg_to_rgb());
+
+ return 0;
+}
--
1.5.6.5