last-svn-commit-228-g218a695 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. --- 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@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@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
participants (1)
-
Yann Jacquelet