* README.green: New.
* demo/annotating/bic/Makefile.am: New.
* demo/annotating/bic/bic.cc: New.
* demo/annotating/hsv/Makefile.am: New.
* demo/annotating/hsv/hsv.cc: New.
* demo/annotating/lep/Makefile.am: New.
* demo/annotating/lep/lep.cc: New.
* demo/annotating/nb_color/Makefile.am: New.
* demo/annotating/nb_color/nb_color.cc: New.
* demo/annotating/project/Makefile.am: New.
* demo/annotating/project/project.cc: New.
* demo/annotating/rgb_64/Makefile.am: New.
* demo/annotating/rgb_64/rgb_64.cc: New.
* demo/annotating/rgb_64_9/Makefile.am: New.
* demo/annotating/rgb_64_9/rgb_64_9.cc: New.
* demo/annotating/stddev_color/Makefile.am: New.
* demo/annotating/stddev_color/stddev_color.cc: New.
* demo/annotating/stddev_color_16/Makefile.am: New.
* demo/annotating/stddev_color_16/stddev_color_16.cc: New.
* exp/annotating/achromastism/Makefile.am: New.
* exp/annotating/achromastism/achromastism.cc: New.
* exp/annotating/achromastism/text-color.txt: New.
* exp/annotating/achromastism/text-img.txt: New.
* exp/annotating/achromastism/text-only.txt: New.
* exp/annotating/bench/Makefile.am: New.
* exp/annotating/bench/bench.cc: New.
* exp/annotating/error/Makefile.am: New.
* exp/annotating/error/error.cc: New.
* exp/annotating/histo/Makefile.am: New.
* exp/annotating/histo/histo.cc: New.
* exp/annotating/hsv/Makefile.am: New.
* exp/annotating/hsv/hsv.cc: New.
* exp/annotating/hue/Makefile.am: New.
* exp/annotating/hue/hue.cc: New.
* exp/annotating/hue/text-color.txt: New.
* exp/annotating/hue/text-img.txt: New.
* exp/annotating/hue/text-only.txt: New.
* exp/annotating/nb_color/Makefile.am: New.
* exp/annotating/nb_color/nb_color.cc: New.
* exp/annotating/saturation/Makefile.am: New.
* exp/annotating/saturation/saturation.cc: New.
* exp/annotating/saturation/text-color.txt: New.
* exp/annotating/saturation/text-img.txt: New.
* exp/annotating/saturation/text-only.txt: New.
* exp/annotating/stddev_color/Makefile.am: New.
* exp/annotating/stddev_color/stddev_color.cc: New.
* exp/annotating/stddev_color_16/Makefile.am: New.
* exp/annotating/stddev_color_16/stddev_color_16.cc: New.
* exp/annotating/value/Makefile.am: New.
* exp/annotating/value/text-color.txt: New.
* exp/annotating/value/text-img.txt: New.
* exp/annotating/value/text-only.txt: New.
* exp/annotating/value/value.cc: New.
* mln/clustering/kmean2d.hh: New.
* mln/fun/p2b/achromatic.hh: New.
* mln/fun/v2v/hue_concentration.hh: New.
* mln/fun/v2v/rgb_to_achromatism_map.hh: New.
* mln/fun/v2v/rgb_to_hsv.hh: New.
---
scribo/sandbox/green/ChangeLog | 64 +
scribo/sandbox/green/README.green | 507 +++++++-
.../kmean1d => annotating/bic}/Makefile.am | 0
scribo/sandbox/green/demo/annotating/bic/bic.cc | 122 ++
.../kmean1d => annotating/hsv}/Makefile.am | 0
scribo/sandbox/green/demo/annotating/hsv/hsv.cc | 721 ++++++++++
.../kmean1d => annotating/lep}/Makefile.am | 0
scribo/sandbox/green/demo/annotating/lep/lep.cc | 127 ++
.../kmean1d => annotating/nb_color}/Makefile.am | 0
.../green/demo/annotating/nb_color/nb_color.cc | 143 ++
.../kmean1d => annotating/project}/Makefile.am | 0
.../green/demo/annotating/project/project.cc | 275 ++++
.../kmean1d => annotating/rgb_64}/Makefile.am | 0
.../sandbox/green/demo/annotating/rgb_64/rgb_64.cc | 80 ++
.../kmean1d => annotating/rgb_64_9}/Makefile.am | 0
.../green/demo/annotating/rgb_64_9/rgb_64_9.cc | 132 ++
.../stddev_color}/Makefile.am | 0
.../demo/annotating/stddev_color/stddev_color.cc | 191 +++
.../stddev_color_16}/Makefile.am | 0
.../annotating/stddev_color_16/stddev_color_16.cc | 261 ++++
.../achromastism}/Makefile.am | 0
.../exp/annotating/achromastism/achromastism.cc | 179 +++
.../exp/annotating/achromastism/text-color.txt | 0
.../green/exp/annotating/achromastism/text-img.txt | 0
.../exp/annotating/achromastism/text-only.txt | 0
.../bench}/Makefile.am | 0
scribo/sandbox/green/exp/annotating/bench/bench.cc | 1450 ++++++++++++++++++++
.../error}/Makefile.am | 0
scribo/sandbox/green/exp/annotating/error/error.cc | 833 +++++++++++
.../histo}/Makefile.am | 0
scribo/sandbox/green/exp/annotating/histo/histo.cc | 366 +++++
.../hsv}/Makefile.am | 0
scribo/sandbox/green/exp/annotating/hsv/hsv.cc | 912 ++++++++++++
.../hue}/Makefile.am | 0
scribo/sandbox/green/exp/annotating/hue/hue.cc | 402 ++++++
.../green/exp/annotating/hue}/text-color.txt | 0
.../sandbox/green/exp/annotating/hue}/text-img.txt | 0
.../green/exp/annotating/hue}/text-only.txt | 0
.../nb_color}/Makefile.am | 0
.../green/exp/annotating/nb_color/nb_color.cc | 171 +++
.../saturation}/Makefile.am | 0
.../green/exp/annotating/saturation/saturation.cc | 175 +++
.../exp/annotating/saturation}/text-color.txt | 0
.../green/exp/annotating/saturation}/text-img.txt | 0
.../green/exp/annotating/saturation}/text-only.txt | 0
.../stddev_color}/Makefile.am | 0
.../exp/annotating/stddev_color/stddev_color.cc | 216 +++
.../stddev_color_16}/Makefile.am | 0
.../annotating/stddev_color_16/stddev_color_16.cc | 277 ++++
.../value}/Makefile.am | 0
.../green/exp/annotating/value}/text-color.txt | 0
.../green/exp/annotating/value}/text-img.txt | 0
.../green/exp/annotating/value}/text-only.txt | 0
scribo/sandbox/green/exp/annotating/value/value.cc | 468 +++++++
scribo/sandbox/green/mln/clustering/kmean2d.hh | 4 +-
scribo/sandbox/green/mln/fun/p2b/achromatic.hh | 20 +-
.../sandbox/green/mln/fun/v2v/hue_concentration.hh | 10 +
.../green/mln/fun/v2v/rgb_to_achromatism_map.hh | 5 +
scribo/sandbox/green/mln/fun/v2v/rgb_to_hsv.hh | 15 +-
59 files changed, 8105 insertions(+), 21 deletions(-)
copy scribo/sandbox/green/demo/{clustering/kmean1d => annotating/bic}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/demo/annotating/bic/bic.cc
copy scribo/sandbox/green/demo/{clustering/kmean1d => annotating/hsv}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/demo/annotating/hsv/hsv.cc
copy scribo/sandbox/green/demo/{clustering/kmean1d => annotating/lep}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/demo/annotating/lep/lep.cc
copy scribo/sandbox/green/demo/{clustering/kmean1d => annotating/nb_color}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/demo/annotating/nb_color/nb_color.cc
copy scribo/sandbox/green/demo/{clustering/kmean1d => annotating/project}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/demo/annotating/project/project.cc
copy scribo/sandbox/green/demo/{clustering/kmean1d => annotating/rgb_64}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/demo/annotating/rgb_64/rgb_64.cc
copy scribo/sandbox/green/demo/{clustering/kmean1d => annotating/rgb_64_9}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/demo/annotating/rgb_64_9/rgb_64_9.cc
copy scribo/sandbox/green/demo/{clustering/kmean1d =>
annotating/stddev_color}/Makefile.am (100%)
create mode 100644 scribo/sandbox/green/demo/annotating/stddev_color/stddev_color.cc
copy scribo/sandbox/green/demo/{clustering/kmean1d =>
annotating/stddev_color_16}/Makefile.am (100%)
create mode 100644
scribo/sandbox/green/demo/annotating/stddev_color_16/stddev_color_16.cc
copy scribo/sandbox/green/exp/{regional_maxima => annotating/achromastism}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/exp/annotating/achromastism/achromastism.cc
copy {milena => scribo}/sandbox/green/exp/annotating/achromastism/text-color.txt
(100%)
copy {milena => scribo}/sandbox/green/exp/annotating/achromastism/text-img.txt (100%)
copy {milena => scribo}/sandbox/green/exp/annotating/achromastism/text-only.txt
(100%)
copy scribo/sandbox/green/exp/{regional_maxima => annotating/bench}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/exp/annotating/bench/bench.cc
copy scribo/sandbox/green/exp/{regional_maxima => annotating/error}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/exp/annotating/error/error.cc
copy scribo/sandbox/green/exp/{regional_maxima => annotating/histo}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/exp/annotating/histo/histo.cc
copy scribo/sandbox/green/exp/{regional_maxima => annotating/hsv}/Makefile.am (100%)
create mode 100644 scribo/sandbox/green/exp/annotating/hsv/hsv.cc
copy scribo/sandbox/green/exp/{regional_maxima => annotating/hue}/Makefile.am (100%)
create mode 100644 scribo/sandbox/green/exp/annotating/hue/hue.cc
copy {milena/sandbox/green/exp/annotating/achromastism =>
scribo/sandbox/green/exp/annotating/hue}/text-color.txt (100%)
copy {milena/sandbox/green/exp/annotating/achromastism =>
scribo/sandbox/green/exp/annotating/hue}/text-img.txt (100%)
copy {milena/sandbox/green/exp/annotating/achromastism =>
scribo/sandbox/green/exp/annotating/hue}/text-only.txt (100%)
copy scribo/sandbox/green/exp/{regional_maxima => annotating/nb_color}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/exp/annotating/nb_color/nb_color.cc
copy scribo/sandbox/green/exp/{regional_maxima => annotating/saturation}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/exp/annotating/saturation/saturation.cc
copy {milena/sandbox/green/exp/annotating/achromastism =>
scribo/sandbox/green/exp/annotating/saturation}/text-color.txt (100%)
copy {milena/sandbox/green/exp/annotating/achromastism =>
scribo/sandbox/green/exp/annotating/saturation}/text-img.txt (100%)
copy {milena/sandbox/green/exp/annotating/achromastism =>
scribo/sandbox/green/exp/annotating/saturation}/text-only.txt (100%)
copy scribo/sandbox/green/exp/{regional_maxima => annotating/stddev_color}/Makefile.am
(100%)
create mode 100644 scribo/sandbox/green/exp/annotating/stddev_color/stddev_color.cc
copy scribo/sandbox/green/exp/{regional_maxima =>
annotating/stddev_color_16}/Makefile.am (100%)
create mode 100644
scribo/sandbox/green/exp/annotating/stddev_color_16/stddev_color_16.cc
copy scribo/sandbox/green/exp/{regional_maxima => annotating/value}/Makefile.am
(100%)
copy {milena/sandbox/green/exp/annotating/achromastism =>
scribo/sandbox/green/exp/annotating/value}/text-color.txt (100%)
copy {milena/sandbox/green/exp/annotating/achromastism =>
scribo/sandbox/green/exp/annotating/value}/text-img.txt (100%)
copy {milena/sandbox/green/exp/annotating/achromastism =>
scribo/sandbox/green/exp/annotating/value}/text-only.txt (100%)
create mode 100644 scribo/sandbox/green/exp/annotating/value/value.cc
diff --git a/scribo/sandbox/green/ChangeLog b/scribo/sandbox/green/ChangeLog
index 5e4cb27..6210a79 100644
--- a/scribo/sandbox/green/ChangeLog
+++ b/scribo/sandbox/green/ChangeLog
@@ -1,3 +1,67 @@
+2010-09-08 Yann Jacquelet <jacquelet(a)lrde.epita.fr>
+
+ Import annotating sources from milena green's sandbox.
+
+ * README.green: New.
+ * demo/annotating/bic/Makefile.am: New.
+ * demo/annotating/bic/bic.cc: New.
+ * demo/annotating/hsv/Makefile.am: New.
+ * demo/annotating/hsv/hsv.cc: New.
+ * demo/annotating/lep/Makefile.am: New.
+ * demo/annotating/lep/lep.cc: New.
+ * demo/annotating/nb_color/Makefile.am: New.
+ * demo/annotating/nb_color/nb_color.cc: New.
+ * demo/annotating/project/Makefile.am: New.
+ * demo/annotating/project/project.cc: New.
+ * demo/annotating/rgb_64/Makefile.am: New.
+ * demo/annotating/rgb_64/rgb_64.cc: New.
+ * demo/annotating/rgb_64_9/Makefile.am: New.
+ * demo/annotating/rgb_64_9/rgb_64_9.cc: New.
+ * demo/annotating/stddev_color/Makefile.am: New.
+ * demo/annotating/stddev_color/stddev_color.cc: New.
+ * demo/annotating/stddev_color_16/Makefile.am: New.
+ * demo/annotating/stddev_color_16/stddev_color_16.cc: New.
+ * exp/annotating/achromastism/Makefile.am: New.
+ * exp/annotating/achromastism/achromastism.cc: New.
+ * exp/annotating/achromastism/text-color.txt: New.
+ * exp/annotating/achromastism/text-img.txt: New.
+ * exp/annotating/achromastism/text-only.txt: New.
+ * exp/annotating/bench/Makefile.am: New.
+ * exp/annotating/bench/bench.cc: New.
+ * exp/annotating/error/Makefile.am: New.
+ * exp/annotating/error/error.cc: New.
+ * exp/annotating/histo/Makefile.am: New.
+ * exp/annotating/histo/histo.cc: New.
+ * exp/annotating/hsv/Makefile.am: New.
+ * exp/annotating/hsv/hsv.cc: New.
+ * exp/annotating/hue/Makefile.am: New.
+ * exp/annotating/hue/hue.cc: New.
+ * exp/annotating/hue/text-color.txt: New.
+ * exp/annotating/hue/text-img.txt: New.
+ * exp/annotating/hue/text-only.txt: New.
+ * exp/annotating/nb_color/Makefile.am: New.
+ * exp/annotating/nb_color/nb_color.cc: New.
+ * exp/annotating/saturation/Makefile.am: New.
+ * exp/annotating/saturation/saturation.cc: New.
+ * exp/annotating/saturation/text-color.txt: New.
+ * exp/annotating/saturation/text-img.txt: New.
+ * exp/annotating/saturation/text-only.txt: New.
+ * exp/annotating/stddev_color/Makefile.am: New.
+ * exp/annotating/stddev_color/stddev_color.cc: New.
+ * exp/annotating/stddev_color_16/Makefile.am: New.
+ * exp/annotating/stddev_color_16/stddev_color_16.cc: New.
+ * exp/annotating/value/Makefile.am: New.
+ * exp/annotating/value/text-color.txt: New.
+ * exp/annotating/value/text-img.txt: New.
+ * exp/annotating/value/text-only.txt: New.
+ * exp/annotating/value/value.cc: New.
+ * mln/clustering/kmean2d.hh: New.
+ * mln/fun/p2b/achromatic.hh: New.
+ * mln/fun/v2v/hue_concentration.hh: New.
+ * mln/fun/v2v/rgb_to_achromatism_map.hh: New.
+ * mln/fun/v2v/rgb_to_hsv.hh: New.
+
+
2010-07-07 Yann Jacquelet <jacquelet(a)lrde.epita.fr>
Import regional maxima sources from milena green's sandbox.
diff --git a/scribo/sandbox/green/README.green b/scribo/sandbox/green/README.green
index 7886914..5d6e147 100644
--- a/scribo/sandbox/green/README.green
+++ b/scribo/sandbox/green/README.green
@@ -685,21 +685,6 @@ rechercher dans les derniers répertoires mp00042c et mp00307c.
* doc/labeling/mp00307c: Test sur la representativité des couleurs trouvées.
-Faire le changelog, il y a de l'aide dans git/doc/Changelog
-... et commiter
-
-
-XI ANNOTATING
---------------
-
-==> to do
-
-
-
-* doc/annotating
-
-
-
XI AUTRES ASPECTS DOCUMENTAIRES
-------------------------------
@@ -732,3 +717,495 @@ l'effort.
* doc/formulae: LaTex directory.
* doc/quick_tour: LaTex directory.
+
+XII ANNOTATING
+--------------
+
+Tout d'abord, voici les notes documentaires qui ont été réalisées sur
+la problématique d'annotation d'image. On trouvera un fichier
+class.txt qui a pour but de poser quelques réflexions sur les types de
+classes de document. Les informations ne sont pas abouties mais
+permettent de défricher un peu le terrain. Le document
+syntheseMillet2008 est un compte-rendu de lecture des parties
+relatives à nos travaux dans la thèse de Millet. Pour bien comprendre
+mon travail, il est impératif de lire les travaux de Millet, ou
+simplement ce compte-rendu. Le dernier document est moins intéressant,
+il s'agit d'une note de travail sur les indicateurs de Millet bruts de
+fonderie (testMillet2008). Cette note n'est ni achevée, ni
+aboutie. Elle conclue sur le fait que les indicateurs et les seuils
+donnés par Millet dans sa thèse sont complètement à revoir pour nos
+besoins. Notemment, des tests sur la détection des images par rapport
+aux cliparts nous ont convaincu que certaines images AFP contiennent
+des de grandes zones homogènes qui induisent des erreurs dans les
+prédicteurs de Millet. Néanmoins, les cas particuliers qui
+contredisent les aspects opérationnnels de Millet n'enlèvent pas sa
+réflexion: Les images noir/blanc (ou monochromes) ont une très faible
+saturation, et/ou une forte concentration de la teinte. Les cliparts
+ont une forte concentration de niveaux de gris autour d'un pic.
+
+* doc/annotating: La documentation relative à l'annotation.
+
+
+Après la lecture des descripteurs de Millet, un des premiers réflexe a
+été d'en implémenter plusieurs pour voir ce qu'ils pouvaient ressortir
+sur les images que nous avions. Le descripteur BIC sépare une image en
+deux ensembles de pixels, les points intérieurs et les points
+extérieurs. Les points intérieurs ont la propriété d'être de même
+couleur que leur 4-voisins. Attention, la couleur est évaluée dans un
+espace RGB à 3 bits.
+
+* demo/annotating/bic: Histogrammes des points intérieurs et extérieurs.
+
+
+Le descripteur LEP, lui, propose de seuiller par sobel l'image et de
+faire l'histogramme des configurations du voisinage des points
+seuillés. Pour ce faire, on utilise une convolution un peu spéciale
+qui va attribué un unique id en fonction du voisinage.
+
+* demo/annotating/lep: Histogramme des configurations des voisinages des pixels.
+
+
+Un autre descripteur simple est le nombre de couleur dans une
+image. Pour cela, il est possible de construire l'histogramme des
+couleurs et de compter les cellules pleines. On peut éventuellement
+appliquer une quantification sur l'espace des couleurs. La
+compilation laisse place à d'étranges warnings sur une comparaison
+entre entiers signés et non signés, mais je n'ai pas la main dans mon
+code (ou je ne sais pas comment faire) pour enlever ces warnings. Ils
+sont récents, je n'avais pas souvenir de les avoir eu.
+
+* demo/annotating/nb_color: Compte le nombre de couleurs dans une image.
+* exp/annotating/nb_color: Adaptation pour fonctionner sur une base d'image.
+
+
+L'histogramme RGB-64 est un descripteur simple qui quantifie les
+couleurs sur 2 bits et réalise l'histogramme dans cet espace. C'est
+bien sûr une classification gros grain, mais ajouté au reste ... La
+version RGB-64-9 ajoute une phase de division de l'image en 9 sous
+images. De cette manière, l'histogramme RGB-64 est construit sur les 9
+sous images. Pour former le descripteur final, on fusionne les neufs
+histogrammes.
+
+* demo/annotating/rgb_64: Histogramme couleur dans l'espace RGB-64 (2 bits/axe).
+* demo/annotating/rgb_64_9: Histogramme RGB-64 sur les 9 sous images.
+
+
+Le descripteur de projection relaté par Millet est particulier. En
+premier lieu l'image est sous échantillonnée pour réduire sa dimension
+à 100 x 100 de manière à borner la taille des vecteurs obtenus au
+final. Puis l'image est seuillée par sobel (threshold = 100). L'image
+est d'abord divisée horizontalement en deux. Puis on établit la
+projecton perpendiculairement à la séparation de manière à obtenir
+deux vecteurs de 100 valeurs chacunes. On recommence l'opération en
+divisant maintenant l'image verticalement. L'union des 4 vecteurs
+forme le descripteur de projection. L'information condensée dans ces
+vecteurs est simplement la répartition des contours de manière
+horizontale ou verticale.
+
+* demo/annotating/project: Répartition des contours horizontaux et verticaux.
+
+
+La reconnaissance des cliparts s'appuie sur une analyse d'histogramme
+qui est fournie dans le code suivant. L'idée est de dire qu'une image
+de type clipart va être reconnaissable surtout à l'aide de ces
+contours. La couleur existe mais est très grossière. Le faitde
+dessiner à la main implique de simplifier énormément, de caricaturer,
+le remplissage. Du coup, une analyse en niveau de gris de
+l'histogramme révèle très peu de nuances. Il peut cependant en avoir
+un peu. Néanmoins, il existe des logiciels pour aider à la fabrication
+des cliparts qui proposent l'usage de dégradé, ce qui nuit à cette
+méthode de reconnaissance. Millet analyze l'histogramme normalisé
+(histogramme divisé par son pic) et regarde si son energie ne serait
+pas concentrée autour du pic (5 pixels de chaque côté
+maximum). Parfois cette méthode ne fonctionne pas correctement sur des
+photographies qui ont un cadre uniforme. La méthode trouve un pic (le
+cadre) et vérifie alors qu'une proportion non négligeable des pixels
+sont bien autour de ce pic (tout dépend de l'épaisseur du cadre). Pour
+palier à cet inconvénient, Millet propose d'utiliser ce test, non plus
+sur l'image entière, mais sur chacune des 16 sous images après un
+découpage géométrique régulier. De facto, la contribution du cadre
+diminue suffisemment pour repasser en dessous du seuil de
+reconnaissance.
+
+* demo/annotating/stddev_color: Descripteur utilisé reconnaitre des cliparts.
+* exp/annotating/stddev_color_16: Adaptation pour le travail sur base.
+* demo/annotating/stddev_color_16: Descripteur pour cliparts avec 16 imagettes.
+* exp/annotating/stddev_color: Adaptation pour le travail sur une base d'image.
+
+
+A partir de maintenant, tous les morceaux de codes réalisés préparent
+directement ou indirectement le résultat de la classification des
+bases (exp/annotating/bench).
+
+Plus de temps pour faire le code use correspondant aux fichiers
+librairies. Tout le code pour le faire est dans hsv. Rien de
+compliqué, mais allons à l'essentiel.
+
+Le but du code HSV est d'effectuer les tests de Millet ou des
+améliorations sur ces tests. Le premier test proposé par Millet est
+l'achromaticité. Il s'agit de regarder s'il existe une faible
+variation entre les trois canaux (R/G/B) pour un grand nombre de
+pixels. Si c'est le cas, c'est que l'image est presque en niveau de
+gris et peut être remplacée facilement par une image grisée sans trop
+de distorsions au niveau de la couleur. Nous avons essayer de
+généraliser un peu le test de manière à produire, non pas seulement
+une réponse sur l'achromaticité de l'image, mais aussi avoir une vue
+d'ensemble (sous forme d'image) des variations entre les cannaux pour
+chaque pixel. Il n'est pas utile d'analyser les différences sur chacun
+des canaux, prendre la différence absolue entre le canal min et le
+canal max suffit pour définir le test d'achromaticité.
+
+Les autres tests de Millet sont la faible saturation et la dominance
+de la teinte. Pour savoir si la saturation est faible, il faut
+utiliser un histogramme du canal dédié à la saturation. Si 95% des
+pixels sont en dessous de 100, alors l'image est faiblement saturée,
+elle est en noir et blanc. De la même manière, on regarde la dominance
+de la teinte. Pour ce faire, il faut voir si l'histogramme de la
+teinte ne possède pas un pic avec une très faible variance (tout
+rapproché autour du pic). Si c'est le cas, la dominance de la teinte
+est avérée et l'on peut calculé la couleur dominante. L'image est en
+niveau de gris, mais colorisé autour d'une couleur (par cepia, vert
+...).
+
+Ce programme est très très sujet à changements, il m'a servit de test
+et je ne peux pas juré qu'il est complètement sain au niveau du
+traitement. D'autres versions sont potentiellement plus
+stables. Notemment celle dans exp/annotating/hsv.
+
+* mln/fun/v2v/rgb_to_achromatism_map.hh : Distance pour l'achromaticité.
+* mln/fun/v2v/achromatic.hh : Define the achromatic map.
+* mln/fun/v2v/hue_concentration.hh : Define the distance hue/peak map.
+* mln/fun/p2b/achromatic.hh : Say if a site is achromatic.
+* demo/annotating/hsv: Code des différents tests de Millet.
+
+
+Dans le répertoire exp/annotating/hue, on trouve 3 fichiers textes qui
+rassemblent des classes d'images. Tout d'abord les images ICDAR
+n'ayant que du texte et des traces de couleurs (lettrine de couleur,
+trait, petit bandeau), un fichier où il n'y a que du texte noir &
+blanc et un fichier contenant les images couleurs (avec photographies
+ou dessins). Cette classification a été effectuée de manière manuelle.
+Le code hue test la proportion de pixels étant autour du pic de
+teinte. Il s'agit de savoir si la dominance d'une teinte est
+avérée. Le code renvoit la proportion de pixels agglomérés autour du
+pic. Le but est de généralisé les tests de millets pour qu'ils se
+ressemblent le plus possible.
+
+* exp/annotating/hue: Implémentation de la généralisation du test de Millet.
+* mln/fun/v2v/rgb_to_hue_map.hh : Construction de la map de teinte.
+
+
+On retrouve les trois fichiers permettant de classifier la base ICDAR
+en trois sous populations. Le test de saturation consiste simplement à
+regarder si une certaine quantité de la population de l'histogramme de
+saturation est en dessous d'un certain seuil. La généralisation du
+test ne porte pas sur le test en lui-même, mais sur la forme dans
+lequel le test est fait.
+
+* exp/annotating/saturation: Implémentation de la généralisation du test.
+* mln/fun/v2v/rgb_to_saturation_map.hh : Construction de la map de saturation.
+
+
+Le test de value a déjà été décrit précédemment dans
+stddev_color. L'idée est toujours la même, mais cette fois il est
+effectué dans l'espace des valeurs (HSV). Cela ne change pas grand
+chose, puisqu'il était utilisé sur des images en niveau de gris. C'est
+l'un des tests importants car il réagit à la différentiation entre une
+image type photographie et une image plus stylisée comme un
+clipart. Ce test a aussi des vertus pour la distinction entre du noir
+& blanc et de la couleur. Il s'avère que les images type photographie
+avec pleins de couleurs ont un histogramme moins sujet aux pics que
+les histogrammes noir & blanc. De facto, l'énergie de l'histogramme
+est distribué sur l'ensemble de la plage contrairement aux images noir
+& blanc où il y a une concentration de chaque côté de l'histogramme
+(bipolarité).
+
+* exp/annotating/value: Implémentation de la généralisation du test de Millet.
+* mln/fun/v2v/rgb_to_value_map.hh : Transformation d'espace.
+
+
+Le programme hsv reprend les tests préalablement élaborés auparavant
+sur les plans H, S puis V. Il combine tout en un seul programme pour
+avoir une vision plus synthétique de ce qui se passe sur les 3 espaces
+simultanément.
+
+Les tests incorpore mes transformations. C'est à dire que l'on
+effectue une série de test équivalent à ceux de Millet (au moins dans
+l'idée et le plus souvent, il s'agit d'une réecriture sous une autre
+forme) en partant des histogrammes normalisés. Un histogramme
+normalisé est un histogramme de flottant qui contient l'histogramme
+classique divisé par le nombre total de pixels. En faisant cela, on se
+déplace dans l'espace des distributions. Si l'histogramme n'a qu'un
+seul pic et que ce dernier contient tous les pixels (pic de dirac par
+exemple), alors l'histogramme normalisé donnera 1 comme valeur de
+proportion à ce pic. En fait, l'intégrale d'une distribution vaut
+1. Le but des distributions est de s'affranchir des caractéristiques
+de taille de l'image, ce qui permet de comparer les histogrammes entre
+eux. On peut ainsi comparer les histogrammes d'une photo AFP petit
+format avec celui d'une image grand format de la base ICDAR. Le but du
+jeu est de garder les idées de Millet dans ce nouvel espace. Les tests
+obtenus sont équivalents mais pas identiques.
+
+Pour la teinte, une fois l'histogramme normalisé obtenu, on cherche à
+savoir s'il existe un pic avec une forte proportion de l'histogramme
+autour de ce pic. Plutôt que le pic, nous prenons la moyenne qui est
+un opérateur un peu plus robuste et nous calculons la proportion de
+l'histogramme autour (un seuil donné en paramètre défini le périmètre
+du calcul). L'expression sous forme de proportion plutôt que sous la
+forme d'une variance rend le test homogène avec les autres tests.
+
+Pour la saturation, après normalisation, on regarde la proportion de
+l'histogramme en dessous d'un certain seuil. Il n'y a pas de
+changement significatif par rapport au test de Millet. Le seuil
+initialement proposé par Millet était 100, il a été adapté car nos
+bases sont différentes des siennes (le notre est à 25).
+
+Le test sur les valeurs (cliparts contre photos) a vraiment un intérêt
+au delà de ce cas d'utilisation. Il nous renseigne sur la
+concentration autour d'un pic de l'histogramme ou non. Nous préferrons
+la mesure de similarité à l'équi-répartition des densités, mais l'idée
+est exactement la même. Est-ce que notre histogramme est plat ou
+inversement, est-ce que les contributions sont rassemblées autour d'un
+pic? Si une image est noir et blanc, il existera un pic correspondant
+au fond et la densité s'éloignera fortement de la distribution
+équiprobable. Dans le cas maintenant d'une image couleur, la
+répartition est plus homogène, couvrant un large spectre dans le
+domaine de l'histogramme. Du coup, la distribution semblera davantage
+equi-répartie. On notera que nous prenons le test à l'envers de ce que
+propose Millet. Il essaye de voir si il y a un pic et calcule une
+forme de contribution normalisée autour de ce pic. Nous au contraire,
+on regarde l'absence de pic et on calcule la différence entre la
+densité et cette absence de pic. Notre avantage par rapport à Millet
+est démontré particulièrement dans les cas où il existe plusieurs
+grosses distributions. A contrario, notre test souffre des cas où il
+existe de nombreuses petites distributions.
+
+
+Voici un premier retour sur les expériementations:
+La discrimination entre la base AFP et la base ICDAR peut se faire en
+étudiant la forme des densités des niveaux de gris. Les images
+naturelles semblent avoir un spectre recouvrant en général les 256
+niveaux de gris alors que les images de documents ont une présence
+importante du fond. Dans le cadre d'une densité, ce qui est alloué sur
+le fond ne peut se retrouver ailleurs. Une comparaison avec la densité
+équiprobable nous renseigne donc sur la nature des images. Il semble
+néanmoins qu'un certain nombre d'images défient ce dispositif. Par
+exemple des gros plans sur des zones mono-teintée (ski, voile,site
+web).
+
+* exp/annotating/hsv: Code unifiant les trois tests sur chacun des plans HSV.
+* mln/fun/v2v/rgb_to_hue_map.hh : Transformation d'espace.
+* mln/fun/v2v/rgb_to_saturation_map.hh : Transformation d'espace.
+* mln/fun/v2v/rgb_to_value_map.hh : Transformation d'espace.
+
+
+Le test sur l'achromatisme des images est décrit dans le code
+suivant. Il a été purement et simplement abandonné dans la mesure où
+c'est un cas très particulier qui est repris par une saturation très
+faible. La saturation s'exprime comme 1 - min(channel)/max(channel),
+mais dans le cas où le min(channel) == max(channel), la saturation
+vaut 0. Le problème vient plutôt du calcul de la teine qui ne peut pas
+admettre que le min soit égal au max. Pour ce calcul, on se débrouille
+pour gérer le cas et renvoyer une valeur standardisée, Millet
+proposait -1.
+
+* exp/annotating/achromatism: Détection d'image couleur en niveau de gris.
+* mln/fun/v2v/rgb_to_achromatism_map.hh : Transformation d'espace.
+
+
+Ce programme a pour but de créer les histogrammes normalisés en rafale
+pour les bases AFP et ICDAR. Il assure leur création dans les six
+plans possibles R,G,B,H,S,V. De cette manière il est possible de
+vérifier les corrélations éventuelles entre le canal B et G. Par
+ailleurs, après visionnement de tous les histogrammes, on note des
+spécificités dans les deux bases sur les plans S et V. Certaines
+images ont des réactions très fortes sur le plan H, mais ce n'est pas
+une caractéristique pour une base (seulement pour ces images en
+question). Les résultats ont déjà été sauvegardés dans le répertoire
+image du LRDE. Des infos sont notés à ce sujet dans README.result. Le
+seul but de ce calcul est de maîtriser csujet dans README.result. Le
+seul but de ce calcul est de maîtriser ce qui se passe dans ces
+espaces, pas simplement de supposer ce qu'il pourrait s'y passer. La
+comparaison des images est rendu possible quelque soit la base
+d'origine par le fait qu'elles sont normalisées. Chaque fréquence des
+histogrammes est divisée par la somme des fréquences. On obtient donc
+une version discrète des densitées. La somme des nouvelles fréquences
+vaut 1. On voit davantage si les densités se rapprochent d'une
+équi-répartition ou non. La négative implique un ou plusieurs pics. Le
+cas défavorable dans mon approche (qui existe pour certaines images)
+est une multitude de tout petits pics autour de l'équi-répartition. Ce
+n'est pas équi-répartie pour les calculs mais ce n'est clairement pas
+la manisfestation d'une concentration de l'énergie quelque part.
+
+* exp/annotating/histo: Creation des histogrammes normalisés.
+* mln/fun/v2v/rgb_to_hue_map.hh: Transformation d'espace.
+* mln/fun/v2v/rgb_to_saturation_map.hh: Transformation d'espace.
+* mln/fun/v2v/rgb_to_value_map.hh: Transformation d'espace.
+
+
+Dans le programme erreur, on teste l'idée de jonathan. Une référence à
+ce sujet peut être trouvée dans README.img. Les bases AFP et ICDAR
+sont retravaillées à l'aide de ImageMagick et de Gimp pour diminuer le
+nombre de couleurs initiales. On oblige à n'avoir que 30, 20 ou 10
+couleurs pour chaque base. Il y a donc 4 versions de chacune des bases
+en comptant la version originale des images. Les algorithmes utilisés
+par Gimp et ImageMagick sont très différents. L'idée de Jonathan était
+de dire que lorsqu'une image est couleur, plus on réduit le nombre de
+couleur, plus elle change vis-à-vis de l'image originale. Inversement,
+si une image possède peu de couleurs (noir & blanc), sa dégradation ne
+l'altérera pas tant que cela. Prenons une image d'un skieur de la base
+AFP, en réduisant le nombre de couleurs, la combinaison marron va
+devenir marron strictement homogène et la perception que nous en avons
+est visuellement très altérée. A contrario, une image en noir & blanc
+ne semble pas bouger d'un pouce. La comparaison avec la discrimination
+sur la saturation ou la valeur montrera des résultats un peu meilleur
+plus tard mais il impossible de préjuger a priori des résultats
+futurs. L'erreur entre l'image initiale et l'image dégradée est
+calculée avec le PNSNR (compression p278 Handbook Color). Le programme
+calcule la dégradation et essaie de trouver automatiquement des seuils
+de séparation pour les deux bases. 4 détection de seuils sont testées.
+Ces seuils sont calculées avec deux bases représentatives des bases à
+discriminer. En mode production, le seuil est vu comme une constante
+pour le programme. Les deux premières classifications renvoient un
+seuil calculée comme une moyenne pondérée des moyennes des populations
+à discriminer. Le premier détecteur pondère par la déviation standard
+et le second par la variance. Le troisième simule deux populations
+gaussiennes de variances différentes et résoud l'équation de second
+degré qui en résulte. Enfin, le dernier test ne préjuge pas des
+distributions statistiques et réalise la minimisation de l'erreur de
+classification. Pour cela, il suffit de compter le nombre d'images
+bien classées et mal classées sur les bases d'apprentissage des
+populations. On utilise pour cela la méthode Otsu. Le détecteur PNSRN
+renvoie une valeur. Pour chaque population (AFP, ICDAR), on construit
+l'histogramme de des valeurs obtenues. A noter, qu'il faut que les
+valeurs du PNSNR soient ramenées entre 0 et 255. En pratique ce n'est
+pas un problème, mais il faut le mettre en oeuvre, dans mon code, ce
+n'est pas fait (les valeurs ne posaient pas de problème). Donc, pour
+chaque seuil possible (de 0 à 256), on étudie la matrice de classement
+(groupe 1 - détecté groupe 1, groupe 1 - détecté groupe 2, groupe 2 -
+détecté groupe 1, groupe 2 - détecté groupe 2). L'erreur est
+simplement la somme des quantités groupe x - détecté groupe y avec x
+!= y. Finalement, pour chaque seuil, il est possible de connaitre
+l'erreur. Le processus de minimisation de l'erreur revient à chercher
+le seuil associé à l'erreur minimale. C'est ce dernier test que nous
+préconisons. Il faut mettre en lumière que ces quatre tests renvoient
+à peu près les mêmes seuils. La minimisation de l'erreur étant le
+meilleur de tous puisqu'il minimise directement l'erreur de
+classification et c'est ce que nous cherchions en fin de compte. Un
+cinquième test a été fait avec une analyse de fisher sur l'histogramme
+des populations mélangées, mais c'est une idée saugrenue car nous
+disposons à ce niveau des populations séparées et évidemment les
+résultats sont moins bons.
+
+Petit rappel. Un vieux problème a été mis à jour ici. Lorsqu'on
+calcule des informations sur un histogramme, le type temporaire qui
+contient les résultats ne doit pas être le type qui encode les valeurs
+des résultats. Par exemple, un histogramme de byte, un calcul de
+variance tout simple où il faut stocker la valeur des pixels au carré
+multiplié par leur occurrence tiendra facilement dans un long mais pas
+dans un byte. Le sucre avec les acesseurs des itérateurs tend à
+mélanger les genres. Une solution simple est de stocker la valeur de
+l'histogramme dans un type pouvant effectuer les calculs et ensuite
+retravailler avec ce type. Nous avions déjà discuté de ce problème et
+je ne sais pas si tu avais pu corriger le problème. Si la
+classification renvoit n'importe quoi, il se peut que cela provienne
+de ce problème. Le problème ne se voit pas sur des calculs de
+moyennes, il ne s'observe que sur certains calculs de variance (dépend
+de la formule utilisée).
+
+* exp/annotating/error: Test de l'idée de jonathan (dégradation des couleurs)
+
+
+Le travail dans bench.cc reprend toute sorte de travaux déjà réalisés
+dans d'autres fichiers. Il a pour but de comparer ensemble tous les
+descripteurs pour la reconnaissance de base de données entre l'AFP et
+l'ICDAR.
+
+Le travail commence avec un certain nombres de routines travaillant
+sur les histogrammes permettant de trouver le pic, la moyenne, la
+variance et d'autres éléments. Les routines étaient éparpillées dans
+le code, du coup je les ai regroupées au même endroit. Il y a des
+redondances de code correspondant à des copier/coller ou à différents
+essais. Prendre les versions les plus génériques et en faire des
+accumulateurs serait un riche idée.
+
+Huit détecteurs sont comparés ensembles:
+- hue1, détection d'un pic de teinte très dense par la méthode de Millet.
+- sat1, détection d'une densité importante dans les saturations basses (Millet).
+- lvl0, comptage du nombre de niveau de gris (idée de Millet).
+- hue0, détection d'un pic de teinte par la méthode des densités.
+- sat0, détection d'une forte basse saturation par la méthode des densités.
+- val0, détection d'un pic de niveau de gris par la méthode des densités.
+- val1, détection d'un pic de niveau de gris par la méthode de Millet.
+- err, PNSNR (idée de jonathan).
+
+FIXME: Attention, le PNSNR n'est pas borné, il faut le faire, il doit avoir
+au maximum 255 comme valeur.
+
+Tous les détecteurs ont été expliqués en large, en long et en travers
+dans les sources précédentes. LIRE le chapitre XII (ANNOTATING) de ce fichier
+en entier.
+
+Ensuite vient les séparateurs de population statistiques qui ont été
+déjà introduit dans le fichier error. Bien que tous soient présent,
+c'est la minimisation de l'erreur qui est utilisée.
+
+Enfin vient le front end, l'un des plus complexes que j'ai écrit cette
+année. Le main lui même, n'est pas la partie la plus complexe. Il
+définit les actions fonctionnelles à réaliser et la structure de
+donnée réalisée pour garder la trace de tous les résultats.
+- File_name : Cette variable retient le nom des fichiers. C'est un tableau
+de la taille du nombre d'images rencontrées toute base confondue. Comme on
+ne parcourt qu'une fois les répertoires, il faut pouvoir retenir cette
+information qui servira éventuellement pour la nomenclature des dumps
+par la suite.
+- Result : Cette variable contient toutes les informations du traitement.
+C'est un tableau à deux dimensions, une pour les images et une autre pour
+les descripteurs. L'index d'image est le même que pour file_name.
+- Size : Cette variable contient le nombre d'images par database.
+- Threshold : Cette variable va stocker les seuils calculés sur chacun
+des descripteurs. Ces seuils sont sensés effectuer la séparation entre les
+deux bases.
+- Cxx : variables de comptage des images bien ou mal classées relativement
+à la position des seuils et à l'appartenance d'origine des images. Cette
+appartenance d'origine est calculée à l'aide Size qui contient le nombre
+d'image par base de données. Comme les images sont vues dans l'ordre, les X
+premières appartiennent à la base ICDAR et les Y suivantes à la base AFP.
+- histo : Variable servant à effectuer par database et par descripteur un
+histogramme utilisé ensuite lors de la discrimination des bases.
+
+La partie compute_descriptors a pour mission de passer une fois sur
+toutes les images et de calculer les descripteurs associés. A l'issue
+de cette passe file_name, result et size sont remplis et pourront être
+utilisés par les autres routines.
+
+La partie dump_descriptors a pour but de réaliser un tracé en gnuplot,
+avec une couleur différente pour chaque base. Le graphe montre les
+valeurs utilisées par chaque descripteur pour toutes les images de la
+base.
+
+La partie correction des descripteurs est optionnelle et force un
+certain nombre de valeurs pour être inférieures à 256. Le but était de
+pouvoir travaillé, même si les descripteurs n'étaient pas complètement
+opérationnels. Elle sert donc pour le debug.
+
+La partie calcul des histogrammes sert à obtenir la distribution des
+valeurs de chacun des descripteurs en fonction des bases
+utilisées. C'est une étape préliminaire à l'analyse des populations et
+au calcul des seuils.
+
+La partie calcul des seuils repose sur la minimisation des erreurs de
+classification. Cette méthode ne fonctionne bien si la classe zéro à
+une moyenne inférieure à la classe un. Du coup, il n'est pas possible
+de déterminer de manière simple si la classe 0 correspond à l'AFP ou à
+l'ICDAR. Pour chaque descripteur, les cartes sont rebattues.
+
+Enfin, tous les histogrammes sont sauvés pour pouvoir comprendre et
+visualiser les résultats.
+
+Le main2 ne sert à rien, juste pour des essais.
+
+Attention, modification VAL0/VAL1, vérifiez que le bon descripteur est
+au bon endroit dans le tableau.
+
+* exp/annotating/bench: Comparaison des détecteurs pour la classif. ICDAR/AFP.
\ No newline at end of file
diff --git a/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
b/scribo/sandbox/green/demo/annotating/bic/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
copy to scribo/sandbox/green/demo/annotating/bic/Makefile.am
diff --git a/scribo/sandbox/green/demo/annotating/bic/bic.cc
b/scribo/sandbox/green/demo/annotating/bic/bic.cc
new file mode 100644
index 0000000..f63d260
--- /dev/null
+++ b/scribo/sandbox/green/demo/annotating/bic/bic.cc
@@ -0,0 +1,122 @@
+// 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 Implement the Millet BIC descriptor [millet.phd.2008.pdf]
+///
+/// This is an image descriptor. It quantifies the three channels on 3
+/// bits, then builds two histograms with the interior pixels and the
+/// exterior ones. The interior pixels are those where color value is
+/// the same as their 4 neighbouring pixels. The descriptor is the
+/// fusion of the two histograms.
+
+#include <iostream>
+
+#include <mln/accu/stat/histo3d_rgb.hh>
+
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/routine/initialize.hh>
+#include <mln/core/var.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/convert.hh>
+#include <mln/data/transform.hh>
+#include <mln/data/fill.hh>
+
+#include <mln/debug/println.hh>
+
+#include <mln/fun/v2v/rgb8_to_rgbn.hh>
+
+#include <mln/img_path.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/ppm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/literal/colors.hh>
+
+#include <mln/value/rgb.hh>
+#include <mln/value/rgb8.hh>
+
+/// \brief Main entry.
+///
+/// Load the images, compute the interior and the exterior with the
+/// predicate, then compute the two histograms separately.
+int main()
+{
+ typedef mln::value::rgb<3> t_rgb3;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::neighb2d t_neighb2d;
+ typedef mln::image2d<t_rgb3> t_image2d_rgb3;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image3d<unsigned> t_histo3d;
+ typedef mln::fun::v2v::rgb8_to_rgbn<3> t_rgb8_to_rgb3;
+ typedef mln::accu::meta::stat::histo3d_rgb t_histo3d_fun;
+
+ t_image2d_rgb8 input_rgb8;
+ t_image2d_rgb3 input_rgb3;
+ t_image2d_rgb3 interior_rgb3;
+ t_image2d_rgb3 exterior_rgb3;
+ t_histo3d histo_exterior;
+ t_histo3d histo_interior;
+
+ // IMAGE LOADING PHASE
+ std::cout << "Image loading phase ..." << std::endl;
+ mln::io::ppm::load(input_rgb8, ICDAR_50P_PPM_IMG_PATH"/mp00082c_50p.ppm");
+ input_rgb3 = mln::data::transform(input_rgb8, t_rgb8_to_rgb3());
+
+ mln::initialize(interior_rgb3, input_rgb3);
+ mln::initialize(exterior_rgb3, input_rgb3);
+
+ mln::data::fill(interior_rgb3, mln::literal::black);
+ mln::data::fill(exterior_rgb3, mln::literal::black);
+
+ mln_piter_(t_image2d_rgb3) p(input_rgb3.domain());
+ mln_niter_(t_neighb2d) n(mln::c4(), p);
+
+ for_all(p)
+ {
+ bool is_interior = true;
+
+ for_all(n)
+ is_interior = is_interior && (input_rgb3(p) == input_rgb3(n));
+
+ if (is_interior)
+ interior_rgb3(p) = input_rgb3(p);
+ else
+ exterior_rgb3(p) = input_rgb3(p);
+ }
+
+ histo_interior = mln::data::compute(t_histo3d_fun(), interior_rgb3);
+ histo_exterior = mln::data::compute(t_histo3d_fun(), exterior_rgb3);
+
+ //mln::io::plot::save_image_sh(histo, "histo.sh");
+
+ // PRINTING PHASE
+ mln::debug::println(histo_interior);
+ mln::debug::println(histo_exterior);
+}
diff --git a/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
b/scribo/sandbox/green/demo/annotating/hsv/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
copy to scribo/sandbox/green/demo/annotating/hsv/Makefile.am
diff --git a/scribo/sandbox/green/demo/annotating/hsv/hsv.cc
b/scribo/sandbox/green/demo/annotating/hsv/hsv.cc
new file mode 100644
index 0000000..e87ab2d
--- /dev/null
+++ b/scribo/sandbox/green/demo/annotating/hsv/hsv.cc
@@ -0,0 +1,721 @@
+// 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 Implement the Millet HSV operator [millet.phd.2008.pdf]
+///
+/// This is the Millet code for moving from RGB space to HSV
+/// one. Formulae are classical, we can find them on the web.
+///
+// Val = max(R,G,B).
+// Sat = (max(R,G,B) - min(R,G,B))/max(R,G,B).
+// IF R = max(R,G,B) THEN Hue = 60 * [(V-B)/(max(R,G,B)-min(R,G,B))].
+// IF G = max(R,G,B) THEN Hue = 60 * [2 + (B-R)/(max(R,G,B)-min(R,G,B))].
+// IF B = max(R,G,B) THEN Hue = 60 * [4 + (R-G)/(max(R,G,B)-min(R,G,B))].
+///
+/// \fixme: This code is unstable. It was using to make a lot of tests.
+/// Don't use it, we have more stable version of it.
+#include <iostream>
+#include <fstream>
+
+#include <mln/accu/max_site.hh>
+#include <mln/accu/math/count.hh>
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/binarization/threshold.hh>
+
+#include <mln/core/alias/point1d.hh>
+#include <mln/core/alias/box1d.hh>
+#include <mln/core/concept/image.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+
+#include <mln/data/transform.hh>
+#include <mln/data/compute.hh>
+#include <mln/data/stretch.hh>
+
+#include <mln/debug/println.hh>
+
+#include <mln/literal/colors.hh>
+#include <mln/literal/grays.hh>
+
+#include <mln/fun/v2v/rgb_to_hsv.hh>
+#include <mln/fun/v2v/rgb_to_achromatism_map.hh>
+#include <mln/fun/v2v/achromatism.hh>
+#include <mln/fun/v2v/hue_concentration.hh>
+#include <mln/fun/p2b/component_equals.hh>
+#include <mln/fun/p2b/achromatic.hh>
+#include <mln/fun/v2v/component.hh>
+
+#include <mln/geom/nsites.hh>
+
+#include <mln/img_path.hh>
+
+#include <mln/io/plot/save_image_sh.hh>
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/pbm/save.hh>
+
+#include <mln/pw/cst.hh>
+#include <mln/pw/value.hh>
+//#include <mln/trace/quiet.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/int_u8.hh>
+#include <mln/value/hsv.hh>
+
+
+/// \brief Classify a rgb a value with a color of reference.
+///
+/// \param[in] rgb a rgb8 value.
+///
+/// \return a rgb8 initialize with the selecting literal.
+///
+/// This classification of the RGB color space is based on the
+/// Millet's work. It uses the hue wheel to do it and make new
+/// distinction as brown/orange for instance.
+mln::value::rgb8 label_color(const mln::value::rgb8 rgb)
+{
+ mln::value::hsv_f hsv = mln::fun::v2v::f_rgb_to_hsv_f(rgb);
+
+ mln::value::rgb8 result;
+
+ // Is it a gray level ?
+ if (0 == hsv.sat())
+ {
+ // which result one ?
+ if (82 > hsv.sat())
+ result = mln::literal::black;
+ else if (179 > hsv.sat())
+ result= mln::literal::medium_gray;
+ else
+ result = mln::literal::white;
+ }
+ // Is it a true result color ?
+ else if (14 > hsv.hue())
+ result = mln::literal::red;
+ else if (29 > hsv.hue())
+ {
+ // Is is brown or orange ?
+ unsigned dist_orange = mln::math::abs(hsv.sat() - 184)
+ + mln::math::abs(hsv.val() - 65);
+
+ unsigned dist_brown = mln::math::abs(hsv.sat() - 255)
+ + mln::math::abs(hsv.val() - 125);
+
+ if (dist_orange < dist_brown)
+ result = mln::literal::orange;
+ else
+ result = mln::literal::brown;
+ }
+ else if (45 > hsv.hue())
+ {
+ // Is it green or yellow ?
+ if (80 > hsv.val())
+ result = mln::literal::green;
+ else
+ result = mln::literal::yellow;
+ }
+ else if (113 > hsv.hue())
+ result = mln::literal::green;
+ else if (149 > hsv.hue())
+ result = mln::literal::cyan;
+ else if (205 > hsv.hue())
+ result = mln::literal::blue;
+ else if (235 > hsv.hue())
+ result = mln::literal::violet;
+ else if (242 > hsv.hue())
+ result = mln::literal::pink;
+ else
+ result = mln::literal::red;
+
+ return result;
+}
+
+/// \brief Sum all the bins of the histogram.
+///
+/// \param[in] img the histogram based on image.
+///
+/// \return the sum of the overall bins.
+///
+/// Sum evry bins and return the result.
+template <typename I>
+unsigned count_histo(const mln::Image<I>& img_)
+{
+ const I& img = exact(img_);
+
+ mln_precondition(img.is_valid());
+
+ unsigned result = 0;
+ mln_piter(I) p(img.domain());
+
+ for_all(p)
+ result += img(p);
+
+ return result;
+}
+
+
+/// \brief The R function of Millet
+///
+/// \param[in] p the position of the pic.
+/// \param[in] histo_p the histo value of the pic.
+/// \param[in] x the position of the element which we compute the contrib.
+/// \param[in] histo_x the histo value of that element.
+///
+/// \result the contribution of the element x.
+///
+/// This function compute the variance-like contribution of an element
+/// x linked to the pic of the histogram. In fact, every thing is like
+/// we compute a square distance-like between the element x and the
+/// pic in the normalized histogram. Notice that the normalized
+/// histogram is the histogram divide by the value of it's pic. So at
+/// the pic, the value equals 1. It's a current representation of the
+/// histogram in image processing, we can find it in gimp for exemple.
+float r(short p, unsigned histo_p, short x, unsigned histo_x)
+{
+ float result = mln::math::sqr(((float)histo_x / histo_p) * (x-p));
+
+ return result;
+}
+
+
+/// \brief Find the peak of the histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the bin which contains the greatest value.
+///
+/// Compute the position of the peak of the histogram. To do this, we
+/// view evrey bin and we maintain the maxima of the values and the
+/// position. At the end, we return the position which contains the
+/// greatest value.
+template <typename I>
+unsigned peak_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the peak of the histogram
+ unsigned v_max = mln::opt::at(histo, 0);
+ short p_max = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ if (v_max < histo(p))
+ {
+ v_max = histo(p);
+ p_max = p.ind();
+ }
+ }
+
+ return p_max;
+}
+
+
+/// Brief compute the whole deviation of Millet
+///
+/// \param[in] image the input image to analyze.
+///
+/// \return the deviation.
+///
+/// The deviation uses the R function. It stats by finding the pic. If
+/// the pic is near the rigth border of the histo, compute the R
+/// function on the left neighbouring of the pic. If the pic is near
+/// the left border of the histo, compute the R function on the right
+/// neigbouring. Otherwise, compute the average of the right and left
+/// results. The selected neighbouring is composed of five pixels at
+/// the right or at the left of the pic. The detection of clipart
+/// assumes that the majority of the energy of the histogram is closed
+/// to the pic (five pixels around it).
+// unsigned stddev_color(mln::image2d<mln::value::int_u8> input_int_u8,
+// const char *name_histo,
+// const char *name_image)
+// {
+// typedef mln::point1d t_point1d;
+// typedef mln::value::rgb8 t_rgb8;
+// typedef mln::value::int_u8 t_int_u8;
+// typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+// typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+// typedef mln::image1d<unsigned> t_histo1d;
+// typedef mln::fun::v2v::rgb8_to_int_u8 t_rgb8_to_int_u8;
+// typedef mln::accu::meta::stat::histo1d t_histo1d_fun;
+// typedef mln::accu::max_site<t_histo1d> t_max_site_fun;
+
+// t_histo1d histo;
+
+// std::cout << "histo : " << name_histo << std::endl;
+// std::cout << "image : " << name_image << std::endl;
+
+// histo = mln::data::compute(t_histo1d_fun(), input_int_u8);
+
+// mln::io::pgm::save(input_int_u8, name_image);
+// mln::io::plot::save_image_sh(histo, name_histo);
+// mln::debug::println(histo);
+
+// // Find the peak of the histogram
+// unsigned v_max = mln::opt::at(histo, 0);
+// short p_max = 0;
+
+// mln_piter_(t_histo1d) p(histo.domain());
+
+// for_all(p)
+// {
+// if (v_max < histo(p))
+// {
+// v_max = histo(p);
+// p_max = p.ind();
+// }
+// }
+
+// // Compute the specific stddev
+
+// float stddev_low = 0.0;
+// float stddev_up = 0.0;
+// float stddev = 0.0;
+
+// if (250 > p_max)
+// for (short i = p_max+1; i < p_max+6; ++i)
+// stddev_up += r(p_max, mln::opt::at(histo,p_max),
+// i, mln::opt::at(histo,i));
+
+// if (5 < p_max)
+// for (short i = p_max-1; i > p_max-6; --i)
+// stddev_low += r(p_max, mln::opt::at(histo,p_max),
+// i, mln::opt::at(histo,i));
+
+// stddev = (250 < p_max)? stddev_low : (5 > p_max)? stddev_up :
+// (stddev_low + stddev_up)/2;
+
+// std::cout << "max_site : " << p_max << std::endl;
+// std::cout << "h(max_site) : " << v_max << std::endl;
+// std::cout << "stddev_up : " << stddev_up <<
std::endl;
+// std::cout << "stddev_low : " << stddev_low <<
std::endl;
+// std::cout << "stddev : " << stddev << std::endl;
+
+// return 0;
+// }
+
+
+// -------------------------------------
+// input image <name>.ppm
+// map <name>-<map>.pgm
+// thresholded map <name>-<map>.pbm
+// histogram <name>-<map>.sh
+// decision <name>-<map>.txt
+// -------------------------------------
+// Achromatism <name>-achromatism.pgm
+// call achromatism(input_rgb8, 7, 99.0)
+
+
+/// \brief Decide if an image is achromatic or not [Millet].
+///
+/// \param[in] input_rgb8 the input image.
+/// \param[in] threshold the distance threshold used for equality.
+/// \param[in] percentage the percentage of pixels that very the test.
+///
+/// This is an improving of the Millet test. The original test
+/// compares rgb values to each other and look at differences greater
+/// than the threshold. If the number of pixel that pass the test are
+/// greater than 99.0, then the image is declared achromatic. In fact,
+/// there is few variations between the three channels, so we can say
+/// that it is like a grey image. We can with no too distortions
+/// replace the color image by the grey one. The improving is in first
+/// creating a map of the difference. As we can't keep the free
+/// differences between channels, we look at reducing the test and we
+/// find an equivalent one based on the difference between minima
+/// channel value and the maxima channel value. After the map is
+/// ready, we make binarization with the threshold. Then we compute
+/// the histogram 1d for every pixels of the map that are greater the
+/// threshold. Then, we count pixels in the histogram and traduce the
+/// count in percentage to compare to the second threshold. Details
+/// are saved in files and printed in the screen.
+void achromatism(mln::image2d<mln::value::rgb8> input_rgb8,
+ mln::value::int_u8 threshold,
+ float percentage)
+{
+ typedef mln::fun::v2v::rgb_to_achromatism_map<8> t_rgb_to_achromatism_map;
+
+ mln::image2d<mln::value::int_u8> map;
+ mln::image2d<mln::value::int_u8> view;
+ mln::image2d<bool> mask;
+ mln::image1d<unsigned> histo;
+ unsigned cnt1;
+ unsigned cnt2;
+ float prop;
+ bool result;
+
+
+ map = mln::data::transform(input_rgb8, t_rgb_to_achromatism_map());
+ view = mln::data::stretch(mln::value::int_u8(), map);
+ mask = mln::binarization::threshold(map, threshold);
+ histo = mln::data::compute(mln::accu::meta::stat::histo1d(),
+ map | (mln::pw::value(mask) == true));
+ cnt1 = count_histo(histo);
+ cnt2 = mln::geom::nsites(input_rgb8);
+ prop = (100.0 * (cnt2 - cnt1) / cnt2);
+ result = (prop > percentage);
+
+
+ std::ofstream txt_stream("achromatism.txt");
+ txt_stream << "Achromatism" << std::endl;
+
+ txt_stream << "Nbre pixels : " << cnt2
<< std::endl;
+ txt_stream << "Nbre pixels achromatiques : " <<
(cnt2-cnt1)<< std::endl;
+ txt_stream << "Percentage : " << prop
<< std::endl;
+ txt_stream << "Image achromatique : " << result
<< std::endl;
+ txt_stream << std::endl;
+
+ txt_stream.flush();
+ txt_stream.close();
+
+ mln::io::pgm::save(view, "achromatism.pgm");
+ mln::io::plot::save_image_sh(histo, "achromatism.sh");
+ mln::io::pbm::save(mask, "achromatism.pbm");
+}
+
+
+/// \brief Decide if an image is low saturate or not and so b/w [Millet].
+///
+/// \param[in] input_hsvf the input image in the HSV space.
+/// \param[in] achromatism_mask the mask to prevent computing bad saturation.
+/// \param[in] threshold the distance threshold used for equality.
+/// \param[in] percentage the percentage of pixels that very the test.
+///
+/// As we are in the HSV space, we can just isolate saturation
+/// channel. The original idea of Millet is to build histogram bound
+/// to 256 for the saturation. If a great percentage (95%) of the
+/// population are under a threshold (100), then the image has got low
+/// saturation. So, it is b/w image. Low saturation is sometimes
+/// redundant with the achromatism test but not every time.
+
+// call low_saturation(input_rgb8, achromatism_mask, 100, 95.0)
+void low_saturation(mln::image2d<mln::value::hsv_f> input_hsvf,
+ mln::image2d<bool> achromatism_mask,
+ mln::value::int_u8 threshold,
+ float percentage)
+{
+ typedef mln::value::hsv_f t_hsvf;
+ typedef mln::value::hsv_f::s_type t_sat;
+ typedef mln::fun::v2v::component<t_hsvf,1> t_component_s;
+
+ mln::image2d<t_sat> map;
+ mln::image2d<mln::value::int_u8> view;
+ mln::image2d<bool> mask;
+ mln::image1d<unsigned> histo;
+ unsigned cnt1;
+ unsigned cnt2;
+ float prop;
+ bool result;
+
+
+ map = mln::data::transform(input_hsvf, t_component_s());
+ view = mln::data::stretch(mln::value::int_u8(), map);
+ histo = mln::data::compute(mln::accu::meta::stat::histo1d(),
+ view|(mln::pw::value(achromatism_mask) == true));
+ prop = (100.0 * (cnt2 - cnt1) / cnt2);
+ result = (prop > percentage);
+
+ std::cout << "Saturation" << std::endl;
+
+ cnt1 = count_histo(histo | mln::box1d(mln::point1d(0),mln::point1d(100)));
+ cnt2= mln::geom::nsites(achromatism_mask|
+ (mln::pw::value(achromatism_mask)==false));
+
+ std::ofstream txt_stream("saturation.txt");
+ txt_stream << "Saturation" << std::endl;
+
+ txt_stream << "Nbre pixels : " << cnt2
<< std::endl;
+ txt_stream << "Nbre p faiblement saturés : " << cnt1
<< std::endl;
+ txt_stream << "Pourcentage : " << prop
<< std::endl;
+ txt_stream << "Image faiblement saturé : " << result
<< std::endl;
+ txt_stream << std::endl;
+
+ txt_stream.flush();
+ txt_stream.close();
+
+ mln::io::pgm::save(view, "saturation.pgm");
+ mln::io::plot::save_image_sh(histo, "saturation.sh");
+ mln::io::pbm::save(mask, "saturation.pbm");
+}
+
+/* This is a classification of the ICDAR base in 3 modalities.
+// COLOR
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00032c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00042c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00076c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00082c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00142c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00215c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00228c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00234c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00248c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00252c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00253c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00255c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00259c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00271c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00290c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00293c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00304c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00307c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00376c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00411c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00419c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00447c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00498c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00510c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00550c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00573c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00589c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00592c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00597c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00599c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00600c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00031c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00034c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00043c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00063c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00065c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00072c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00081c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00083c_20p.ppm");
+
+// BLACK AND WHITE
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00329c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00036c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00037c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00039c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00040c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00049c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00055c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00057c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00068c_20p.ppm");
+
+
+// A LITTLE BIT OF COLOR
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00262c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00263c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00311c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00319c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00440c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00608c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00630c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00631c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00028c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00046c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00073c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00089c_20p.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/ta00090c_20p.ppm");
+*/
+
+
+/// \brief The main entry and the whole processing routine
+///
+/// This is the routine which works on Millet test. First compute the
+/// achromatic mask. Then build the transfer between RGB and HSV. Then
+/// isolate each channel to work on it. Each separate channel is bound
+/// between 0 and 255. Then keep only pixels low saturated (< 100 in S
+/// canal) in a specefic map. Build the 3 histograms without the
+/// achromatic pixels based on the 3 separated channels (H/S/V). Build the
+/// 3 maps (hue_concentration, low_saturation and achromatism). Then do
+/// the 3 tests of Millet with the thow thresolded pass (threshold,percentage).
+int main()
+{
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::value::hsv_f t_hsvf;
+ typedef mln::value::hsv_f::h_type t_hue;
+ typedef mln::value::hsv_f::s_type t_sat;
+ typedef mln::value::hsv_f::v_type t_val;
+ typedef mln::image2d<t_hue> t_image2d_hue;
+ typedef mln::image2d<t_sat> t_image2d_sat;
+ typedef mln::image2d<t_val> t_image2d_val;
+ typedef mln::image2d<t_hsvf> t_image2d_hsvf;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<float> t_image2d_float;
+ typedef mln::image1d<unsigned> t_histo1d;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ typedef mln::image2d<bool> t_mask;
+ typedef mln::fun::v2v::f_rgb_to_hsv_f_t t_rgb8_to_hsv;
+ typedef mln::accu::math::count<t_hsvf> t_count;
+ typedef mln::fun::v2v::component<t_hsvf,0> t_component_h;
+ typedef mln::fun::v2v::component<t_hsvf,1> t_component_s;
+ typedef mln::fun::v2v::component<t_hsvf,2> t_component_v;
+ typedef mln::fun::p2b::component_equals<t_image2d_hsvf,0> t_component_eq0;
+ typedef mln::fun::p2b::component_equals<t_image2d_hsvf,1> t_component_eq1;
+ typedef mln::fun::p2b::component_equals<t_image2d_hsvf,2> t_component_eq2;
+ typedef mln::fun::p2b::achromatic<t_rgb8> t_achromatic;
+
+ t_image2d_rgb8 input_rgb8;
+ t_image2d_hsvf input_hsvf;
+
+ t_mask achromatic;
+ t_mask low_saturation;
+
+ t_image2d_float achromatism1;
+ t_image2d_int_u8 achromatism2;
+ t_image2d_float hue_concentration1;
+ t_image2d_int_u8 hue_concentration2;
+
+ t_image2d_hue input_h;
+ t_image2d_hue input_h2;
+ t_image2d_sat input_s;
+ t_image2d_val input_v;
+
+ t_image2d_int_u8 input_h8;
+ t_image2d_int_u8 input_s8;
+ t_image2d_int_u8 input_v8;
+
+ t_histo1d histo_h;
+ t_histo1d histo_s;
+ t_histo1d histo_v;
+
+ unsigned cnt1;
+ unsigned cnt2;
+ float percentage;
+ bool result;
+
+
+
+ // IMAGE LOADING PHASE
+ std::cout << "Image loading phase ..." << std::endl;
+// mln::io::ppm::load(input_rgb8, ANNOTATING_1_BILL_IMG_PATH"/bill03.ppm");
+ mln::io::ppm::load(input_rgb8, ICDAR_20P_PPM_IMG_PATH"/mp00082c_20p.ppm");
+
+
+// achromatism(input_rgb8,7,99.0);
+// exit(-1);
+
+ // REPERAGE DES PIXELS ACHROMATICS
+ std::cout << "Init achromatic mask ..." << std::endl;
+ initialize(achromatic, input_rgb8);
+ mln::data::fill(achromatic, false);
+ mln::data::fill((achromatic | t_achromatic(input_rgb8, 0.03)).rw(), true);
+
+ mln::io::pbm::save(achromatic, "achromatic.pbm");
+
+ std::cout << "Achieve canal forking ..." << std::endl;
+ input_hsvf = mln::data::transform(input_rgb8, t_rgb8_to_hsv());
+ input_h = mln::data::transform(input_hsvf, t_component_h());
+ input_s = mln::data::transform(input_hsvf, t_component_s());
+ input_v = mln::data::transform(input_hsvf, t_component_v());
+
+ // quid of achromatic pixels ???
+ input_h8 = mln::data::stretch(t_int_u8(), input_h);
+ input_s8 = mln::data::stretch(t_int_u8(), input_s);
+ input_v8 = mln::data::stretch(t_int_u8(), input_v);
+
+ // IDENTIFY LOW SATURATED PIXELS
+ std::cout << "Init low saturation mask ..." << std::endl;
+ initialize(low_saturation, input_s8);
+ mln::data::fill(low_saturation, false);
+ mln::data::fill((low_saturation|(mln::pw::value(input_s8) <
+ mln::pw::cst(100u))).rw(), true);
+
+ mln::io::pbm::save(low_saturation, "low_saturation.pbm");
+
+ std::cout << "Compute histograms ..." << std::endl;
+ histo_h = mln::data::compute(mln::accu::meta::stat::histo1d(),
+ input_h8|(mln::pw::value(achromatic)==false));
+
+ histo_s = mln::data::compute(mln::accu::meta::stat::histo1d(),
+ input_s8|(mln::pw::value(achromatic)==false));
+
+ histo_v = mln::data::compute(mln::accu::meta::stat::histo1d(),
+ input_v8|(mln::pw::value(achromatic)==false));
+
+
+ // Study the maps
+ hue_concentration1=mln::data::transform(input_h,
+ mln::fun::v2v::hue_concentration(histo_h));
+ achromatism1=mln::data::transform(input_rgb8,mln::fun::v2v::achromatism());
+
+ hue_concentration2= mln::data::stretch(t_int_u8(), hue_concentration1);
+ achromatism2= mln::data::stretch(t_int_u8(), achromatism1);
+
+ mln::io::pgm::save(achromatism2, "achromatism_map.pgm");
+ mln::io::pgm::save(hue_concentration2, "hue_concentration_map.pgm");
+ mln::io::pgm::save(input_s8, "saturation_map.pgm");
+
+// cnt1 = mln::data::compute(t_count(),
+// (input_hsvf|t_component_eq0(input_hsvf,-1)).rw());
+
+
+ // (I) ACHROMATISM
+ std::cout << "Achromatism" << std::endl;
+ cnt1 = count_histo(histo_h);
+ cnt2 = mln::geom::nsites(input_h);
+
+ percentage = (100.0 * (cnt2 - cnt1) / cnt2);
+ result = percentage > 99.0;
+
+ std::cout << "Nbre pixels : " << cnt2
<< std::endl;
+ std::cout << "Nbre pixels achromatiques : " <<
(cnt2-cnt1)<< std::endl;
+ std::cout << "Percentage : " << percentage
<< std::endl;
+ std::cout << "Image achromatique : " << result
<< std::endl;
+ std::cout << std::endl;
+
+ // (II) LOW SATURATION
+ std::cout << "Saturation" << std::endl;
+
+ cnt1 = count_histo(histo_s | mln::box1d(mln::point1d(0),mln::point1d(100)));
+
+ cnt2= mln::geom::nsites(achromatic | (mln::pw::value(achromatic)==false));
+
+ percentage = (100.0 * cnt1 / cnt2);
+ result = percentage > 95.0;
+
+ std::cout << "Nbre pixels : " << cnt2
<< std::endl;
+ std::cout << "Nbre p faiblement saturés : " << cnt1
<< std::endl;
+ std::cout << "Percentage : " << percentage
<< std::endl;
+ std::cout << "Image faiblement saturé : " << result
<< std::endl;
+ std::cout << std::endl;
+
+ // (III) HIGH HUE CONCENTRATION
+ mln::debug::println(histo_h);
+ unsigned peak = peak_histo(histo_h);
+
+ cnt1 = count_histo(histo_h | mln::box1d(mln::point1d(peak-20),
+ mln::point1d(peak+20)));
+
+ cnt2= count_histo(histo_h);
+
+ percentage = (100.0 * cnt1 / cnt2);
+ result = percentage > 95.0;
+
+ std::cout << "Position du pic : " << peak
<< std::endl;
+ std::cout << "Nbre pixels : " << cnt2
<< std::endl;
+ std::cout << "Nbre pixels proches pic : " << cnt1
<< std::endl;
+ std::cout << "Percentage : " << percentage
<< std::endl;
+ std::cout << "Image fortement teintée : " << result
<< std::endl;
+ std::cout << std::endl;
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
b/scribo/sandbox/green/demo/annotating/lep/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
copy to scribo/sandbox/green/demo/annotating/lep/Makefile.am
diff --git a/scribo/sandbox/green/demo/annotating/lep/lep.cc
b/scribo/sandbox/green/demo/annotating/lep/lep.cc
new file mode 100644
index 0000000..981a369
--- /dev/null
+++ b/scribo/sandbox/green/demo/annotating/lep/lep.cc
@@ -0,0 +1,127 @@
+// 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 Implement the Millet LEP descriptor [millet.phd.2008.pdf]
+///
+/// This is an image descriptor. It works on grey level image. First,
+/// Sobel is applied on the image. Then a specific window is build to
+/// be convolved on the image. The aim of the convolution is to mark
+/// the configuration of the neighbouring for this thresholded image.
+/// Histogram of the configuration is then created and that's all.
+
+#include <iostream>
+
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/binarization/threshold.hh>
+
+#include <mln/core/alias/w_window2d_int.hh>
+#include <mln/core/image/image2d.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/convert.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/debug/println.hh>
+
+#include <mln/fun/v2v/rgb8_to_rgbn.hh>
+
+#include <mln/img_path.hh>
+
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/linear/ch_convolve.hh>
+#include <mln/linear/convolve.hh>
+#include <mln/linear/sobel_2d.hh>
+
+#include <mln/make/w_window2d.hh>
+
+#include <mln/value/rgb.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/value/int_u8.hh>
+
+#include <mln/core/var.hh>
+
+/// \brief Main entry.
+///
+/// Load the pgm image. Threshold it. Identifie the pixel
+/// configuration with specific convolution filter. Build 1d histogram.
+
+int main()
+{
+ using namespace mln;
+
+ typedef mln::w_window2d_int t_win2d;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::value::int_u<9> t_int_u9;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ typedef mln::image2d<t_int_u9> t_image2d_int_u9;
+ typedef mln::image2d<int> t_image2d_int;
+ typedef mln::image2d<unsigned> t_image2d_unsigned;
+ typedef mln::image2d<float> t_image2d_float;
+ typedef mln::image2d<double> t_image2d_double;
+ typedef mln::image2d<bool> t_image2d_bool;
+ typedef mln::image1d<unsigned> t_histo1d;
+ typedef mln::accu::meta::stat::histo1d t_histo1d_fun;
+
+ t_image2d_int_u8 input_int_u8;
+ t_image2d_int input_int;
+ t_image2d_unsigned input_unsigned;
+ t_image2d_float sobel;
+ t_image2d_bool thresh_bool;
+ t_image2d_int_u8 thresh_int_u8;
+ t_image2d_float conf_float;
+ t_image2d_int_u9 conf_int_u9;
+ t_histo1d histo;
+
+ // IMAGE LOADING PHASE
+ std::cout << "Image loading phase ..." << std::endl;
+ mln::io::pgm::load(input_int_u8,ICDAR_50P_PGM_IMG_PATH"/mp00082c_50p.pgm");
+
+ sobel = mln::linear::sobel_2d_l1_norm(input_int_u8);
+
+ //mln::io::plot::save_image_sh(sobel, "sobel.sh");
+ thresh_bool = mln::binarization::threshold(sobel, 100);
+ thresh_int_u8 = mln::data::convert(mln::value::int_u8(), thresh_bool);
+ //mln::io::plot::save_image_sh(thresh, "thresh.sh");
+
+ int ws[] = { 1, 2, 4,
+ 8, 256, 16,
+ 32, 64, 128 };
+
+ t_win2d win2d = mln::make::w_window2d(ws);
+ conf_float = mln::linear::convolve(thresh_int_u8, win2d);
+ conf_int_u9 = mln::data::convert(t_int_u9(), conf_float);
+ histo = mln::data::compute(t_histo1d_fun(), conf_int_u9);
+
+ mln::io::plot::save_image_sh(histo, "histo.sh");
+
+ // PRINTING PHASE
+ mln::debug::println(histo);
+}
diff --git a/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
b/scribo/sandbox/green/demo/annotating/nb_color/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
copy to scribo/sandbox/green/demo/annotating/nb_color/Makefile.am
diff --git a/scribo/sandbox/green/demo/annotating/nb_color/nb_color.cc
b/scribo/sandbox/green/demo/annotating/nb_color/nb_color.cc
new file mode 100644
index 0000000..acc64e9
--- /dev/null
+++ b/scribo/sandbox/green/demo/annotating/nb_color/nb_color.cc
@@ -0,0 +1,143 @@
+// 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 Compute the number of colors in an image.
+///
+/// Build histogram of colors and count the bins different from zero.
+
+#include <iostream>
+#include <sstream>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/math/sum.hh>
+#include <mln/accu/math/count.hh>
+#include <mln/accu/stat/histo3d_rgb.hh>
+#include <mln/accu/stat/mean.hh>
+#include <mln/accu/stat/variance.hh>
+
+#include <mln/algebra/vec.hh>
+
+#include <mln/arith/diff_abs.hh>
+
+#include <mln/core/macros.hh>
+#include <mln/core/alias/neighb3d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/image3d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/core/routine/initialize.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/fill.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/fun/v2v/rgb8_to_rgbn.hh>
+
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/ppm/load.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/labeling/regional_maxima.hh>
+#include <mln/labeling/mean_values.hh>
+#include <mln/labeling/compute.hh>
+
+#include <mln/literal/colors.hh>
+
+#include <mln/morpho/opening/volume.hh>
+#include <mln/morpho/elementary/dilation.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/pw/cst.hh>
+
+#include <mln/util/array.hh>
+#include <mln/util/timer.hh>
+
+#include <mln/value/label_8.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/value/rgb.hh>
+#include <mln/value/int_u.hh>
+
+/// \brief Count the colors.
+///
+/// \param[in] image the name of the image to process.
+///
+/// \return the number of colors.
+///
+/// Count the color by building histogram. Quantification is done to
+/// reduce the size of the histogram.
+///
+/// \fixme: Strange compilation warning, I don't know how to solve it!
+
+// n < 8, n is the degree of quantification
+template <unsigned n>
+unsigned count_image_color(const std::string& image)
+{
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::rgb<n> t_rgbn;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_rgbn> t_image2d_rgbn;
+ typedef mln::image3d<unsigned> t_histo3d;
+ typedef mln::fun::v2v::rgb8_to_rgbn<n> t_rgb8_to_rgbn;
+ typedef mln::accu::meta::stat::histo3d_rgb t_histo3d_fun;
+ typedef mln::accu::meta::math::count t_count_fun;
+
+ t_image2d_rgb8 input_rgb8;
+ t_image2d_rgbn input_rgbn;
+ t_image2d_rgbn output_rgbn;
+ t_histo3d histo;
+ t_histo3d opened;
+
+ mln::io::ppm::load(input_rgb8, image.c_str());
+
+// unsigned nb_pixel = input_rgb8.ncols() * input_rgb8.nrows();
+// unsigned min_volume = (unsigned)(nb_pixel * 0.054);
+ unsigned nb_color = 0;
+
+ input_rgbn = mln::data::transform(input_rgb8, t_rgb8_to_rgbn());
+ histo = mln::data::compute(t_histo3d_fun(), input_rgbn);
+ nb_color = mln::data::compute(t_count_fun(),
+ (histo | (mln::pw::value(histo) != 0)).rw());
+
+ return nb_color;
+}
+
+
+/// \brief Main entry.
+///
+/// Print the number of colors.
+int main()
+{
+ unsigned val=count_image_color<8>(ANNOTATING_1_PHOTO_IMG_PATH
"/photo01.ppm");
+
+ std::cout << "nb color : " << val << std::endl;
+
+ return 0;
+}
+
diff --git a/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
b/scribo/sandbox/green/demo/annotating/project/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
copy to scribo/sandbox/green/demo/annotating/project/Makefile.am
diff --git a/scribo/sandbox/green/demo/annotating/project/project.cc
b/scribo/sandbox/green/demo/annotating/project/project.cc
new file mode 100644
index 0000000..4cab73c
--- /dev/null
+++ b/scribo/sandbox/green/demo/annotating/project/project.cc
@@ -0,0 +1,275 @@
+// 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 Implement the Millet PROJECT descriptor [millet.phd.2008.pdf]
+///
+/// This is an image descriptor. It works a grey level image. First,
+/// we make subsampling of the image to the size 100x100. Then Sobel
+/// is applied. After that, we divide the image in 2 sub-images with
+/// horizontal or vertical splitting. Projection (summing along a
+/// direction) is done in a way that preserves a vector of size
+/// 100. Finally, it results 4 vector of size 100 which are concatened
+/// to build the descriptor.
+
+#include <iostream>
+#include <sstream>
+
+#include <mln/accu/image/init.hh>
+#include <mln/accu/image/take.hh>
+#include <mln/accu/image/to_result.hh>
+#include <mln/accu/stat/mean.hh>
+
+#include <mln/binarization/threshold.hh>
+
+#include <mln/core/alias/box2d.hh>
+#include <mln/core/alias/point2d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/core/routine/initialize.hh>
+#include <mln/core/image/dmorph/unproject_image.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/convert.hh>
+#include <mln/data/paste.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/debug/println.hh>
+
+#include <mln/fun/v2v/projection.hh>
+
+#include <mln/img_path.hh>
+
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/pbm/save.hh>
+
+#include <mln/linear/sobel_2d.hh>
+
+#include <mln/opt/at.hh>
+
+/// \brief get the sub-image name.
+///
+/// \param[in] base the common part of the name.
+/// \param[in] i the column.
+/// \param[in] j the line.
+///
+/// \result the complete name of the sub-image.
+///
+/// This function builds the complete name of a sub-image by making
+/// explicit its position in the array.
+const char *get_name(const char *base, const unsigned i, const unsigned j)
+{
+ std::ostringstream name;
+
+ name << base;
+ name << i;
+ name << "_";
+ name << j;
+ name << ".ppm";
+
+ return name.str().c_str();
+}
+
+
+/// \brief Project row data.
+///
+/// \param[in] img the binary image converted to u_int8.
+///
+/// \ return a vector.
+///
+/// This routine "eats" one dimension of the image by making a
+/// projection. The projection sums the pixel along a specific
+/// direction. It results a vector.
+mln::image1d<mln::value::int_u8>
+project_row(const mln::image2d<mln::value::int_u8>& img)
+{
+ typedef mln::accu::math::sum<mln::value::int_u8,mln::value::int_u8> t_sum;
+ typedef mln::fun::v2v::projection<mln::point2d,0> t_projection;
+
+ mln::image1d<t_sum> img_accu(img.ncols());
+
+ mln::accu::image::init(img_accu);
+
+ mln::accu::image::take(unproject(img_accu,
+ img.domain(),
+ t_projection()).rw(),
+ img);
+
+ return mln::accu::image::to_result(img_accu);
+}
+
+
+/// \brief Project column data.
+///
+/// \param[in] img the binary image converted to u_int8.
+///
+/// \ return a vector.
+///
+/// This routine "eats" one dimension of the image by making a
+/// projection. The projection sums the pixel along a specific
+/// direction. It results a vector.
+mln::image1d<mln::value::int_u8>
+project_col(const mln::image2d<mln::value::int_u8>& img)
+{
+ typedef mln::accu::math::sum<mln::value::int_u8,mln::value::int_u8> t_sum;
+ typedef mln::fun::v2v::projection<mln::point2d,1> t_projection;
+
+ mln::image1d<t_sum> img_accu(img.nrows());
+
+ mln::accu::image::init(img_accu);
+
+ mln::accu::image::take(unproject(img_accu,
+ img.domain(),
+ t_projection()).rw(),
+ img);
+
+ return mln::accu::image::to_result(img_accu);
+}
+
+
+/// \brief The image processing routine.
+///
+/// Describe the processing chain. First subsample the input image to
+/// 100x100. This is done by splitting the image and then compute the
+/// mean of the subimage. The result is a pixel of the subsample
+/// image. Then apply Sobel and threshold. Then split in two
+/// (vertically or horizontally), it results 4 images. Finally, make
+/// the projection.
+int main()
+{
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::algebra::vec<3,float> t_vec3f;
+ typedef mln::algebra::vec<3,unsigned> t_vec3u;
+ typedef mln::image2d<float> t_image2d_float;
+ typedef mln::image2d<bool> t_image2d_bool;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ typedef mln::accu::meta::stat::mean t_mean_fun;
+ typedef mln::accu::math::sum<t_int_u8,t_int_u8> t_sum;
+ typedef mln::image1d<t_int_u8> t_image1d_int_u8;
+
+ t_image2d_int_u8 input_int_u8;
+ t_image2d_float sobel;
+ t_image2d_bool thresh_bool;
+ t_image2d_int_u8 thresh_int_u8;
+
+ // IMAGE LOADING PHASE
+ std::cout << "Image loading phase ..." << std::endl;
+ mln::io::pgm::load(input_int_u8,ICDAR_50P_PGM_IMG_PATH"/mp00082c_50p.pgm");
+
+
+ // IMAGE SPLITTING PHASE
+ t_image2d_int_u8 subimg_int_u8(mln::box2d(mln::point2d(0,0),
+ mln::point2d(100,100)));
+
+ mln::box2d domain = input_int_u8.domain();
+ mln::point2d pmin = domain.pmin();
+ mln::point2d pmax = domain.pmax();
+
+ unsigned sz_row = (pmax.row() - pmin.row())/ 100;
+ unsigned sz_col = (pmax.col() - pmin.col())/ 100;
+
+ std::cout << domain << std::endl;
+
+ // Subsampling in 100x100
+ // FIXME Test that is it a subsampling, not a upsampling!
+ for (unsigned i = 0; i < 100; ++i)
+ for (unsigned j = 0; j < 100; ++j)
+ {
+ mln::point2d min(pmin.row()+sz_row*i,pmin.col()+sz_col*j);
+ mln::point2d max(pmin.row()+sz_row*(i+1),pmin.col()+sz_col*(j+1));
+ mln::box2d dom(min,max);
+
+ std::cout << dom << std::endl;
+
+ // Save it
+ t_image2d_int_u8 input_part_int_u8(dom);
+
+ mln::data::paste(input_int_u8 | dom, input_part_int_u8);
+ //mln::io::pgm::save(input_part_int_u8, get_name("output",i,j));
+ float mean = mln::data::compute(t_mean_fun(), input_part_int_u8);
+ t_int_u8 val = static_cast<t_int_u8>(mean);
+ mln::opt::at(subimg_int_u8, i,j) = val;
+ }
+
+ mln::io::pgm::save(subimg_int_u8, "subimg.pgm");
+
+ sobel = mln::linear::sobel_2d_l1_norm(subimg_int_u8);
+ thresh_bool = mln::binarization::threshold(sobel, 100);
+ thresh_int_u8 = mln::data::convert(t_int_u8(), thresh_bool);
+
+ mln::io::pbm::save(thresh_bool, "subimg.pbm");
+
+ // Define img_up, img_down, img_left, img_right
+ t_image2d_int_u8 img_up(mln::box2d(mln::point2d(0,0),
+ mln::point2d(49,99)));
+
+ mln::data::paste(thresh_int_u8 | img_up.domain(), img_up);
+
+
+ t_image2d_int_u8 img_down(mln::box2d(mln::point2d(50,0),
+ mln::point2d(99,99)));
+
+ mln::data::paste(thresh_int_u8 | img_down.domain(), img_down);
+
+ t_image2d_int_u8 img_left(mln::box2d(mln::point2d(0,0),
+ mln::point2d(99,49)));
+
+ mln::data::paste(thresh_int_u8 | img_left.domain(), img_left);
+
+
+ t_image2d_int_u8 img_right(mln::box2d(mln::point2d(0,50),
+ mln::point2d(99,99)));
+
+ mln::data::paste(thresh_int_u8 | img_right.domain(), img_right);
+
+
+ // Define project_up, project_down, project_left, project_right
+ t_image1d_int_u8 project_up = project_row(img_up);
+ t_image1d_int_u8 project_down = project_row(img_down);
+ t_image1d_int_u8 project_left = project_col(img_left);
+ t_image1d_int_u8 project_right = project_col(img_right);
+
+ mln::io::pgm::save(img_up, "up.pgm");
+ mln::io::pgm::save(img_down, "down.pgm");
+ mln::io::pgm::save(img_left, "left.pgm");
+ mln::io::pgm::save(img_right, "right.pgm");
+
+ // PRINTING PHASE
+
+ std::cout << std::endl << "UP" << std::endl;
+ mln::debug::println(project_up);
+
+ std::cout << std::endl << "DOWN" << std::endl;
+ mln::debug::println(project_down);
+
+ std::cout << std::endl << "LEFT" << std::endl;
+ mln::debug::println(project_left);
+
+ std::cout << std::endl << "RIGHT" << std::endl;
+ mln::debug::println(project_right);
+}
diff --git a/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
b/scribo/sandbox/green/demo/annotating/rgb_64/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
copy to scribo/sandbox/green/demo/annotating/rgb_64/Makefile.am
diff --git a/scribo/sandbox/green/demo/annotating/rgb_64/rgb_64.cc
b/scribo/sandbox/green/demo/annotating/rgb_64/rgb_64.cc
new file mode 100644
index 0000000..b49f979
--- /dev/null
+++ b/scribo/sandbox/green/demo/annotating/rgb_64/rgb_64.cc
@@ -0,0 +1,80 @@
+// 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 Implement the Millet RGB-64 descriptor [millet.phd.2008.pdf]
+///
+/// This is an image descriptor. It works by making 2 bits
+/// quantification on each channel. It result a processing in RGB-64
+/// space. Then we build the color histogram.
+
+#include <iostream>
+
+#include <mln/accu/stat/histo3d_rgb.hh>
+
+#include <mln/core/image/image2d.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/debug/println.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>
+
+/// \brief Main entry.
+///
+/// Loading, Quantifiying in two bits each channel, then building
+/// color histogram.
+int main()
+{
+ typedef mln::fun::v2v::rgb8_to_rgbn<2> t_rgb8_to_rgb2;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::rgb<2> t_rgb2;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_rgb2> t_image2d_rgb2;
+ typedef mln::image3d<unsigned> t_histo3d;
+ typedef mln::accu::meta::stat::histo3d_rgb t_histo3d_fun;
+
+ t_image2d_rgb8 input_rgb8;
+ t_image2d_rgb2 input_rgb2;
+ t_histo3d histo;
+
+ // IMAGE LOADING PHASE
+ std::cout << "Image loading phase ..." << std::endl;
+ mln::io::ppm::load(input_rgb8, ICDAR_50P_PPM_IMG_PATH"/mp00082c_50p.ppm");
+ input_rgb2 = mln::data::transform(input_rgb8, t_rgb8_to_rgb2());
+ histo = mln::data::compute(t_histo3d_fun(), input_rgb2);
+
+ // PRINTING PHASE
+ mln::debug::println(histo);
+}
diff --git a/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
b/scribo/sandbox/green/demo/annotating/rgb_64_9/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
copy to scribo/sandbox/green/demo/annotating/rgb_64_9/Makefile.am
diff --git a/scribo/sandbox/green/demo/annotating/rgb_64_9/rgb_64_9.cc
b/scribo/sandbox/green/demo/annotating/rgb_64_9/rgb_64_9.cc
new file mode 100644
index 0000000..355cbfd
--- /dev/null
+++ b/scribo/sandbox/green/demo/annotating/rgb_64_9/rgb_64_9.cc
@@ -0,0 +1,132 @@
+// 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 Implement the Millet RGB-64 descriptor [millet.phd.2008.pdf]
+///
+/// This is an image descriptor. It works by making 2 bits
+/// quantification on each channel. It result a processing in RGB-64
+/// space. Then we build the color histogram.
+
+#include <iostream>
+#include <sstream>
+
+#include <mln/accu/stat/histo3d_rgb.hh>
+
+#include <mln/core/alias/box2d.hh>
+#include <mln/core/alias/point2d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/core/routine/initialize.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/paste.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/debug/println.hh>
+
+#include <mln/fun/v2v/rgb8_to_rgbn.hh>
+
+#include <mln/img_path.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/ppm/save.hh>
+
+#include <mln/value/rgb.hh>
+#include <mln/value/rgb8.hh>
+
+/// \brief Get the sub image name.
+///
+/// \return the name of the ith/jth sub image of the array.
+const char *get_name(const char *base, const unsigned i, const unsigned j)
+{
+ std::ostringstream name;
+
+ name << base;
+ name << i;
+ name << "_";
+ name << j;
+ name << ".ppm";
+
+ return name.str().c_str();
+}
+
+/// \brief Same code as rgb-64 but divide the wall image in nine.
+///
+/// Adding a splitting phase for image rgb-64 code reference.
+int main()
+{
+ typedef mln::fun::v2v::rgb8_to_rgbn<2> t_rgb8_to_rgb2;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::rgb<2> t_rgb2;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_rgb2> t_image2d_rgb2;
+ typedef mln::image3d<unsigned> t_histo3d;
+ typedef mln::accu::meta::stat::histo3d_rgb t_histo3d_fun;
+
+ t_image2d_rgb8 input_rgb8;
+ t_image2d_rgb2 input_rgb2;
+ t_histo3d histo;
+
+ // IMAGE LOADING PHASE
+ std::cout << "Image loading phase ..." << std::endl;
+ mln::io::ppm::load(input_rgb8, ICDAR_50P_PPM_IMG_PATH"/mp00082c_50p.ppm");
+
+ input_rgb2 = mln::data::transform(input_rgb8, t_rgb8_to_rgb2());
+
+ // IMAGE SPLITTING PHASE
+ mln::box2d domain = input_rgb2.domain();
+ mln::point2d pmin = domain.pmin();
+ mln::point2d pmax = domain.pmax();
+
+ unsigned sz_row = (pmax.row() - pmin.row())/ 3;
+ unsigned sz_col = (pmax.col() - pmin.col())/ 3;
+
+ std::cout << domain << std::endl;
+
+ // Divide the domain in nine sub-domains.
+ for (unsigned i = 0; i < 3; ++i)
+ for (unsigned j = 0; j < 3; ++j)
+ {
+ mln::point2d min(pmin.row()+sz_row*i,pmin.col()+sz_col*j);
+ mln::point2d max(pmin.row()+sz_row*(i+1),pmin.col()+sz_col*(j+1));
+ mln::box2d dom(min,max);
+
+ std::cout << dom << std::endl;
+
+ // Save it
+ t_image2d_rgb2 input_1o9_rgb2(dom);
+
+ mln::data::paste(input_rgb2 | dom, input_1o9_rgb2);
+ mln::io::ppm::save(input_1o9_rgb2, get_name("output",i,j));
+
+ histo = mln::data::compute(t_histo3d_fun(), input_1o9_rgb2);
+
+ // PRINTING PHASE
+ mln::debug::println(histo);
+ }
+
+}
diff --git a/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
b/scribo/sandbox/green/demo/annotating/stddev_color/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
copy to scribo/sandbox/green/demo/annotating/stddev_color/Makefile.am
diff --git a/scribo/sandbox/green/demo/annotating/stddev_color/stddev_color.cc
b/scribo/sandbox/green/demo/annotating/stddev_color/stddev_color.cc
new file mode 100644
index 0000000..549834f
--- /dev/null
+++ b/scribo/sandbox/green/demo/annotating/stddev_color/stddev_color.cc
@@ -0,0 +1,191 @@
+// 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 Implement the Millet clipart detection [millet.phd.2008.pdf]
+///
+/// The aim of this descriptor is to recognize clipart. To do this, we
+/// assume that clipart have their histogram concentrated around their
+/// mode. This is particularly true if the clipart is design by hand,
+/// because a very small number of grey tones or colors are used to
+/// draw it. But sometimes, computer assists their creation and we can
+/// find some continuous set of tones and this artefact create noise
+/// for the detection technique describe bellow.
+
+#include <iostream>
+#include <sstream>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/max_site.hh>
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/core/macros.hh>
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/image3d.hh>
+
+#include <mln/debug/println.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/fill.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/fun/v2v/rgb8_to_int_u8.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/math/sqr.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/int_u.hh>
+
+
+
+/// \brief The R function of Millet
+///
+/// \param[in] p the position of the pic.
+/// \param[in] histo_p the histo value of the pic.
+/// \param[in] x the position of the element which we compute the contrib.
+/// \param[in] histo_x the histo value of that element.
+///
+/// \result the contribution of the element x.
+///
+/// This function compute the variance-like contribution of an element
+/// x linked to the pic of the histogram. In fact, every thing is like
+/// we compute a square distance-like between the element x and the
+/// pic in the normalized histogram. Notice that the normalized
+/// histogram is the histogram divide by the value of it's pic. So at
+/// the pic, the value equals 1. It's a current representation of the
+/// histogram in image processing, we can find it in gimp for exemple.
+float r(short p, unsigned histo_p, short x, unsigned histo_x)
+{
+ float result = mln::math::sqr(((float)histo_x / histo_p) * (x-p));
+
+ return result;
+}
+
+/// Brief compute the whole deviation of Millet
+///
+/// \param[in] image the input image to analyze.
+///
+/// \return the deviation.
+///
+/// The deviation uses the R function. It stats by finding the pic. If
+/// the pic is near the rigth border of the histo, compute the R
+/// function on the left neighbouring of the pic. If the pic is near
+/// the left border of the histo, compute the R function on the right
+/// neigbouring. Otherwise, compute the average of the right and left
+/// results. The selected neighbouring is composed of five pixels at
+/// the right or at the left of the pic. The detection of clipart
+/// assumes that the majority of the energy of the histogram is closed
+/// to the pic (five pixels around it).
+unsigned stddev_color(const std::string& image)
+{
+ typedef mln::point1d t_point1d;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ typedef mln::image1d<unsigned> t_histo1d;
+ typedef mln::fun::v2v::rgb8_to_int_u8 t_rgb8_to_int_u8;
+ typedef mln::accu::meta::stat::histo1d t_histo1d_fun;
+ typedef mln::accu::max_site<t_histo1d> t_max_site_fun;
+
+ t_image2d_rgb8 input_rgb8;
+ t_image2d_int_u8 input_int_u8;
+ t_histo1d histo;
+ t_point1d max_site;
+
+ mln::io::ppm::load(input_rgb8, image.c_str());
+ input_int_u8 = mln::data::transform(input_rgb8, t_rgb8_to_int_u8());
+ histo = mln::data::compute(t_histo1d_fun(), input_int_u8);
+
+ mln::io::pgm::save(input_int_u8, "tmp.pgm");
+ mln::io::plot::save_image_sh(histo, "histo.sh");
+ mln::debug::println(histo);
+
+ // Find the peak of the histogram
+ unsigned v_max = mln::opt::at(histo, 0);
+ short p_max = 0;
+
+ mln_piter_(t_histo1d) p(histo.domain());
+
+ for_all(p)
+ {
+ if (v_max < histo(p))
+ {
+ v_max = histo(p);
+ p_max = p.ind();
+ }
+ }
+
+ // Compute the specific stddev
+
+ float stddev_low = 0.0;
+ float stddev_up = 0.0;
+ float stddev = 0.0;
+
+ if (250 > p_max)
+ for (short i = p_max+1; i < p_max+6; ++i)
+ stddev_up += r(p_max, mln::opt::at(histo,p_max),
+ i, mln::opt::at(histo,i));
+
+ if (5 < p_max)
+ for (short i = p_max-1; i > p_max-6; --i)
+ stddev_low += r(p_max, mln::opt::at(histo,p_max),
+ i, mln::opt::at(histo,i));
+
+ stddev = (250 < p_max)? stddev_low : (5 > p_max)? stddev_up :
+ (stddev_low + stddev_up)/2;
+
+ std::cout << "max_site : " << p_max << std::endl;
+ std::cout << "h(max_site) : " << v_max << std::endl;
+ std::cout << "stddev_up : " << stddev_up << std::endl;
+ std::cout << "stddev_low : " << stddev_low << std::endl;
+ std::cout << "stddev : " << stddev << std::endl;
+
+ return 0;
+}
+
+
+/// \brief Main entry.
+///
+/// Front end for image processing.
+int main()
+{
+// unsigned val = stdev_color(ANNOTATING_1_PHOTO_IMG_PATH "/photo01.ppm");
+ unsigned val = stddev_color(ANNOTATING_1_LOGO_IMG_PATH "/logo06.ppm");
+
+// std::cout << "nb color : " << val << std::endl;
+
+ return 0;
+}
+
diff --git a/scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
b/scribo/sandbox/green/demo/annotating/stddev_color_16/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/demo/clustering/kmean1d/Makefile.am
copy to scribo/sandbox/green/demo/annotating/stddev_color_16/Makefile.am
diff --git a/scribo/sandbox/green/demo/annotating/stddev_color_16/stddev_color_16.cc
b/scribo/sandbox/green/demo/annotating/stddev_color_16/stddev_color_16.cc
new file mode 100644
index 0000000..98d94fd
--- /dev/null
+++ b/scribo/sandbox/green/demo/annotating/stddev_color_16/stddev_color_16.cc
@@ -0,0 +1,261 @@
+// 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 Implement the Millet clipart detection [millet.phd.2008.pdf]
+///
+/// The aim of this descriptor is to recognize clipart. To do this, we
+/// assume that clipart have their histogram concentrated around their
+/// mode. This is particularly true if the clipart is design by hand,
+/// because a very small number of grey tones or colors are used to
+/// draw it. But sometimes, computer assists their creation and we can
+/// find some continuous set of tones and this artefact create noise
+/// for the detection technique describe bellow. When photographies
+/// has some large uniform border, the detection can fail. To improve
+/// the method, Millet decide to subdivise the image in 16 sub images
+/// on which it applies the test.
+#include <iostream>
+#include <sstream>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/max_site.hh>
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/core/macros.hh>
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/image3d.hh>
+
+#include <mln/debug/println.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/fill.hh>
+#include <mln/data/transform.hh>
+#include <mln/data/paste.hh>
+
+#include <mln/fun/v2v/rgb8_to_int_u8.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/math/sqr.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/int_u.hh>
+
+
+/// \brief The R function of Millet
+///
+/// \param[in] p the position of the pic.
+/// \param[in] histo_p the histo value of the pic.
+/// \param[in] x the position of the element which we compute the contrib.
+/// \param[in] histo_x the histo value of that element.
+///
+/// \result the contribution of the element x.
+///
+/// This function compute the variance-like contribution of an element
+/// x linked to the pic of the histogram. In fact, every thing is like
+/// we compute a square distance-like between the element x and the
+/// pic in the normalized histogram. Notice that the normalized
+/// histogram is the histogram divide by the value of it's pic. So at
+/// the pic, the value equals 1. It's a current representation of the
+/// histogram in image processing, we can find it in gimp for exemple.
+float r(short p, unsigned histo_p, short x, unsigned histo_x)
+{
+ float result = mln::math::sqr(((float)histo_x / histo_p) * (x-p));
+
+ return result;
+}
+
+/// Brief compute the whole deviation of Millet
+///
+/// \param[in] input_int_u8 the 8 bits input image to analyze.
+/// \param[in] name_histo the name of the output histogram.
+/// \param[in] name_image the name of the ouput sub image.
+///
+/// \return the deviation, but at this time nothing..
+///
+/// The deviation uses the R function. It stats by finding the pic. If
+/// the pic is near the rigth border of the histo, compute the R
+/// function on the left neighbouring of the pic. If the pic is near
+/// the left border of the histo, compute the R function on the right
+/// neigbouring. Otherwise, compute the average of the right and left
+/// results. The selected neighbouring is composed of five pixels at
+/// the right or at the left of the pic. The detection of clipart
+/// assumes that the majority of the energy of the histogram is closed
+/// to the pic (five pixels around it).
+unsigned stddev_color(mln::image2d<mln::value::int_u8> input_int_u8,
+ const char *name_histo,
+ const char *name_image)
+{
+ typedef mln::point1d t_point1d;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ typedef mln::image1d<unsigned> t_histo1d;
+ typedef mln::fun::v2v::rgb8_to_int_u8 t_rgb8_to_int_u8;
+ typedef mln::accu::meta::stat::histo1d t_histo1d_fun;
+ typedef mln::accu::max_site<t_histo1d> t_max_site_fun;
+
+ t_histo1d histo;
+
+ std::cout << "histo : " << name_histo << std::endl;
+ std::cout << "image : " << name_image << std::endl;
+
+ histo = mln::data::compute(t_histo1d_fun(), input_int_u8);
+
+ mln::io::pgm::save(input_int_u8, name_image);
+ mln::io::plot::save_image_sh(histo, name_histo);
+ mln::debug::println(histo);
+
+ // Find the peak of the histogram
+ unsigned v_max = mln::opt::at(histo, 0);
+ short p_max = 0;
+
+ mln_piter_(t_histo1d) p(histo.domain());
+
+ for_all(p)
+ {
+ if (v_max < histo(p))
+ {
+ v_max = histo(p);
+ p_max = p.ind();
+ }
+ }
+
+ // Compute the specific stddev
+
+ float stddev_low = 0.0;
+ float stddev_up = 0.0;
+ float stddev = 0.0;
+
+ if (250 > p_max)
+ for (short i = p_max+1; i < p_max+6; ++i)
+ stddev_up += r(p_max, mln::opt::at(histo,p_max),
+ i, mln::opt::at(histo,i));
+
+ if (5 < p_max)
+ for (short i = p_max-1; i > p_max-6; --i)
+ stddev_low += r(p_max, mln::opt::at(histo,p_max),
+ i, mln::opt::at(histo,i));
+
+ stddev = (250 < p_max)? stddev_low : (5 > p_max)? stddev_up :
+ (stddev_low + stddev_up)/2;
+
+ std::cout << "max_site : " << p_max << std::endl;
+ std::cout << "h(max_site) : " << v_max << std::endl;
+ std::cout << "stddev_up : " << stddev_up << std::endl;
+ std::cout << "stddev_low : " << stddev_low << std::endl;
+ std::cout << "stddev : " << stddev << std::endl;
+
+ return 0;
+}
+
+
+/// \brief Divide the image in 16 sub images.
+///
+/// \param[in] image the input image.
+///
+/// \result nothing.
+///
+/// Divive the input image in 16 by uniform and geometrical
+/// method. When a sub image is ready, call the stddev routine to show
+/// stats on it.
+unsigned stddev_color_16(const std::string& image)
+{
+ typedef mln::point1d t_point1d;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ typedef mln::image1d<unsigned> t_histo1d;
+ typedef mln::fun::v2v::rgb8_to_int_u8 t_rgb8_to_int_u8;
+ typedef mln::accu::meta::stat::histo1d t_histo1d_fun;
+ typedef mln::accu::max_site<t_histo1d> t_max_site_fun;
+
+ t_image2d_rgb8 input_rgb8;
+ t_image2d_int_u8 input_int_u8;
+
+ mln::io::ppm::load(input_rgb8, image.c_str());
+ input_int_u8 = mln::data::transform(input_rgb8, t_rgb8_to_int_u8());
+
+ // IMAGE SPLITTING PHASE
+ mln::box2d domain = input_int_u8.domain();
+ mln::point2d pmin = domain.pmin();
+ mln::point2d pmax = domain.pmax();
+
+ unsigned sz_row = (pmax.row() - pmin.row())/ 4;
+ unsigned sz_col = (pmax.col() - pmin.col())/ 4;
+
+ std::cout << domain << std::endl;
+
+ // Divide the domain in nine sub-domains.
+ for (unsigned i = 0; i < 4; ++i)
+ for (unsigned j = 0; j < 4; ++j)
+ {
+ mln::point2d min(pmin.row()+sz_row*i,pmin.col()+sz_col*j);
+ mln::point2d max(pmin.row()+sz_row*(i+1),pmin.col()+sz_col*(j+1));
+ mln::box2d dom(min,max);
+
+ std::cout << dom << std::endl;
+
+ // Save it
+ t_image2d_int_u8 input_1o16_int_u8(dom);
+ std::ostringstream name_histo("");
+ std::ostringstream name_image("");
+
+ name_histo << "histo" << i << "_" << j
<< ".sh";
+ name_image << "image" << i << "_" << j
<< ".ppm";
+
+ mln::data::paste(input_int_u8 | dom, input_1o16_int_u8);
+
+ stddev_color(input_1o16_int_u8,
+ name_histo.str().c_str(),
+ name_image.str().c_str());
+ }
+
+ return 0;
+}
+
+
+/// \brief Main entry.
+///
+/// Just a front end for image processing routine.
+int main()
+{
+// unsigned val = stddev_color_16(ANNOTATING_1_PHOTO_IMG_PATH
"/photo01.ppm");
+ unsigned val = stddev_color_16(ANNOTATING_1_LOGO_IMG_PATH "/logo06.ppm");
+
+// std::cout << "nb color : " << val << std::endl;
+
+ return 0;
+}
+
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/achromastism/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/achromastism/Makefile.am
diff --git a/scribo/sandbox/green/exp/annotating/achromastism/achromastism.cc
b/scribo/sandbox/green/exp/annotating/achromastism/achromastism.cc
new file mode 100644
index 0000000..3486b20
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/achromastism/achromastism.cc
@@ -0,0 +1,179 @@
+// 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 Implement the Millet achromatism operator [millet.phd.2008.pdf]
+///
+/// An image is said to be achromatic when have the RGB channel which
+/// are quite identicals.
+
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/stretch.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/math/max.hh>
+#include <mln/math/min.hh>
+
+#include <mln/geom/nsites.hh>
+
+#include <mln/fun/v2v/rgb_to_achromatism_map.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/value/rgb8.hh>
+
+
+/// \brief Sum all the bins of the histogram.
+///
+/// \param[in] img the histogram based on image.
+///
+/// \return the sum of the overall bins.
+///
+/// Sum evry bins and return the result.
+template <typename I>
+unsigned count_histo(const mln::Image<I>& img_)
+{
+ const I& img = exact(img_);
+
+ mln_precondition(img.is_valid());
+
+ unsigned result = 0;
+
+ mln_piter(I) p(img.domain());
+
+ for_all(p)
+ result += img(p);
+
+ return result;
+}
+
+/// \brief Decide if an image is achromatic or not [Millet].
+///
+/// \param[in] input the input image.
+/// \param[in] output the histogram of the achromatic map.
+/// \param[in] threshold the distance threshold used for equality.
+///
+/// This is an improving of the Millet test. The original test
+/// compares rgb values to each other and look at differences greater
+/// than the threshold. If the number of pixel that pass the test are
+/// greater than 99.0, then the image is declared achromatic. In fact,
+/// there is few variations between the three channels, so we can say
+/// that it is like a grey image. We can with no too distortions
+/// replace the color image by the grey one. The improving is in first
+/// creating a map of the difference. As we can't keep the free
+/// differences between channels, we look at reducing the test and we
+/// find an equivalent one based on the difference between minima
+/// channel value and the maxima channel value. After the map is
+/// ready, we make binarization with the threshold. Then we compute
+/// the histogram 1d for every pixels of the map that are greater the
+/// threshold. Then, we count pixels in the histogram and traduce the
+/// count in percentage to compare to the second threshold. Details
+/// are saved in files and printed in the screen.
+float achromatism_test(const std::string input,
+ const std::string output,
+ const unsigned threshold)
+
+{
+ typedef mln::fun::v2v::rgb_to_achromatism_map<8> t_rgb_to_achromatism_map;
+
+ mln::image2d<mln::value::rgb8> input_rgb8;
+ mln::image2d<mln::value::int_u8> map;
+ mln::image1d<unsigned> histo;
+ unsigned cnt1;
+ unsigned cnt2;
+ float prop;
+
+ mln::io::ppm::load(input_rgb8, input.c_str());
+
+ map = mln::data::transform(input_rgb8, t_rgb_to_achromatism_map());
+ histo = mln::data::compute(mln::accu::meta::stat::histo1d(), map);
+ cnt1 = count_histo(histo | mln::box1d(mln::point1d(0),
+ mln::point1d(threshold)));
+ cnt2 = mln::geom::nsites(input_rgb8);
+ prop = ((100.0 * cnt1) / cnt2);
+
+ mln::io::plot::save_image_sh(histo, output.c_str());
+
+ return prop;
+}
+
+
+/// \brief The main entry.
+///
+/// Deal with boost library for walking over image database
+/// directories. Call the image processing routine and compute some
+/// stats on the result.
+int main()
+{
+ typedef boost::filesystem::path t_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+
+ t_path full_path[] = {t_path(ICDAR_20P_PPM_IMG_PATH)};
+
+ for (int i = 0; i < 1; ++i)
+ {
+ std::cout << "entering " << full_path[i] << std::endl;
+
+ if (boost::filesystem::exists(full_path[i]) &&
+ boost::filesystem::is_directory(full_path[i]))
+ {
+ boost::filesystem::system_complete(full_path[i]);
+ const t_iter_path end_iter;
+ float prop = 0.0;
+
+ for (t_iter_path dir_iter(full_path[i]); end_iter != dir_iter; ++dir_iter)
+ {
+ // concatenation de chaine
+ t_path directory(ANNOTATING_RET_PATH);
+ t_path leaf = dir_iter->path().leaf();
+ t_path output = change_extension(directory / leaf, ".sh");
+
+ prop = achromatism_test(dir_iter->path().string(),
+ output.string(),
+ 11);
+
+ std::cout << output << " : " << prop << std::endl;
+ std::cerr << output << " : " << prop << std::endl;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-color.txt
b/scribo/sandbox/green/exp/annotating/achromastism/text-color.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-color.txt
copy to scribo/sandbox/green/exp/annotating/achromastism/text-color.txt
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-img.txt
b/scribo/sandbox/green/exp/annotating/achromastism/text-img.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-img.txt
copy to scribo/sandbox/green/exp/annotating/achromastism/text-img.txt
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-only.txt
b/scribo/sandbox/green/exp/annotating/achromastism/text-only.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-only.txt
copy to scribo/sandbox/green/exp/annotating/achromastism/text-only.txt
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/bench/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/bench/Makefile.am
diff --git a/scribo/sandbox/green/exp/annotating/bench/bench.cc
b/scribo/sandbox/green/exp/annotating/bench/bench.cc
new file mode 100644
index 0000000..102a896
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/bench/bench.cc
@@ -0,0 +1,1450 @@
+// 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
+///
+/// This file is the final work to differentiate between the two image
+/// databases AFP and ICDAR. Several tests are used to show
+/// improvement of detection. The jonathan's tests are put together to
+/// compare them to the others (in fact, to the low saturation one).
+
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/algebra/vec.hh>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/stat/mean.hh>
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/arith/minus.hh>
+#include <mln/arith/times.hh>
+#include <mln/arith/diff_abs.hh>
+#include <mln/arith/div.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/core/alias/point1d.hh>
+#include <mln/core/alias/box1d.hh>
+
+#include <mln/data/transform.hh>
+#include <mln/data/compute.hh>
+#include <mln/data/convert.hh>
+#include <mln/data/stretch.hh>
+#include <mln/data/fill.hh>
+
+#include <mln/fun/v2v/component.hh>
+#include <mln/fun/v2v/rgb_to_hue_map.hh>
+#include <mln/fun/v2v/rgb_to_saturation_map.hh>
+#include <mln/fun/v2v/rgb_to_value_map.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/literal/zero.hh>
+
+#include <mln/math/ceil.hh>
+#include <mln/math/floor.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/trait/value_.hh>
+
+#include <mln/value/rgb8.hh>
+
+
+#include <mln/value/int_u8.hh>
+
+/// Histogram part.
+///
+/// We regroup here the routines that work on histogram, count_histo,
+/// sum_frequency_histo, peak_histo, count_null_frequency_histo,
+/// cmp_equi_frequency_histo and others (variance
+/// operators). count_histo and sum_frequency_histo count the overall
+/// frequency in the domain. peak_histo find the peak of the
+/// histogram. count_null_frequency_histo compute the number of non
+/// grey levels. cmp_equi_frequency_histo compare a histogram with
+/// the one with the same frequency everywhere.
+/// \{
+template <typename I>
+mln_value(I) count_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) result = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ result += histo(p);
+
+ return result;
+}
+
+
+template <typename I>
+mln_value(I) sum_frequency_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) sum = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ sum += histo(p);
+
+ return sum;
+}
+
+
+template <typename I>
+mln_coord(mln_site_(I)) peak_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the peak of the histogram
+ mln_value(I) v_max = mln::opt::at(histo, mln::literal::zero);
+ mln_coord(mln_site_(I)) p_max = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ if (v_max < histo(p))
+ {
+ v_max = histo(p);
+ p_max = p.ind();
+ }
+ }
+
+ return p_max;
+}
+
+template <typename I>
+mln_value(I) count_null_frequency_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) count = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ if (0 == histo(p))
+ count++;
+
+ return count;
+}
+
+template <typename I>
+float cmp_equi_frequency_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ float sum = 0;
+ float var = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ sum ++;
+ var += mln::math::sqr(histo(p) - (1/256.0));
+ }
+
+ var = var / sum;
+
+ return var;
+}
+
+template <typename I>
+mln_value(I) cnt_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) sum = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ sum += histo(p);
+ }
+
+ return sum;
+}
+
+template <typename I>
+mln_value(I) sum_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) pos = mln::literal::zero;
+ mln_value(I) sum = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ pos = p.ind();
+ sum += pos*histo(p);
+ }
+
+ return sum;
+}
+
+template <typename I>
+mln_value(I) avg_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) pos = mln::literal::zero;
+ mln_value(I) sum = mln::literal::zero;
+ mln_value(I) cnt = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ pos = p.ind();
+ cnt += histo(p);
+ sum += pos*histo(p);
+ }
+
+ return (0 == cnt)? 0 : sum/cnt;
+}
+
+template <typename I>
+mln_value(I) var3_histo(const mln::Image<I>& histo_, float mean)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) pos = mln::literal::zero;
+ mln_value(I) sum = mln::literal::zero;
+ mln_value(I) cnt = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ cnt += histo(p);
+ sum += (mln::math::sqr(p.ind()-mean)*histo(p));
+ }
+
+ return (0 == cnt)? 0 : sum/cnt;
+}
+
+template <typename I>
+mln_value(I) var2_histo(const mln::Image<I>& histo_, float mean)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) pos = mln::literal::zero;
+ mln_value(I) sum = mln::literal::zero;
+ mln_value(I) sqr = mln::literal::zero;
+ mln_value(I) cnt = mln::literal::zero;
+ mln_value(I) dlt = mln::literal::zero;
+ mln_value(I) mxt = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ pos = p.ind();
+ cnt += (histo(p));
+ sum += (histo(p)*pos);
+ mxt += (histo(p)*pos*mean);
+ sqr += (histo(p)*mln::math::sqr(pos));
+ dlt += (histo(p)*mln::math::sqr(pos - mean));
+
+ std::cout << "p = " << pos
<< std::endl;
+ std::cout << "p² = " << mln::math::sqr(pos)
<< std::endl;
+ std::cout << "p*mean = " << (pos*mean)
<< std::endl;
+ std::cout << "p-mean = " << (pos-mean)
<< std::endl;
+ std::cout << "(p-mean)² = " << mln::math::sqr(pos-mean)
<< std::endl;
+ std::cout << "histo(p) = " << histo(p)
<< std::endl;
+ std::cout << "histo(p)*p = " << (pos*histo(p))
<< std::endl;
+ std::cout << "histo(p)*p²= " << (mln::math::sqr(pos)*histo(p))
+ << std::endl;
+ std::cout << "cnt = " << cnt << std::endl;
+ std::cout << "sum = " << sum << std::endl;
+ std::cout << "sqr = " << sqr << std::endl;
+ std::cout << "dlt = " << dlt << std::endl;
+ std::cout << "mxt = " << mxt << std::endl;
+ std::cout << std::endl;
+ }
+
+ std::cout << "sqr/cnt = " << (sqr/cnt)
<< std::endl;
+ std::cout << "sum/cnt = " << (sum/cnt)
<< std::endl;
+ std::cout << "(sum/cnt)² = " << mln::math::sqr(sum/cnt)
<< std::endl;
+ std::cout << "dlt/cnt = " << dlt/cnt
<< std::endl;
+ std::cout << "mxt/cnt = " << mxt/cnt
<< std::endl;
+ std::cout << std::endl;
+
+ std::cout << "sqr = "
+ << (sqr) << std::endl;
+ std::cout << "dlt = "
+ << (dlt) << std::endl;
+ std::cout << "cnt*avg² = "
+ << (mln::math::sqr(sum/cnt)*cnt) << std::endl;
+ std::cout << "2*mxt = "
+ << (2*mxt) << std::endl;
+ std::cout << "sqr - cnt*avg² = "
+ << (sqr/cnt - mln::math::sqr(sum/cnt)) << std::endl;
+ std::cout << "(sqr -2*mxt + cnt*avg²) = "
+ << ((sqr - 2*mxt + mln::math::sqr(sum/cnt))/cnt) << std::endl;
+ std::cout << std::endl;
+ return (0 == cnt)? 0 : sqr/cnt - mln::math::sqr(sum/cnt);
+}
+
+template <typename I>
+mln_value(I) var_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) pos = mln::literal::zero;
+ mln_value(I) sum = mln::literal::zero;
+ mln_value(I) sqr = mln::literal::zero;
+ mln_value(I) cnt = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ pos = p.ind();
+ cnt += (histo(p));
+ sum += (histo(p)*pos);
+ sqr += (histo(p)*mln::math::sqr(pos));
+ }
+
+ return (0 == cnt)? 0 : sqr/cnt - mln::math::sqr(sum/cnt);
+}
+
+template <typename I>
+mln_value(I) sqr_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) sum = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ sum += (mln::math::sqr(p.ind())*histo(p));
+
+ return sum;
+}
+/// \}
+
+
+/// \brief Millet Hue detector.
+///
+/// \param[in] histo the histogram image on which applying the detector.
+/// \param[in] threshold a way to adapt the test to the population.
+///
+/// \return the proportion of population that verify the hue detector.
+///
+/// This test is used for discrimination between black and white pictures and
+/// color ones. Some colored Black and white pictures have their energy near
+/// the peak.
+float hue1_descriptor(mln::image1d<unsigned> histo, const short threshold)
+{
+ float cnt1;
+ float cnt2;
+ float prop;
+ short peak;
+ mln::point1d inf;
+ mln::point1d sup;
+
+ peak = peak_histo(histo);
+ inf = mln::point1d(mln::math::max(0, peak-threshold));
+ sup = mln::point1d(mln::math::min(255, peak+threshold));
+ cnt1 = count_histo(histo|mln::box1d(inf,sup));
+ cnt2 = count_histo(histo);
+ prop = ((255.0 * cnt1) / cnt2);
+
+ return prop;
+}
+
+
+/// \brief Saturation detector.
+///
+/// \param[in] histo the histogram image on which applying the detector.
+/// \param[in] threshold a way to adapt the test to the population.
+///
+/// \return the proportion of population that verify the hue detector.
+///
+/// This test is used for discrimination between black and white pictures and
+/// color ones. Black and white pictures have their energy in the low saturation
+/// band.
+float sat1_descriptor(mln::image1d<unsigned> histo, const short threshold)
+{
+ float cnt1;
+ float cnt2;
+ float result;
+
+ cnt1 = count_histo(histo | mln::box1d(mln::point1d(0),
+ mln::point1d(threshold)));
+ cnt2 = count_histo(histo);
+ result = ((255.0 * cnt1) / cnt2);
+
+ return result;
+}
+
+
+/// \brief Counting grey levels descriptor.
+///
+/// \param[in] histo the histogram image on which applying the detector.
+///
+/// \return the number of grey levels.
+///
+/// This test aims at compute the number of grey levels. Photographies tends to
+/// use all the levels or many of them.
+float lvl0_descriptor(mln::image1d<unsigned> histo)
+{
+ float result;
+
+ // FIXME 255
+ result = 255-count_null_frequency_histo(histo);
+
+ return result;
+}
+
+
+/// \brief Density hue detector.
+///
+/// \param[in] histo the histogram image on which applying the detector.
+///
+/// \return the proportion of population that verify the hue detector.
+///
+/// This test works on density histogram and compare to the
+/// equi-frequency histogram. If the normalized histogram show a peak,
+/// it will differ from the reference density.
+float hue0_descriptor(mln::image1d<unsigned> histo)
+{
+ mln::image1d<float> histo_float;
+ float sum;
+ float result;
+
+ sum = sum_frequency_histo(histo);
+ histo_float = mln::data::convert(float(), histo) / sum;
+ result = cmp_equi_frequency_histo(histo_float);
+
+ return result*255;
+}
+
+
+/// \brief Density saturation detector.
+///
+/// \param[in] histo the histogram image on which applying the detector.
+///
+/// \return the proportion of population that verify the hue detector.
+///
+/// This test works on density histogram and compare to the
+/// equi-frequency histogram. If the normalized histogram show a peak,
+/// it will differ from the reference density.
+float sat0_descriptor(mln::image1d<unsigned> histo)
+{
+ mln::image1d<float> histo_float;
+ float sum;
+ float result;
+
+ sum = sum_frequency_histo(histo);
+ histo_float = mln::data::convert(float(), histo) / sum;
+ result = cmp_equi_frequency_histo(histo_float);
+
+ return result*255;
+}
+
+
+/// \brief Density value detector.
+///
+/// \param[in] histo the histogram image on which applying the detector.
+///
+/// \return the proportion of population that verify the hue detector.
+///
+/// This test works on density histogram and compare to the
+/// equi-frequency histogram. If the normalized histogram show a peak,
+/// it will differ from the reference density.
+float val0_descriptor(mln::image1d<unsigned> histo)
+{
+ mln::image1d<float> histo_float;
+ float sum;
+ float result;
+
+ sum = sum_frequency_histo(histo);
+ histo_float = mln::data::convert(float(), histo) / sum;
+ result = cmp_equi_frequency_histo(histo_float);
+
+ return result*255;
+}
+
+
+/// \brief The R function of Millet
+///
+/// \param[in] p the position of the pic.
+/// \param[in] histo_p the histo value of the pic.
+/// \param[in] x the position of the element which we compute the contrib.
+/// \param[in] histo_x the histo value of that element.
+///
+/// \result the contribution of the element x.
+///
+/// This function compute the variance-like contribution of an element
+/// x linked to the pic of the histogram. In fact, every thing is like
+/// we compute a square distance-like between the element x and the
+/// pic in the normalized histogram. Notice that the normalized
+/// histogram is the histogram divide by the value of it's pic. So at
+/// the pic, the value equals 1. It's a current representation of the
+/// histogram in image processing, we can find it in gimp for exemple.
+float r(short p, unsigned histo_p, short x, unsigned histo_x)
+{
+ float result = mln::math::sqr(((float)histo_x / histo_p) * (x-p));
+
+ return result;
+}
+
+/// \brief The stddev3 is an internal stuff.
+///
+/// \param[in] histo_ the image which represents the histogram.
+/// \param[in] peak the position of the histogram peak.
+///
+/// \return simple computing of deviation.
+///
+/// This is an internal stuff. It splits the computing for easy
+/// reusing practice. Sum the R contribution.
+template <typename I>
+float stddev3(const mln::Image<I>& histo_, unsigned peak)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Compute stddev
+
+ float stddev = 0.0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ stddev += r((short)peak, mln::opt::at(histo,peak), p.ind(), histo(p));
+ }
+
+ return stddev;
+}
+
+/// Brief compute the whole deviation of Millet
+///
+/// \param[in] image the input image to analyze.
+/// \param[in] peak the peak of the histogram.
+/// \param[in] limit the threshold to compute the contribution.
+///
+/// \return the deviation.
+///
+/// The deviation uses the R function. It stats by finding the pic. If
+/// the pic is near the rigth border of the histo, compute the R
+/// function on the left neighbouring of the pic. If the pic is near
+/// the left border of the histo, compute the R function on the right
+/// neigbouring. Otherwise, compute the average of the right and left
+/// results. The selected neighbouring is composed of five pixels at
+/// the right or at the left of the pic. The detection of clipart
+/// assumes that the majority of the energy of the histogram is closed
+/// to the pic (five pixels around it). The test is generalized by
+/// making constants as parameters.
+template <typename I>
+float stddev2(const mln::Image<I>& histo_, unsigned peak, unsigned limit)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ float stddev_low = 0.0;
+ float stddev_up = 0.0;
+ float ret = 0.0;
+
+ // A transformer avec des iterators
+
+ if (250 > peak)
+ stddev_up = stddev3(histo |mln::box1d(mln::point1d(peak+1),
+ mln::point1d(peak+limit)), peak);
+
+ if (5 < peak)
+ stddev_low = stddev3(histo |mln::box1d(mln::point1d(peak-limit),
+ mln::point1d(peak-1)), peak);
+
+ ret = (250 < peak)? stddev_low : (5 > peak)? stddev_up :
+ (stddev_low + stddev_up)/2;
+
+ return ret;
+}
+
+
+/// \brief Millet value descriptor (cf. Millet.phd.2008)
+///
+/// \param[in] histo the histogram image on which applying the detector.
+/// \param[in] threshold the limit where to compute the contribution.
+///
+/// \return the proportion of population that verify the hue detector.
+///
+/// This test aims at compute some deviation on the peak of the histogram of
+/// the image. Large deviations mean lots of graduation in colors (such as
+/// photos) and small ones mean something like cartoon.
+float val1_descriptor(mln::image1d<unsigned> histo, const short threshold)
+{
+ typedef mln::fun::v2v::rgb_to_value_map<8> t_rgb_to_value_map;
+
+ float result;
+ short peak;
+
+ peak = peak_histo(histo);
+ result = stddev2(histo, peak, threshold);
+
+ return result;
+}
+
+
+/// \brief Error detector (jonathan idea).
+///
+/// \param[in] r_img_map the original red channel.
+/// \param[in] g_img_map the original green channel.
+/// \param[in] b_img_map the original blue channel.
+/// \param[in] r_rdc_map the reduced (in color) red channel.
+/// \param[in] g_rdc_map the reduced (in color) green channel.
+/// \param[in] b_rdc_map the reduced (in color) blue channel.
+///
+/// \return the PNSNR (cf compression p278 Handbook Color).
+///
+/// \fixme the actual PNSNR is unbound, we need to fix its max to
+/// 255. Two images which are the same produces an infinite PNSNR.
+float err_descriptor(mln::image2d<mln::value::int_u8> r_img_map,
+ mln::image2d<mln::value::int_u8> g_img_map,
+ mln::image2d<mln::value::int_u8> b_img_map,
+ mln::image2d<mln::value::int_u8> r_rdc_map,
+ mln::image2d<mln::value::int_u8> g_rdc_map,
+ mln::image2d<mln::value::int_u8> b_rdc_map)
+
+
+{
+ typedef mln::accu::meta::stat::mean t_mean;
+ typedef mln::image2d<mln::value::int_u8> t_map;
+ typedef mln_trait_op_minus_(t_map,t_map) t_minus;
+ typedef mln_trait_op_times_(t_minus,t_minus) t_times;
+
+
+ t_minus minus_red;
+ t_minus minus_green;
+ t_minus minus_blue;
+
+ t_times times_red;
+ t_times times_green;
+ t_times times_blue;
+
+ float error_red;
+ float error_green;
+ float error_blue;
+
+ float error;
+
+ minus_red = (r_img_map - r_rdc_map);
+ times_red = minus_red * minus_red;
+
+ minus_green = (g_img_map - g_rdc_map);
+ times_green = minus_green * minus_green;
+
+ minus_blue = (b_img_map - b_rdc_map);
+ times_blue = minus_blue * minus_blue;
+
+ error_red = mln::data::compute(t_mean(), times_red);
+ error_green = mln::data::compute(t_mean(), times_green);
+ error_blue = mln::data::compute(t_mean(), times_blue);
+
+ error = (error_red + error_green + error_blue)/3.0;
+ error = mln::math::sqrt(error);
+ error = 20 * log(255/error);
+
+// FIXME:
+// SAME IMAGE PRODUCE PNSNR GOING THROW THE INFINITY.
+// DIFFERENT IMAGE PRODUCE PNSNR GOING NEAR ZERO.
+// WE SHOULD KEEP THE PNSNR BELOW 255 FOR COMPARAISON.
+
+ return error;
+}
+
+/// Discriminant operators.
+///
+/// We have some operators that compute the threshold which separate
+/// two sub-populations in a histogram.
+/// /{
+
+/// \brief Compute discrimination threshold.
+/// \param[in] avg1 the mean of the population 1.
+/// \param[in] var1 the variance of the population 1.
+/// \param[in] avg2 the mean of the population 2.
+/// \param[in] var2 the variance of the population 2.
+///
+/// \return the threshold to discriminate the two populations.
+///
+/// Linear discriminant analysis in 1d is done. When two population
+/// have the same variance, the threshold is at (m1+m2)/2. When threre
+/// are different variances, we propose the threshold at the position
+/// (m1*sqrt(v1)+m2*sqrt(v2))/(sqrt(v1)+sqrt(v2)).
+float threshold_histo(float avg1, float var1, float avg2, float var2)
+{
+ float sigma1 = mln::math::sqrt(var1);
+ float sigma2 = mln::math::sqrt(var2);
+ float threshold = (avg1*sigma1+avg2*sigma2)/(sigma1+sigma2);
+
+ return threshold;
+}
+
+/// \brief Compute discrimination threshold.
+/// \param[in] avg1 the mean of the population 1.
+/// \param[in] var1 the variance of the population 1.
+/// \param[in] avg2 the mean of the population 2.
+/// \param[in] var2 the variance of the population 2.
+///
+/// \return the threshold to discriminate the two populations.
+///
+/// Linear discriminant analysis in 1d is done. When two population
+/// have the same variance, the threshold is at (m1+m2)/2. When threre
+/// are different variances, we propose the threshold at the position
+/// (m1*var1+m2*var2)/(sqrt(v1)+sqrt(v2)).
+
+float threshold3_histo(float avg1, float var1, float avg2, float var2)
+{
+ float threshold = (avg1*var1+avg2*var2)/(var1+var2);
+
+ return threshold;
+}
+
+
+/// \brief Compute discrimination threshold.
+/// \param[in] avg1 the mean of the population 1.
+/// \param[in] var1 the variance of the population 1.
+/// \param[in] avg2 the mean of the population 2.
+/// \param[in] var2 the variance of the population 2.
+///
+/// \return the threshold to discriminate the two populations.
+///
+/// Gaussian discriminant analysis in 1d is done. Compute the
+/// discrimanation and solve the parabolic equation.
+float threshold2_histo(float avg1, float var1, float avg2, float var2)
+{
+ float a = var2 - var1;
+ float b = -2 * (avg1 * var2 - avg2 * var1);
+ float c = var2 * mln::math::sqr(avg1) - var1 * mln::math::sqr(avg2);
+ float d = mln::math::sqr(b) - 4 * a * c;
+
+ if (d < 0)
+ std::cout << "delta negatif" << std::endl;
+
+ float x1 = (-b+mln::math::sqrt(d))/(2*a);
+ float x2 = (-b-mln::math::sqrt(d))/(2*a);
+
+ std::cout << "a = " << a << std::endl;
+ std::cout << "b = " << b << std::endl;
+ std::cout << "c = " << c << std::endl;
+ std::cout << "d = " << d << std::endl;
+ std::cout << "x1 = " << x1 << std::endl;
+ std::cout << "x2 = " << x2 << std::endl;
+
+ return x2;
+}
+
+/// \brief Minimisation of the error.
+///
+/// \param[in] histo_grp1 the histogram of the first population.
+/// \param[in] histo_grp2 the histogram of the second population.
+///
+/// \return the threshold.
+///
+/// Computes the error and find the minimum error threshold. It's just
+/// a counting of element in four categories (0 - but detects 1, 1 -
+/// but detects 1, 1 but detects 0, 0 but detects 0). The error is the
+/// sum of missclassifications for the classes 0 and 1. As Otsu done,
+/// we can iterate on the threshold and compute the error associated
+/// to it. The bes threshold is the one that minimize the error.
+short min_error(const mln::image1d<float> histo_grp1,
+ const mln::image1d<float> histo_grp2,
+ float *_c00, float *_c10, float *_c01, float *_c11)
+{
+ float c00[256];
+ float c10[256];
+ float c01[256];
+ float c11[256];
+ float err[256];
+
+ for (short p = 0; p < 256; p++)
+ {
+ c00[p] = cnt_histo(histo_grp1|mln::box1d(mln::point1d(0),
+ mln::point1d(p)));
+
+ c10[p] = cnt_histo(histo_grp1|mln::box1d(mln::point1d(p+1),
+ mln::point1d(255)));
+
+ c01[p] = cnt_histo(histo_grp2|mln::box1d(mln::point1d(0),
+ mln::point1d(p)));
+
+ c11[p] = cnt_histo(histo_grp2|mln::box1d(mln::point1d(p+1),
+ mln::point1d(255)));
+ }
+
+ short threshold = 0;
+ float error = c01[0] + c01[0] + c00[0] + c11[0];
+
+ for(short p = 0; p < 256; p++)
+ {
+ err[p] = c10[p] + c01[p];
+
+// std::cout << " p = " << p
+// << ";c00 = " << c00[p]
+// << ";c10 = " << c10[p]
+// << ";c01 = " << c01[p]
+// << ";c11 = " << c11[p]
+// << std::endl;
+// std::cout << "err[" << p << "] = " <<
err[p] << std::endl;
+
+ if (error > err[p])
+ {
+ error = err[p];
+ threshold = p;
+ }
+ }
+
+ *_c00 = c00[threshold];
+ *_c10 = c10[threshold];
+ *_c01 = c01[threshold];
+ *_c11 = c11[threshold];
+
+ return threshold;
+}
+
+
+/// \brief Fisher analysis.
+///
+/// \param[in] histo the histogram of the mixed population.
+///
+/// \return the threshold.
+///
+/// This routine is less performant than the others because it starts
+/// with a mixed population, but we know exactly the two separated
+/// population. It was just a test. Don't take it in production
+/// environement, it doesn't help you.
+short fisher_analysis(const mln::image1d<float> histo)
+{
+ typedef mln::value::int_u8 t_int_u8;
+
+ // FIXE ME SIZE const short a = mln_min(t_int_u8);
+ // float cnt1[a];
+
+ float cnt1[256];
+ float sum1[256];
+ float sqr1[256];
+ float avg1[256];
+ float var1[256];
+
+ float cnt2[256];
+ float sum2[256];
+ float sqr2[256];
+ float avg2[256];
+ float var2[256];
+
+ float cnt0[256]; // count of points
+ float sum0[256]; // sum of population
+ float sqr0[256]; // sqr of population
+ float avg0[256]; // average of the population
+ float v_in[256]; // variance with-in class
+ float v_bw[256]; // variance between class
+ float var0[256]; // variance of the population
+ short threshold;
+ float pos;
+ float min_var;
+
+ // Assign the first elements
+ cnt1[0] = 0;
+ sum1[0] = 0;
+ sqr1[0] = 0;
+ avg1[0] = 0;
+ var1[0] = 0;
+
+ // Compute the stats of the wall histogram
+ cnt2[0] = 0;
+ sum2[0] = 0;
+ sqr2[0] = 0;
+
+ for(short p = 0; p < 256; p++)
+ {
+ pos = p;
+ cnt2[0] += mln::opt::at(histo,p);
+ sum2[0] += (pos * mln::opt::at(histo,p));
+ sqr2[0] += (mln::math::sqr(pos) * mln::opt::at(histo,p));
+ }
+
+ avg2[0] = (0 == cnt2[0])? 0 : sum2[0] / cnt2[0];
+ var2[0] = (0 == cnt2[0])? 0 : sqr2[0] / cnt2[0] - mln::math::sqr(avg2[0]);
+
+ // watch the array limits
+ for (short p = 1; p < 256; p++)
+ {
+ pos = p;
+
+ // Assign the statistics to the primary class
+ cnt1[p] = cnt1[p-1] + mln::opt::at(histo, p);
+ sum1[p] = sum1[p-1] + pos * mln::opt::at(histo, p);
+ sqr1[p] = sqr1[p-1] + mln::math::sqr(pos) * mln::opt::at(histo, p);
+ avg1[p] = (0 == cnt1[p])? 0 : (sum1[p] / cnt1[p]);
+ var1[p] = (0 == cnt1[p])? 0 : ((sqr1[p] / cnt1[p])-mln::math::sqr(avg1[p]));
+
+ // Assign the statistics to the second class
+ cnt2[p] = cnt2[p-1] - mln::opt::at(histo, p);;
+ sum2[p] = sum2[p-1] - p * mln::opt::at(histo, p);;
+ sqr2[p] = sqr2[p-1] - mln::math::sqr(p) * mln::opt::at(histo, p);;
+ avg2[p] = (0 == cnt2[p])? 0 : (sum2[p] / cnt2[p]);
+ var2[p] = (0 == cnt2[p])? 0 : ((sqr2[p] / cnt2[p])-mln::math::sqr(avg2[p]));
+
+ // Lets compute the invariants
+ cnt0[p] = cnt1[p] + cnt2[p];
+ sum0[p] = sum1[p] + sum2[p];
+ sqr0[p] = sqr1[p] + sqr2[p];
+ avg0[p] = (cnt1[p] * avg1[p] + cnt2[p] * avg2[p])/cnt0[p];
+ v_in[p] = (cnt1[p] * var1[p] + cnt2[p] * var2[p])/cnt0[p];
+ v_bw[p] = (cnt1[p] * mln::math::sqr(avg1[p]-avg0[p]) +
+ cnt2[p] * mln::math::sqr(avg2[p]-avg0[p]))/cnt0[p];
+ var0[p] = v_in[p] + v_bw[p];
+ }
+
+ // Find the threshold that minimizes the intra-class variance
+ min_var = cnt2[0]*var2[0];
+ threshold = 0;
+
+ for(short p = 0; p < 256; p++)
+ {
+ // Compute the intra-class variance
+ v_in[p] = cnt1[p]*var1[p] + cnt2[p]*var2[p];
+// std::cout << "var intra[" << p << "]= "
<< v_in[p] << std::endl;
+
+ if (min_var > v_in[p])
+ {
+ min_var = v_in[p];
+ threshold = p;
+ }
+ }
+
+ return threshold;
+}
+/// /}
+
+
+/// Launching part.
+///
+/// In this part, we have the front end that walk over the image
+/// databases and start to compute information that we pass to
+/// previous routines.
+/// \{
+
+#define LVL0_DESCR 0 // Number of grey available
+#define HUE0_DESCR 1 // Density histogram hue analysis
+#define HUE1_DESCR 2 // Millet Hue analysis
+#define SAT0_DESCR 3 // Density histogram saturation analysis
+#define SAT1_DESCR 4 // Millet saturation analysis
+#define VAL0_DESCR 5 // Density histogram grey level analysis
+#define VAL1_DESCR 6 // Millet grey level analysis
+#define GMP0_DESCR 7 // PNSNR with GIMP compression
+#define GMP1_DESCR 8 // PNSNR with GIMP compression
+#define GMP2_DESCR 9 // PNSNR with GIMP compression
+#define MGK0_DESCR 9 // PNSNR with ImageMagick compression
+#define MGK1_DESCR 10 // PNSNR with ImageMagick compression
+#define MGK2_DESCR 11 // PNSNR with ImageMagick compression
+
+#define MGK_DESCR(version) (MGK0_DESCR + version)
+#define GMP_DESCR(version) (GMP0_DESCR + version)
+
+#define NB_DESCR 12 // Number of descriptors
+#define NB_DATABASE 2 // Number of image databases : AFP,ICDAR
+#define NB_IMAGE 110 // Number of images
+#define NB_VERSION 3 // Number of compression by GIMP or ImageMagick
+
+/// \brief Make sure that the result is between 0 and 255.
+///
+/// \param[in] file_name the name of the analysis files.
+/// \param[in] result the values for each image and each descriptors.
+/// \param[in] size the number of image by each database.
+///
+/// Correct the descriptors if there is overflow values. Just used in
+/// debug mode.
+void init_descriptors(std::string file_name[],
+ float result[][NB_DESCR],
+ int size[])
+{
+ for (int i = 0; i < NB_IMAGE; i++)
+ {
+ file_name[i] = std::string("PGM");
+
+ for (int d = 0; d < NB_DESCR; d++)
+ result[i][d] = (i*d) % 256;
+ }
+
+ size[0] = 62;
+ size[1] = 48;
+}
+
+
+/// \brief Dump gnuplot file for vizualisation of results.
+///
+/// \param[in] file_name the name of the analysis files.
+/// \param[in] result the values for each image and each descriptors.
+/// \param[in] size the number of image by each database.
+///
+/// This routine aimed at plotting the result with one graph. Each
+/// database has got its color. We can see the values used by each
+/// descriptors along the image of each database.
+void dump_descriptors(const std::string file_name[],
+ const float result[][NB_DESCR],
+ const int size[])
+{
+ std::cout << "#!/usr/bin/gnuplot" <<
std::endl;
+ std::cout << "set terminal x11 persist 1" <<
std::endl;
+ std::cout << "plot '-' using 2 with point title
'ICDAR',\\" << std::endl;
+ std::cout << " '-' using 2 with point title 'AFP'"
<< std::endl;
+
+ int num = 0;
+
+ for (int db = 0; db < NB_DATABASE; db++)
+ {
+ for (int i = 0; i < size[db]; i++)
+ {
+ std::cout << result[num][LVL0_DESCR] << " ";
+ std::cout << result[num][HUE0_DESCR] << " ";
+ std::cout << result[num][HUE1_DESCR] << " ";
+ std::cout << result[num][SAT0_DESCR] << " ";
+ std::cout << result[num][SAT1_DESCR] << " ";
+ std::cout << result[num][VAL0_DESCR] << " ";
+ std::cout << result[num][VAL1_DESCR] << " ";
+ std::cout << result[num][GMP0_DESCR] << " ";
+ std::cout << result[num][GMP1_DESCR] << " ";
+ std::cout << result[num][GMP2_DESCR] << " ";
+ std::cout << result[num][MGK0_DESCR] << " ";
+ std::cout << result[num][MGK1_DESCR] << " ";
+ std::cout << result[num][MGK2_DESCR] << " ";
+ std::cout << " # " << file_name[num] << std::endl;
+ num++;
+ }
+
+ std::cout << "e" << std::endl;
+ }
+}
+
+
+/// \brief Compute the descriptor histograms for each database.
+///
+/// \param[in] result the result values of each descriptors.
+/// \param[in] size the number of images by database.
+/// \param[out] histo the computed histograms.
+///
+/// This routine compute a histograms for each database and each descriptors.
+/// So we can see the distribution of descriptor values over each database.
+/// Result values are transform from float to int for histograms.
+void compute_histo(const float result[][NB_DESCR],
+ const int size[],
+ mln::image1d<float> histo[][NB_DATABASE])
+{
+ for (int i = 0; i < NB_DESCR; i++)
+ for (int db = 0; db < NB_DATABASE; db++)
+ {
+ histo[i][db].init_(mln::box1d(mln::point1d(0),mln::point1d(255)));
+
+ mln::data::fill(histo[i][db], mln::literal::zero);
+ }
+
+ short v;
+ int num = 0;
+
+ for (int db = 0; db < NB_DATABASE; db++)
+ {
+ for (int i = 0; i < size[db]; i++)
+ {
+ v = (short)mln::math::floor(result[num][VAL0_DESCR]+0.4999);
+ mln::opt::at(histo[VAL0_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][LVL0_DESCR]+0.4999);
+ mln::opt::at(histo[LVL0_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][HUE0_DESCR]+0.4999);
+ mln::opt::at(histo[HUE0_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][HUE1_DESCR]+0.4999);
+ mln::opt::at(histo[HUE1_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][SAT0_DESCR]+0.4999);
+ mln::opt::at(histo[SAT0_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][SAT1_DESCR]+0.4999);
+ mln::opt::at(histo[SAT1_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][VAL1_DESCR]+0.4999);
+ mln::opt::at(histo[VAL1_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][GMP0_DESCR]+0.4999);
+ mln::opt::at(histo[GMP0_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][GMP1_DESCR]+0.4999);
+ mln::opt::at(histo[GMP1_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][GMP2_DESCR]+0.4999);
+ mln::opt::at(histo[GMP2_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][MGK0_DESCR]+0.4999);
+ mln::opt::at(histo[MGK0_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][MGK1_DESCR]+0.4999);
+ mln::opt::at(histo[MGK1_DESCR][db],v)++;
+
+ v = (short)mln::math::floor(result[num][MGK2_DESCR]+0.4999);
+ mln::opt::at(histo[MGK2_DESCR][db],v)++;
+
+ num++;
+ }
+ }
+}
+
+
+/// Compute the threshold for discrimination between ICDAR and AFP.
+///
+/// \param[in] histo the histogram for each descriptor and for each database.
+/// \param[out] threshold computed values to discriminate between ICDAR/AFP.
+/// \param[out] c00 say CLASS 1 but CLASS 1.
+/// \param[out] c10 say CLASS 2 but CLASS 1.
+/// \param[out] c01 say CLASS 1 but CLASS 2.
+/// \param[out] c11 say CLASS 2 but CLASS 2.
+///
+/// Compute the threshold by the minimum of error of
+/// classification. Population are inverted in function of average,
+/// technical solution to prevent min_error crashed. The bad thing is
+/// now, the class 0 can be either ICDAR of AFP, depends on descriptors.
+void compute_thresholds(const mln::image1d<float> histo[][NB_DATABASE],
+ short threshold[],
+ float c00[],
+ float c10[],
+ float c01[],
+ float c11[])
+{
+ for (int i = 0; i < NB_DESCR; i++)
+ {
+ float avg0 = avg_histo(histo[i][0]);
+ float avg1 = avg_histo(histo[i][1]);
+
+ if (avg0 < avg1)
+ {
+ threshold[i] = min_error(histo[i][0], histo[i][1],
+ &c00[i], &c10[i], &c01[i], &c11[i]);
+ }
+ else
+ {
+ threshold[i] = min_error(histo[i][1], histo[i][0],
+ &c00[i], &c10[i], &c01[i], &c11[i]);
+ }
+
+ std::cerr << " i = " << i
+ << "; c00 = " << c00[i]
+ << "; c10 = " << c10[i]
+ << "; c01 = " << c01[i]
+ << "; c11 = " << c11[i]
+ << "; threshold " << threshold[i]
+ << std::endl;
+
+ }
+}
+
+
+/// \brief Walk over the database directories.
+///
+/// \param[out] file_name the array of the image name.
+/// \param[out] result the descriptors values for each image.
+/// \param[out] size the number of image for each database.
+///
+/// This is the front end part to access to the database directories. We use
+/// boost library to do it. First we explore ICDAR database en then the AFP one.
+/// For each valid image, we compute all the descriptors. Histograms are
+/// computed at this level because we can do that thing one time for every
+/// density descriptors. Every parameters are updated to retrurn the values.
+void compute_descriptors(std::string file_name[],
+ float result[][NB_DESCR],
+ int size[])
+{
+ typedef boost::filesystem::path t_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+ typedef mln::image1d<unsigned> t_histo;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::image2d<t_int_u8> t_map;
+ typedef mln::image2d<t_rgb8> t_input;
+ typedef mln::fun::v2v::rgb_to_hue_map<8> t_rgb_2_hue;
+ typedef mln::fun::v2v::rgb_to_saturation_map<8> t_rgb_2_sat;
+ typedef mln::fun::v2v::rgb_to_value_map<8> t_rgb_2_val;
+ typedef mln::fun::v2v::component<t_rgb8,0> t_rgb_2_red;
+ typedef mln::fun::v2v::component<t_rgb8,1> t_rgb_2_green;
+ typedef mln::fun::v2v::component<t_rgb8,2> t_rgb_2_blue;
+ typedef mln::accu::meta::stat::histo1d t_accu_histo;
+
+
+ t_path img_path[2] = { ICDAR_20P_INPUT_IMG_PATH, AFP_PPM_IMG_PATH};
+ t_path mgk_path[3][2] = {{ICDAR_20P_MGK30_IMG_PATH, AFP_MGK30_IMG_PATH},
+ {ICDAR_20P_MGK20_IMG_PATH, AFP_MGK20_IMG_PATH},
+ {ICDAR_20P_MGK10_IMG_PATH, AFP_MGK10_IMG_PATH}};
+ t_path gmp_path[3][2] = {{ICDAR_20P_GMP30_IMG_PATH, AFP_GMP30_IMG_PATH},
+ {ICDAR_20P_GMP20_IMG_PATH, AFP_GMP20_IMG_PATH},
+ {ICDAR_20P_GMP10_IMG_PATH, AFP_GMP10_IMG_PATH}};
+
+ int num = 0;
+ int cnt = 0;
+
+ for (int db = 0; db < NB_DATABASE; db++)
+ {
+ if (boost::filesystem::exists(img_path[db]) &&
+ boost::filesystem::is_directory(img_path[db]))
+ {
+ boost::filesystem::system_complete(img_path[db]);
+
+ const t_iter_path end_iter;
+
+ cnt = 0;
+
+ for (t_iter_path dir_iter(img_path[db]); end_iter != dir_iter; ++dir_iter)
+ {
+ t_path img_file = dir_iter->path().leaf();
+ t_path dir_file = dir_iter->path();
+ t_input img_input;
+
+ mln::io::ppm::load(img_input, dir_file.string().c_str());
+
+ t_map h_img_map = mln::data::transform(img_input, t_rgb_2_hue());
+ t_map s_img_map = mln::data::transform(img_input, t_rgb_2_sat());
+ t_map v_img_map = mln::data::transform(img_input, t_rgb_2_val());
+ t_map r_img_map = mln::data::transform(img_input, t_rgb_2_red());
+ t_map g_img_map = mln::data::transform(img_input, t_rgb_2_green());
+ t_map b_img_map = mln::data::transform(img_input, t_rgb_2_blue());
+ t_histo h_img_hst = mln::data::compute(t_accu_histo(), h_img_map);
+ t_histo s_img_hst = mln::data::compute(t_accu_histo(), s_img_map);
+ t_histo v_img_hst = mln::data::compute(t_accu_histo(), v_img_map);
+ t_histo r_img_hst = mln::data::compute(t_accu_histo(), r_img_map);
+ t_histo g_img_hst = mln::data::compute(t_accu_histo(), g_img_map);
+ t_histo b_img_hst = mln::data::compute(t_accu_histo(), b_img_map);
+
+ std::cerr << dir_iter->path() << std::endl;
+
+ file_name[num] = img_file.string();
+
+ // descriptors
+ result[num][LVL0_DESCR] = lvl0_descriptor(v_img_hst);
+ result[num][HUE0_DESCR] = hue0_descriptor(h_img_hst);
+ result[num][HUE1_DESCR] = hue1_descriptor(h_img_hst,20);
+ result[num][SAT0_DESCR] = sat0_descriptor(s_img_hst);
+ result[num][SAT1_DESCR] = sat1_descriptor(s_img_hst,50);
+ result[num][VAL0_DESCR] = val0_descriptor(v_img_hst);
+ //result[num][VAL1_DESCR] = val1_descriptor(v_img_hst, 15);
+ result[num][VAL1_DESCR] = 0;
+
+ // for gimp and magick
+ for (int v = 0; v < NB_VERSION; v++)
+ {
+ if (boost::filesystem::exists(mgk_path[v][db]) &&
+ boost::filesystem::exists(gmp_path[v][db]) &&
+ boost::filesystem::is_directory(mgk_path[v][db]) &&
+ boost::filesystem::is_directory(gmp_path[v][db]))
+ {
+ t_path mgk_file = mgk_path[v][db] / img_file;
+ t_path gmp_file = gmp_path[v][db] / img_file;
+ t_input gmp_input;
+
+ mln::io::ppm::load(gmp_input, gmp_file.string().c_str());
+
+ t_map r_gmp_map = mln::data::transform(gmp_input,t_rgb_2_red());
+ t_map g_gmp_map = mln::data::transform(gmp_input,t_rgb_2_green());
+ t_map b_gmp_map = mln::data::transform(gmp_input,t_rgb_2_blue());
+
+ result[num][GMP_DESCR(v)]= err_descriptor(r_img_map,
+ g_img_map,
+ b_img_map,
+ r_gmp_map,
+ g_gmp_map,
+ b_gmp_map);
+
+ t_input mgk_input;
+
+ mln::io::ppm::load(mgk_input, mgk_file.string().c_str());
+
+ t_map r_mgk_map = mln::data::transform(mgk_input,t_rgb_2_red());
+ t_map g_mgk_map = mln::data::transform(mgk_input,t_rgb_2_green());
+ t_map b_mgk_map = mln::data::transform(mgk_input,t_rgb_2_blue());
+
+ result[num][MGK_DESCR(v)]= err_descriptor(r_img_map,
+ g_img_map,
+ b_img_map,
+ r_mgk_map,
+ g_mgk_map,
+ b_mgk_map);
+ }
+ }
+
+ num++;
+ cnt++;
+ }
+ }
+
+ size[db] = cnt;
+ }
+}
+
+/// \brief Just for debugging purpose and tests.
+int main2()
+{
+ typedef mln::image1d<unsigned> t_histo;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::image2d<t_int_u8> t_map;
+ typedef mln::image2d<t_rgb8> t_input;
+ typedef mln::fun::v2v::rgb_to_hue_map<8> t_rgb_2_hue;
+ typedef mln::fun::v2v::rgb_to_saturation_map<8> t_rgb_2_sat;
+ typedef mln::fun::v2v::rgb_to_value_map<8> t_rgb_2_val;
+ typedef mln::fun::v2v::component<t_rgb8,0> t_rgb_2_red;
+ typedef mln::fun::v2v::component<t_rgb8,1> t_rgb_2_green;
+ typedef mln::fun::v2v::component<t_rgb8,2> t_rgb_2_blue;
+ typedef mln::accu::meta::stat::histo1d t_accu_histo;
+
+ t_input img_input;
+
+ mln::io::ppm::load(img_input, ICDAR_20P_INPUT_IMG_PATH"/mp00032c_20p.ppm");
+ //mln::io::ppm::load(img_input, AFP_PPM_IMG_PATH"/000_Del218430.ppm");
+
+
+
+ t_map h_img_map = mln::data::transform(img_input, t_rgb_2_hue());
+ t_map s_img_map = mln::data::transform(img_input, t_rgb_2_sat());
+ t_map v_img_map = mln::data::transform(img_input, t_rgb_2_val());
+ t_map r_img_map = mln::data::transform(img_input, t_rgb_2_red());
+ t_map g_img_map = mln::data::transform(img_input, t_rgb_2_green());
+ t_map b_img_map = mln::data::transform(img_input, t_rgb_2_blue());
+ t_histo h_img_hst = mln::data::compute(t_accu_histo(), h_img_map);
+ t_histo s_img_hst = mln::data::compute(t_accu_histo(), s_img_map);
+ t_histo v_img_hst = mln::data::compute(t_accu_histo(), v_img_map);
+ t_histo r_img_hst = mln::data::compute(t_accu_histo(), r_img_map);
+ t_histo g_img_hst = mln::data::compute(t_accu_histo(), g_img_map);
+ t_histo b_img_hst = mln::data::compute(t_accu_histo(), b_img_map);
+
+
+ std::cout << "sat2 : " << sat0_descriptor(s_img_hst) <<
std::endl;
+
+ return 0;
+}
+
+
+/// \brief Main entry.
+///
+/// This is the front end for every routines.
+/// - compute descriptors.
+/// - dump descriptors.
+/// - compute histograms.
+/// - compute thresholds.
+/// - save results.
+///
+/// Global data used:
+/// - file_name : all the initial images name, mixed every image database.
+/// - result : all the result values for every descriptors and for every images.
+/// - histo : the histograms ny database and by descriptors.
+/// - size : the number of image by database.
+/// - threshold : the computed histogram separation on each descriptors.
+/// - cxx : the count of well/bad classified images function of threshold info.
+int main()
+{
+ std::string file_name[NB_IMAGE];
+ float result[NB_IMAGE][NB_DESCR];
+ int size[NB_DATABASE];
+ mln::image1d<float> histo[NB_DESCR][NB_DATABASE];
+ short threshold[NB_DESCR];
+ float c00[NB_DESCR];
+ float c10[NB_DESCR];
+ float c01[NB_DESCR];
+ float c11[NB_DESCR];
+
+ std::cerr << "DESCRIPTORS" << std::endl;
+ compute_descriptors(file_name,result,size);
+// std::cout << "DUMPING" << std::endl;
+// init_descriptors(file_name,result,size);
+ dump_descriptors(file_name,result,size);
+ std::cerr << "HISTO" << std::endl;
+ compute_histo(result,size,histo);
+ std::cerr << "THRESHOLD" << std::endl;
+ compute_thresholds(histo,threshold,c00,c10,c01,c11);
+
+ mln::io::plot::save_image_sh(histo[LVL0_DESCR][0], "lvl0_histo1.sh");
+ mln::io::plot::save_image_sh(histo[HUE0_DESCR][0], "hue0_histo1.sh");
+ mln::io::plot::save_image_sh(histo[HUE1_DESCR][0], "hue1_histo1.sh");
+ mln::io::plot::save_image_sh(histo[SAT0_DESCR][0], "sat0_histo1.sh");
+ mln::io::plot::save_image_sh(histo[SAT1_DESCR][0], "sat1_histo1.sh");
+ mln::io::plot::save_image_sh(histo[VAL0_DESCR][0], "val0_histo1.sh");
+ mln::io::plot::save_image_sh(histo[VAL1_DESCR][0], "val1_histo1.sh");
+ mln::io::plot::save_image_sh(histo[GMP0_DESCR][0], "gmp0_histo1.sh");
+ mln::io::plot::save_image_sh(histo[GMP1_DESCR][0], "gmp1_histo1.sh");
+ mln::io::plot::save_image_sh(histo[GMP2_DESCR][0], "gmp2_histo1.sh");
+ mln::io::plot::save_image_sh(histo[MGK0_DESCR][0], "mgk0_histo1.sh");
+ mln::io::plot::save_image_sh(histo[MGK1_DESCR][0], "mgk1_histo1.sh");
+ mln::io::plot::save_image_sh(histo[MGK2_DESCR][0], "mgk2_histo1.sh");
+
+ mln::io::plot::save_image_sh(histo[LVL0_DESCR][1], "lvl0_histo2.sh");
+ mln::io::plot::save_image_sh(histo[HUE0_DESCR][1], "hue0_histo2.sh");
+ mln::io::plot::save_image_sh(histo[HUE1_DESCR][1], "hue1_histo2.sh");
+ mln::io::plot::save_image_sh(histo[SAT0_DESCR][1], "sat0_histo2.sh");
+ mln::io::plot::save_image_sh(histo[SAT1_DESCR][1], "sat1_histo2.sh");
+ mln::io::plot::save_image_sh(histo[VAL0_DESCR][1], "val0_histo2.sh");
+ mln::io::plot::save_image_sh(histo[VAL1_DESCR][1], "val1_histo2.sh");
+ mln::io::plot::save_image_sh(histo[GMP0_DESCR][1], "gmp0_histo2.sh");
+ mln::io::plot::save_image_sh(histo[GMP1_DESCR][1], "gmp1_histo2.sh");
+ mln::io::plot::save_image_sh(histo[GMP2_DESCR][1], "gmp2_histo2.sh");
+ mln::io::plot::save_image_sh(histo[MGK0_DESCR][1], "mgk0_histo2.sh");
+ mln::io::plot::save_image_sh(histo[MGK1_DESCR][1], "mgk1_histo2.sh");
+ mln::io::plot::save_image_sh(histo[MGK2_DESCR][1], "mgk2_histo2.sh");
+
+ return 0;
+}
+/// \}
+
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/error/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/error/Makefile.am
diff --git a/scribo/sandbox/green/exp/annotating/error/error.cc
b/scribo/sandbox/green/exp/annotating/error/error.cc
new file mode 100644
index 0000000..949b51b
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/error/error.cc
@@ -0,0 +1,833 @@
+// 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
+///
+/// This file is a prelude just before using the bench source. It puts
+/// the light on the Jonathan's idea which wants to compare ICDAR and
+/// AFP image database with difference between original image and
+/// color reducted one. The key point is to say that when a color
+/// image is degraded, the visual quality fall quickly in function of
+/// the number of colors left. A contrario, when an image is black and
+/// white, this kind of degradation doesn't change the original visual
+/// quality. The PNSNR detector is build and learning threshold for
+/// automatic classification is done (four algorithms are tested).
+
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/algebra/vec.hh>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/stat/mean.hh>
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/arith/minus.hh>
+#include <mln/arith/times.hh>
+#include <mln/arith/diff_abs.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+#include <mln/core/alias/point1d.hh>
+#include <mln/core/alias/box1d.hh>
+
+#include <mln/data/transform.hh>
+#include <mln/data/compute.hh>
+#include <mln/data/stretch.hh>
+#include <mln/data/fill.hh>
+
+#include <mln/fun/v2v/component.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/literal/zero.hh>
+
+#include <mln/math/ceil.hh>
+#include <mln/math/floor.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/trait/value_.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/int_u8.hh>
+
+/// Work on histogram.
+/// \brief Different routines are presented for computing mean, variance ...
+/// \{
+
+/// \brief Counting the number of pixels in the histogram.
+/// \param[in] histo_ the image which represents the histogram.
+///
+/// \return the number of pixels in the histogram.
+///
+/// Such routine is a generic and is generally applied on a portion of
+/// the real domain.
+template <typename I>
+mln_value(I) cnt_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) sum = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ sum += histo(p);
+ }
+
+ return sum;
+}
+
+/// \brief Summing the values ponderated by their occurences.
+/// \param[in] histo_ the image which represents the histogram.
+///
+/// \return the sum ponderated of values by their occurences.
+///
+/// This method is not a production routine, it's just a test to debug
+/// histogram problem. When we compute something over the histogram,
+/// we need to take care of the intermediate type that contains the
+/// temporary result. If not the case, the type used is the one of the
+/// value of the histogram and we can go to some overflow
+/// problems. The trick is to store the value returned by the iterator
+/// in some temporary computing type (look at pos in the code).
+template <typename I>
+mln_value(I) sum_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) pos = mln::literal::zero;
+ mln_value(I) sum = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ pos = p.ind();
+ sum += pos*histo(p);
+ }
+
+ return sum;
+}
+
+/// \brief Summing the values ponderated by their occurences.
+/// \param[in] histo_ the image which represents the histogram.
+///
+/// \return the sum ponderated of values by their occurences.
+template <typename I>
+mln_value(I) avg_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) pos = mln::literal::zero;
+ mln_value(I) sum = mln::literal::zero;
+ mln_value(I) cnt = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ pos = p.ind();
+ cnt += histo(p);
+ sum += pos*histo(p);
+ }
+
+ return (0 == cnt)? 0 : sum/cnt;
+}
+
+/// \brief Computing the variance
+/// \param[in] histo_ the image which represents the histogram.
+///
+/// \return the variance of the histogram.
+///
+/// This computing is safe because the quantity of information stored
+/// in sum is low. This formulae doesn't show the overflow problem.
+template <typename I>
+mln_value(I) var3_histo(const mln::Image<I>& histo_, float mean)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) pos = mln::literal::zero;
+ mln_value(I) sum = mln::literal::zero;
+ mln_value(I) cnt = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ cnt += histo(p);
+ sum += (mln::math::sqr(p.ind()-mean)*histo(p));
+ }
+
+ return (0 == cnt)? 0 : sum/cnt;
+}
+
+/// \brief Computing the variance
+/// \param[in] histo_ the image which represents the histogram.
+///
+/// \return the variance of the histogram.
+///
+/// This is the debugging code to observe overflow problem.
+template <typename I>
+mln_value(I) var2_histo(const mln::Image<I>& histo_, float mean)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) pos = mln::literal::zero;
+ mln_value(I) sum = mln::literal::zero;
+ mln_value(I) sqr = mln::literal::zero;
+ mln_value(I) cnt = mln::literal::zero;
+ mln_value(I) dlt = mln::literal::zero;
+ mln_value(I) mxt = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ pos = p.ind();
+ cnt += (histo(p));
+ sum += (histo(p)*pos);
+ mxt += (histo(p)*pos*mean);
+ sqr += (histo(p)*mln::math::sqr(pos));
+ dlt += (histo(p)*mln::math::sqr(pos - mean));
+
+ std::cout << "p = " << pos
<< std::endl;
+ std::cout << "p² = " << mln::math::sqr(pos)
<< std::endl;
+ std::cout << "p*mean = " << (pos*mean)
<< std::endl;
+ std::cout << "p-mean = " << (pos-mean)
<< std::endl;
+ std::cout << "(p-mean)² = " << mln::math::sqr(pos-mean)
<< std::endl;
+ std::cout << "histo(p) = " << histo(p)
<< std::endl;
+ std::cout << "histo(p)*p = " << (pos*histo(p))
<< std::endl;
+ std::cout << "histo(p)*p²= " << (mln::math::sqr(pos)*histo(p))
+ << std::endl;
+ std::cout << "cnt = " << cnt << std::endl;
+ std::cout << "sum = " << sum << std::endl;
+ std::cout << "sqr = " << sqr << std::endl;
+ std::cout << "dlt = " << dlt << std::endl;
+ std::cout << "mxt = " << mxt << std::endl;
+ std::cout << std::endl;
+ }
+
+ std::cout << "sqr/cnt = " << (sqr/cnt)
<< std::endl;
+ std::cout << "sum/cnt = " << (sum/cnt)
<< std::endl;
+ std::cout << "(sum/cnt)² = " << mln::math::sqr(sum/cnt)
<< std::endl;
+ std::cout << "dlt/cnt = " << dlt/cnt
<< std::endl;
+ std::cout << "mxt/cnt = " << mxt/cnt
<< std::endl;
+ std::cout << std::endl;
+
+ std::cout << "sqr = "
+ << (sqr) << std::endl;
+ std::cout << "dlt = "
+ << (dlt) << std::endl;
+ std::cout << "cnt*avg² = "
+ << (mln::math::sqr(sum/cnt)*cnt) << std::endl;
+ std::cout << "2*mxt = "
+ << (2*mxt) << std::endl;
+ std::cout << "sqr - cnt*avg² = "
+ << (sqr/cnt - mln::math::sqr(sum/cnt)) << std::endl;
+ std::cout << "(sqr -2*mxt + cnt*avg²) = "
+ << ((sqr - 2*mxt + mln::math::sqr(sum/cnt))/cnt) << std::endl;
+ std::cout << std::endl;
+ return (0 == cnt)? 0 : sqr/cnt - mln::math::sqr(sum/cnt);
+}
+
+/// \brief Computing the variance
+/// \param[in] histo_ the image which represents the histogram.
+///
+/// \return the variance of the histogram.
+///
+/// My standard code for the variance.
+template <typename I>
+mln_value(I) var_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) pos = mln::literal::zero;
+ mln_value(I) sum = mln::literal::zero;
+ mln_value(I) sqr = mln::literal::zero;
+ mln_value(I) cnt = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ pos = p.ind();
+ cnt += (histo(p));
+ sum += (histo(p)*pos);
+ sqr += (histo(p)*mln::math::sqr(pos));
+ }
+
+ return (0 == cnt)? 0 : sqr/cnt - mln::math::sqr(sum/cnt);
+}
+/// \}
+
+
+/// Classify.
+/// \brief Classification routines that compute threshold.
+/// \{
+
+/// \brief Compute discrimination threshold.
+/// \param[in] avg1 the mean of the population 1.
+/// \param[in] var1 the variance of the population 1.
+/// \param[in] avg2 the mean of the population 2.
+/// \param[in] var2 the variance of the population 2.
+///
+/// \return the threshold to discriminate the two populations.
+///
+/// Linear discriminant analysis in 1d is done. When two population
+/// have the same variance, the threshold is at (m1+m2)/2. When threre
+/// are different variances, we propose the threshold at the position
+/// (m1*sqrt(v1)+m2*sqrt(v2))/(sqrt(v1)+sqrt(v2)).
+float threshold_histo(float avg1, float var1, float avg2, float var2)
+{
+ float sigma1 = mln::math::sqrt(var1);
+ float sigma2 = mln::math::sqrt(var2);
+ float threshold = (avg1*sigma1+avg2*sigma2)/(sigma1+sigma2);
+
+ return threshold;
+}
+
+/// \brief Compute discrimination threshold.
+/// \param[in] avg1 the mean of the population 1.
+/// \param[in] var1 the variance of the population 1.
+/// \param[in] avg2 the mean of the population 2.
+/// \param[in] var2 the variance of the population 2.
+///
+/// \return the threshold to discriminate the two populations.
+///
+/// Linear discriminant analysis in 1d is done. When two population
+/// have the same variance, the threshold is at (m1+m2)/2. When threre
+/// are different variances, we propose the threshold at the position
+/// (m1*var1+m2*var2)/(sqrt(v1)+sqrt(v2)).
+float threshold3_histo(float avg1, float var1, float avg2, float var2)
+{
+ float threshold = (avg1*var1+avg2*var2)/(var1+var2);
+
+ return threshold;
+}
+
+
+
+/// \brief Compute discrimination threshold.
+/// \param[in] avg1 the mean of the population 1.
+/// \param[in] var1 the variance of the population 1.
+/// \param[in] avg2 the mean of the population 2.
+/// \param[in] var2 the variance of the population 2.
+///
+/// \return the threshold to discriminate the two populations.
+///
+/// Gaussian discriminant analysis in 1d is done. Compute the
+/// discrimanation and solve the parabolic equation.
+float threshold2_histo(float avg1, float var1, float avg2, float var2)
+{
+ float a = var2 - var1;
+ float b = -2 * (avg1 * var2 - avg2 * var1);
+ float c = var2 * mln::math::sqr(avg1) - var1 * mln::math::sqr(avg2);
+ float d = mln::math::sqr(b) - 4 * a * c;
+
+ if (d < 0)
+ std::cout << "delta negatif" << std::endl;
+
+ float x1 = (-b+mln::math::sqrt(d))/(2*a);
+ float x2 = (-b-mln::math::sqrt(d))/(2*a);
+
+ std::cout << "a = " << a << std::endl;
+ std::cout << "b = " << b << std::endl;
+ std::cout << "c = " << c << std::endl;
+ std::cout << "d = " << d << std::endl;
+ std::cout << "x1 = " << x1 << std::endl;
+ std::cout << "x2 = " << x2 << std::endl;
+
+ return x2;
+}
+
+/// \brief Compute the other proportion of histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the ponderated sum of the sqrt values.
+///
+/// This is a test. Don't take this routine in production.
+template <typename I>
+mln_value(I) sqr_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) sum = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ sum += (mln::math::sqr(p.ind())*histo(p));
+
+ return sum;
+}
+
+/// \brief Minimisation of the error.
+///
+/// \param[in] histo_grp1 the histogram of the first population.
+/// \param[in] histo_grp2 the histogram of the second population.
+///
+/// \return the threshold.
+///
+/// Computes the error and find the minimum error threshold. It's just
+/// a counting of element in four categories (0 - but detects 1, 1 -
+/// but detects 1, 1 but detects 0, 0 but detects 0). The error is the
+/// sum of missclassifications for the classes 0 and 1. As Otsu done,
+/// we can iterate on the threshold and compute the error associated
+/// to it. The bes threshold is the one that minimize the error.
+short min_error(const mln::image1d<float> histo_grp1,
+ const mln::image1d<float> histo_grp2)
+{
+ float c00[256];
+ float c10[256];
+ float c01[256];
+ float c11[256];
+ float err[256];
+
+ for (short p = 0; p < 256; p++)
+ {
+ c00[p] = cnt_histo(histo_grp1|mln::box1d(mln::point1d(0),
+ mln::point1d(p)));
+
+ c10[p] = cnt_histo(histo_grp1|mln::box1d(mln::point1d(p+1),
+ mln::point1d(255)));
+
+ c01[p] = cnt_histo(histo_grp2|mln::box1d(mln::point1d(0),
+ mln::point1d(p)));
+
+ c11[p] = cnt_histo(histo_grp2|mln::box1d(mln::point1d(p+1),
+ mln::point1d(255)));
+ }
+
+ short threshold = 0;
+ float error = c01[0] + c01[0] + c00[0] + c11[0];
+
+ for(short p = 0; p < 256; p++)
+ {
+ err[p] = c10[p] + c01[p];
+
+ std::cout << " p = " << p
+ << ";c00 = " << c00[p]
+ << ";c10 = " << c10[p]
+ << ";c01 = " << c01[p]
+ << ";c11 = " << c11[p]
+ << std::endl;
+// std::cout << "err[" << p << "] = " <<
err[p] << std::endl;
+
+ if (error > err[p])
+ {
+ error = err[p];
+ threshold = p;
+ }
+ }
+
+ return threshold;
+}
+
+/// \brief Fisher analysis.
+///
+/// \param[in] histo the histogram of the mixed population.
+///
+/// \return the threshold.
+///
+/// This routine is less performant than the others because it starts
+/// with a mixed population, but we know exactly the two separated
+/// population. It was just a test. Don't take it in production
+/// environement, it doesn't help you.
+short fisher_analysis(const mln::image1d<float> histo)
+{
+ typedef mln::value::int_u8 t_int_u8;
+
+ // FIXE ME SIZE const short a = mln_min(t_int_u8);
+ // float cnt1[a];
+
+ float cnt1[256];
+ float sum1[256];
+ float sqr1[256];
+ float avg1[256];
+ float var1[256];
+
+ float cnt2[256];
+ float sum2[256];
+ float sqr2[256];
+ float avg2[256];
+ float var2[256];
+
+ float cnt0[256]; // count of points
+ float sum0[256]; // sum of population
+ float sqr0[256]; // sqr of population
+ float avg0[256]; // average of the population
+ float v_in[256]; // variance with-in class
+ float v_bw[256]; // variance between class
+ float var0[256]; // variance of the population
+ short threshold;
+ float pos;
+ float min_var;
+
+ // Assign the first elements
+ cnt1[0] = 0;
+ sum1[0] = 0;
+ sqr1[0] = 0;
+ avg1[0] = 0;
+ var1[0] = 0;
+
+ // Compute the stats of the wall histogram
+ cnt2[0] = 0;
+ sum2[0] = 0;
+ sqr2[0] = 0;
+
+ for(short p = 0; p < 256; p++)
+ {
+ pos = p;
+ cnt2[0] += mln::opt::at(histo,p);
+ sum2[0] += (pos * mln::opt::at(histo,p));
+ sqr2[0] += (mln::math::sqr(pos) * mln::opt::at(histo,p));
+ }
+
+ avg2[0] = (0 == cnt2[0])? 0 : sum2[0] / cnt2[0];
+ var2[0] = (0 == cnt2[0])? 0 : sqr2[0] / cnt2[0] - mln::math::sqr(avg2[0]);
+
+ // watch the array limits
+ for (short p = 1; p < 256; p++)
+ {
+ pos = p;
+
+ // Assign the statistics to the primary class
+ cnt1[p] = cnt1[p-1] + mln::opt::at(histo, p);
+ sum1[p] = sum1[p-1] + pos * mln::opt::at(histo, p);
+ sqr1[p] = sqr1[p-1] + mln::math::sqr(pos) * mln::opt::at(histo, p);
+ avg1[p] = (0 == cnt1[p])? 0 : (sum1[p] / cnt1[p]);
+ var1[p] = (0 == cnt1[p])? 0 : ((sqr1[p] / cnt1[p])-mln::math::sqr(avg1[p]));
+
+ // Assign the statistics to the second class
+ cnt2[p] = cnt2[p-1] - mln::opt::at(histo, p);;
+ sum2[p] = sum2[p-1] - p * mln::opt::at(histo, p);;
+ sqr2[p] = sqr2[p-1] - mln::math::sqr(p) * mln::opt::at(histo, p);;
+ avg2[p] = (0 == cnt2[p])? 0 : (sum2[p] / cnt2[p]);
+ var2[p] = (0 == cnt2[p])? 0 : ((sqr2[p] / cnt2[p])-mln::math::sqr(avg2[p]));
+
+ // Lets compute the invariants
+ cnt0[p] = cnt1[p] + cnt2[p];
+ sum0[p] = sum1[p] + sum2[p];
+ sqr0[p] = sqr1[p] + sqr2[p];
+ avg0[p] = (cnt1[p] * avg1[p] + cnt2[p] * avg2[p])/cnt0[p];
+ v_in[p] = (cnt1[p] * var1[p] + cnt2[p] * var2[p])/cnt0[p];
+ v_bw[p] = (cnt1[p] * mln::math::sqr(avg1[p]-avg0[p]) +
+ cnt2[p] * mln::math::sqr(avg2[p]-avg0[p]))/cnt0[p];
+ var0[p] = v_in[p] + v_bw[p];
+ }
+
+ // Find the threshold that minimizes the intra-class variance
+ min_var = cnt2[0]*var2[0];
+ threshold = 0;
+
+ for(short p = 0; p < 256; p++)
+ {
+ // Compute the intra-class variance
+ v_in[p] = cnt1[p]*var1[p] + cnt2[p]*var2[p];
+// std::cout << "var intra[" << p << "]= "
<< v_in[p] << std::endl;
+
+ if (min_var > v_in[p])
+ {
+ min_var = v_in[p];
+ threshold = p;
+ }
+ }
+
+ return threshold;
+}
+/// \}
+
+/// \brief ERROR (MSE, PNSNR) compression p278 Handbook Color.
+/// \param[in] original the original image.
+/// \param[in] reduced the image with a reduced number of colors.
+///
+/// \return the PNSNR.
+///
+/// Compute the PNSNR. First compute the square difference in each
+/// channel. Then compute the mean of those square differences and get
+/// the mean over the three channels. Then, get the sqrt of that to
+/// have a distance. The PNSNR is a logarithmic quantity of that distance.
+float error_test(const std::string original,
+ const std::string reduced)
+
+{
+
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::fun::v2v::component<t_rgb8,0> t_component_red;
+ typedef mln::fun::v2v::component<t_rgb8,1> t_component_green;
+ typedef mln::fun::v2v::component<t_rgb8,2> t_component_blue;
+ typedef mln::accu::meta::stat::mean t_mean;
+ typedef mln::accu::meta::stat::histo1d t_histo;
+ typedef mln::image2d<t_int_u8> t_img;
+ typedef mln_trait_op_minus_(t_img,t_img) t_minus;
+ typedef mln_trait_op_times_(t_minus,t_minus) t_times;
+
+ mln::image2d<mln::value::rgb8> original_rgb8;
+ mln::image2d<mln::value::rgb8> reduced_rgb8;
+
+ mln::image2d<mln::value::int_u8> original_red;
+ mln::image2d<mln::value::int_u8> original_green;
+ mln::image2d<mln::value::int_u8> original_blue;
+
+ mln::image2d<mln::value::int_u8> reduced_red;
+ mln::image2d<mln::value::int_u8> reduced_green;
+ mln::image2d<mln::value::int_u8> reduced_blue;
+
+// mln::image2d<mln::value::int_u8> map_red;
+// mln::image2d<mln::value::int_u8> map_green;
+// mln::image2d<mln::value::int_u8> map_blue;
+
+// mln::image1d<unsigned> histo_red;
+// mln::image1d<unsigned> histo_green;
+// mln::image1d<unsigned> histo_blue;
+
+ t_minus minus_red;
+ t_minus minus_green;
+ t_minus minus_blue;
+
+ t_times times_red;
+ t_times times_green;
+ t_times times_blue;
+
+ float error_red;
+ float error_green;
+ float error_blue;
+
+ float error;
+
+
+ mln::io::ppm::load(original_rgb8, original.c_str());
+ mln::io::ppm::load(reduced_rgb8, reduced.c_str());
+
+ original_red = mln::data::transform(original_rgb8, t_component_red());
+ original_green = mln::data::transform(original_rgb8, t_component_green());
+ original_blue = mln::data::transform(original_rgb8, t_component_blue());
+
+ reduced_red = mln::data::transform(reduced_rgb8, t_component_red());
+ reduced_green = mln::data::transform(reduced_rgb8, t_component_green());
+ reduced_blue = mln::data::transform(reduced_rgb8, t_component_blue());
+
+ minus_red = (original_red - reduced_red);
+ times_red = minus_red * minus_red;
+
+ minus_green = (original_green - reduced_green);
+ times_green = minus_green * minus_green;
+
+ minus_blue = (original_blue - reduced_blue);
+ times_blue = minus_blue * minus_blue;
+
+ error_red = mln::data::compute(t_mean(), times_red);
+ error_green = mln::data::compute(t_mean(), times_green);
+ error_blue = mln::data::compute(t_mean(), times_blue);
+
+// map_red = mln::data::stretch(t_int_u8(), times_red);
+// map_green = mln::data::stretch(t_int_u8(), times_blue);
+// map_blue = mln::data::stretch(t_int_u8(), times_green);
+
+// histo_red = mln::data::compute(t_histo(), map_red);
+// histo_green = mln::data::compute(t_histo(), map_green);
+// histo_blue = mln::data::compute(t_histo(), map_blue);
+
+// mln::io::plot::save_image_sh(histo_red, "histo_red.sh");
+// mln::io::plot::save_image_sh(histo_green,"histo_green.sh");
+// mln::io::plot::save_image_sh(histo_blue, "histo_blue.sh");
+
+// mln::io::pgm::save(map_red, "red.pgm");
+// mln::io::pgm::save(map_green,"green.pgm");
+// mln::io::pgm::save(map_blue, "blue.pgm");
+
+ error = (error_red + error_green + error_blue)/3.0;
+ error = mln::math::sqrt(error);
+ error = 20 * log(255/error);
+
+// Le PNSNR semble offrir plus d'espace pour la discrimination
+// Si les images sont identiques ==> PNSNR = +inf
+// Si les images sont très différentes ==> PNSNR = 0
+
+ return error;
+}
+
+
+/// \brief The main entry.
+///
+/// This is the front end for error classification. This is the big
+/// loop where we walk other image data bases. Computation of
+/// automatic thresholds are called from here.
+int main()
+{
+ typedef boost::filesystem::path t_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+
+ mln::image1d<float> histo(256);
+ mln::image1d<float> histo_grp[2]; // histo by group
+
+ histo_grp[0].init_(mln::box1d(mln::point1d(0),mln::point1d(255)));
+ histo_grp[1].init_(mln::box1d(mln::point1d(0),mln::point1d(255)));
+
+ mln::data::fill(histo, mln::literal::zero);
+ mln::data::fill(histo_grp[0], mln::literal::zero);
+ mln::data::fill(histo_grp[1], mln::literal::zero);
+
+ t_path original_path[] = {ICDAR_20P_INPUT_IMG_PATH,
+ AFP_PPM_IMG_PATH};
+
+// t_path reduced1_path[] = {ICDAR_20P_MGK30_IMG_PATH,
+// AFP_MGK30_IMG_PATH};
+
+// t_path reduced1_path[] = {ICDAR_20P_MGK20_IMG_PATH,
+// AFP_MGK20_IMG_PATH};
+
+ t_path reduced1_path[] = {ICDAR_20P_MGK10_IMG_PATH,
+ AFP_MGK10_IMG_PATH};
+
+// t_path reduced2_path[] = {ICDAR_20P_GMP30_IMG_PATH,
+// AFP_GMP30_IMG_PATH};
+
+// t_path reduced2_path[] = {ICDAR_20P_GMP20_IMG_PATH,
+// AFP_GMP20_IMG_PATH};
+
+ t_path reduced2_path[] = {ICDAR_20P_GMP10_IMG_PATH,
+ AFP_GMP10_IMG_PATH};
+
+
+ std::cout << "#!/usr/bin/gnuplot" <<
std::endl;
+ std::cout << "set terminal x11 persist 1" <<
std::endl;
+ std::cout << "ERROR" <<
std::endl;
+ std::cout << "plot '-' using 1 with point notitle,\\"
<< std::endl;
+ std::cout << " '-' using 1 with point notitle"
<< std::endl;
+
+ for (int i = 0; i < 2; i++)
+ {
+ if (boost::filesystem::exists(original_path[i]) &&
+ boost::filesystem::exists(reduced1_path[i]) &&
+ boost::filesystem::exists(reduced2_path[i]) &&
+ boost::filesystem::is_directory(original_path[i]) &&
+ boost::filesystem::is_directory(reduced1_path[i]) &&
+ boost::filesystem::is_directory(reduced2_path[i]))
+ {
+ boost::filesystem::system_complete(original_path[i]);
+ const t_iter_path end_iter;
+ float error1 = 0.0;
+ float error2 = 0.0;
+ t_path leaf;
+ t_path reduced1_file;
+ t_path reduced2_file;
+
+ for (t_iter_path dir_iter(original_path[i]);end_iter!=dir_iter;++dir_iter)
+ {
+ leaf = dir_iter->path().leaf();
+ reduced1_file = reduced1_path[i] / leaf;
+ reduced2_file = reduced2_path[i] / leaf;
+
+ error1 = error_test(dir_iter->path().string(), reduced1_file.string());
+ error2 = error_test(dir_iter->path().string(), reduced2_file.string());
+
+ float a1 = 1;
+ short v1 = (short)mln::math::floor(error2+0.4999);
+ mln::opt::at(histo,v1) += a1;
+ mln::opt::at(histo_grp[i],v1) += a1;
+
+// float a1 = error2 - mln::math::floor(error2);
+// float a2 = mln::math::ceil(error2) - error2;
+// short v1 = (short)mln::math::floor(error2);
+// short v2 = (short)mln::math::ceil(error2);
+// mln::opt::at(histo,v1) += a1;
+// mln::opt::at(histo,v2) += a2;
+// mln::opt::at(histo_grp[i],v1) += a1;
+// mln::opt::at(histo_grp[i],v2) += a2;
+
+ std::cout << error1 << " ";
+ std::cout << error2 << " ";
+ std::cout << "# " << dir_iter->path().leaf() <<
std::endl;
+ }
+ std::cout << "e" << std::endl;
+ }
+ }
+
+ mln::io::plot::save_image_sh(histo, "histo.sh");
+ mln::io::plot::save_image_sh(histo_grp[1], "histo_grp1.sh");
+ mln::io::plot::save_image_sh(histo_grp[0], "histo_grp2.sh");
+
+ float threshold = fisher_analysis(histo);
+ float threshold2 = threshold_histo(avg_histo(histo_grp[1]),
+ var_histo(histo_grp[1]),
+ avg_histo(histo_grp[0]),
+ var_histo(histo_grp[0]));
+ float threshold3 = threshold2_histo(avg_histo(histo_grp[1]),
+ var_histo(histo_grp[1]),
+ avg_histo(histo_grp[0]),
+ var_histo(histo_grp[0]));
+ float threshold4 = min_error(histo_grp[1],histo_grp[0]);
+
+ std::cout << "threshold = " << threshold << std::endl;
+ std::cout << "threshold2 = " << threshold2 << std::endl;
+ std::cout << "threshold3 = " << threshold3 << std::endl;
+ std::cout << "threshold4 = " << threshold4 << std::endl;
+ std::cout << "avg_grp1 = " << avg_histo(histo_grp[1]) <<
std::endl;
+ std::cout << "avg_grp2 = " << avg_histo(histo_grp[0]) <<
std::endl;
+
+ // compute the classification matrix
+ // for each sub population
+
+ float c00 = cnt_histo(histo_grp[1] | mln::box1d(mln::point1d(0),
+ mln::point1d(threshold)));
+
+ float c10 = cnt_histo(histo_grp[1] | mln::box1d(mln::point1d(threshold+1),
+ mln::point1d(255)));
+
+ float c01 = cnt_histo(histo_grp[0] | mln::box1d(mln::point1d(0),
+ mln::point1d(threshold)));
+
+ float c11 = cnt_histo(histo_grp[0] | mln::box1d(mln::point1d(threshold+1),
+ mln::point1d(255)));
+
+
+ std::cout << "pop0 = " << cnt_histo(histo_grp[1]) <<
std::endl;
+ std::cout << "pop1 = " << cnt_histo(histo_grp[0]) <<
std::endl;
+ std::cout << std::endl;
+
+ std::cout << "c00 = " << c00 << std::endl;
+ std::cout << "c10 = " << c10 << std::endl;
+ std::cout << "c01 = " << c01 << std::endl;
+ std::cout << "c11 = " << c11 << std::endl;
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/histo/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/histo/Makefile.am
diff --git a/scribo/sandbox/green/exp/annotating/histo/histo.cc
b/scribo/sandbox/green/exp/annotating/histo/histo.cc
new file mode 100644
index 0000000..90b18e4
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/histo/histo.cc
@@ -0,0 +1,366 @@
+// 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 Build normalized histograms for visualization only.
+///
+/// The goal of this code is to build every normalized histograms of
+/// an image database for visual inspection. It enables the
+/// comparaison of the densities of each image database and the
+/// understanding of the differences in this space.
+
+
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/arith/minus.hh>
+#include <mln/arith/div.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+
+#include <mln/data/convert.hh>
+#include <mln/data/compute.hh>
+#include <mln/data/stretch.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/literal/zero.hh>
+#include <mln/literal/colors.hh>
+#include <mln/literal/grays.hh>
+
+#include <mln/math/max.hh>
+#include <mln/math/min.hh>
+#include <mln/math/sqr.hh>
+#include <mln/math/sqrt.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/geom/nsites.hh>
+
+#include <mln/fun/v2v/rgb_to_hue_map.hh>
+#include <mln/fun/v2v/rgb_to_saturation_map.hh>
+#include <mln/fun/v2v/rgb_to_value_map.hh>
+#include <mln/fun/v2v/component.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/value/rgb8.hh>
+
+//============================================================================//
+// HISTOGRAM
+//============================================================================//
+
+/// \brief Count the number of pixel in the histogram.
+///
+/// \param[in] histo_ the image which represents the histogram.
+///
+/// \return the number of pixels in the domain.
+///
+/// This is simple counting routine that compute the number of pixels
+/// in the domain of the histogram. For each site, it sums the
+/// frequencies associated to its site.
+template <typename I>
+mln_value(I) cnt_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) cnt = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ cnt += histo(p);
+ }
+
+ return cnt;
+}
+
+/// \brief The computing of the normalized histogram.
+///
+/// \param[in] input the name of the input image.
+/// \param[in] output_map the name of the specific map (hue,sat,val,R,G,B).
+/// \param[in] output_histo the name of the output normalized histogram.
+/// \param[in] space the name of the studied channel (R,G,B,H,S,V).
+///
+/// Compute the normalized histogram in the given channel. First get
+/// the channel from the RGB space or the HSV space and then compute
+/// its normalized histogram. Normalization is done by dividing each
+/// frequency by the sum of frequencies. It's a way to make the
+/// histogram independant from the dimension of the input image and
+/// then to compare different image databases together.
+void histo(const std::string input,
+ const std::string output_map,
+ const std::string output_histo,
+ const char space)
+
+{
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::fun::v2v::rgb_to_hue_map<8> t_rgb_to_hue_map;
+ typedef mln::fun::v2v::rgb_to_saturation_map<8> t_rgb_to_sat_map;
+ typedef mln::fun::v2v::rgb_to_value_map<8> t_rgb_to_val_map;
+ typedef mln::fun::v2v::component<t_rgb8,0> t_component_r;
+ typedef mln::fun::v2v::component<t_rgb8,1> t_component_g;
+ typedef mln::fun::v2v::component<t_rgb8,2> t_component_b;
+
+ mln::image2d<mln::value::rgb8> input_rgb8;
+ mln::image2d<mln::value::int_u8> map;
+ mln::image1d<unsigned> histo;
+ mln::image1d<float> histo_float;
+ float sum;
+
+ mln::io::ppm::load(input_rgb8, input.c_str());
+
+ switch(space)
+ {
+ case 'h': map = mln::data::transform(input_rgb8, t_rgb_to_hue_map()); break;
+ case 's': map = mln::data::transform(input_rgb8, t_rgb_to_sat_map()); break;
+ case 'v': map = mln::data::transform(input_rgb8, t_rgb_to_val_map()); break;
+ case 'r': map = mln::data::transform(input_rgb8, t_component_r()); break;
+ case 'g': map = mln::data::transform(input_rgb8, t_component_g()); break;
+ case 'b': map = mln::data::transform(input_rgb8, t_component_b()); break;
+ default: break;// crash
+ }
+
+ histo = mln::data::compute(mln::accu::meta::stat::histo1d(), map);
+ sum = cnt_histo(histo);
+ histo_float = mln::data::convert(float(), histo) / sum;
+
+ mln::io::pgm::save(map, output_map.c_str());
+ mln::io::plot::save_image_sh(histo_float, output_histo.c_str());
+}
+
+//============================================================================//
+// MAIN
+//============================================================================//
+
+
+/// \brief The main entry.
+///
+/// This a front end to compute histogram with boost plumberies. There
+/// is 2 uses cases, the computing over the icdar database and over
+/// the afp database. We force the computing over the six channel
+/// (H,S,V,R,G,B) in order to select the channel the most specific for
+/// a database. It seems that saturation channel and value channel are
+/// the most specific to describe each database. Take care to
+/// coherence of the output directories for each source of images.
+int main()
+{
+ typedef boost::filesystem::path t_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+
+// t_path full_path[] = {t_path(ICDAR_20P_TEXT_ONLY_IMG_PATH),
+// t_path(ICDAR_20P_TEXT_COLOR_IMG_PATH),
+// t_path(ICDAR_20P_TEXT_PHOTO_IMG_PATH)};
+
+// t_path full_path[] = {t_path(AFP_INPUT_IMG_PATH)};
+// t_path full_path[] = {t_path(AFP_GMP30_IMG_PATH)};
+// t_path full_path[] = {t_path(AFP_GMP20_IMG_PATH)};
+// t_path full_path[] = {t_path(AFP_GMP10_IMG_PATH)};
+// t_path full_path[] = {t_path(AFP_MGK30_IMG_PATH)};
+// t_path full_path[] = {t_path(AFP_MGK20_IMG_PATH)};
+// t_path full_path[] = {t_path(AFP_MGK10_IMG_PATH)};
+
+// t_path full_path[] = {t_path(ICDAR_20P_INPUT_IMG_PATH)};
+// t_path full_path[] = {t_path(ICDAR_20P_GMP30_IMG_PATH)};
+ t_path full_path[] = {t_path(ICDAR_20P_GMP20_IMG_PATH)};
+// t_path full_path[] = {t_path(ICDAR_20P_GMP10_IMG_PATH)};
+// t_path full_path[] = {t_path(ICDAR_20P_MGK30_IMG_PATH)};
+// t_path full_path[] = {t_path(ICDAR_20P_MGK20_IMG_PATH)};
+// t_path full_path[] = {t_path(ICDAR_20P_MGK10_IMG_PATH)};
+
+ for (int i = 0; i < 1; ++i)
+ {
+ if (boost::filesystem::exists(full_path[i]) &&
+ boost::filesystem::is_directory(full_path[i]))
+ {
+ boost::filesystem::system_complete(full_path[i]);
+ const t_iter_path end_iter;
+ t_path directory;
+ t_path leaf;
+ t_path output_map;
+ t_path output_histo;
+
+ std::cerr << "entering " << full_path[i] <<
std::endl;
+
+ for (t_iter_path dir_iter(full_path[i]); end_iter != dir_iter; ++dir_iter)
+ {
+ std::cerr << dir_iter->path() << std::endl;
+
+ leaf = dir_iter->path().leaf();
+
+// directory = ANNOTATING_AFP_R_INPUT_RET_PATH;
+// directory = ANNOTATING_AFP_R_GMP30_RET_PATH;
+// directory = ANNOTATING_AFP_R_GMP20_RET_PATH;
+// directory = ANNOTATING_AFP_R_GMP10_RET_PATH;
+// directory = ANNOTATING_AFP_R_MGK30_RET_PATH;
+// directory = ANNOTATING_AFP_R_MGK20_RET_PATH;
+// directory = ANNOTATING_AFP_R_MGK10_RET_PATH;
+
+// directory = ANNOTATING_ICDAR_R_INPUT_RET_PATH;
+// directory = ANNOTATING_ICDAR_R_GMP30_RET_PATH;
+ directory = ANNOTATING_ICDAR_R_GMP20_RET_PATH;
+// directory = ANNOTATING_ICDAR_R_GMP10_RET_PATH;
+// directory = ANNOTATING_ICDAR_R_MGK30_RET_PATH;
+// directory = ANNOTATING_ICDAR_R_MGK20_RET_PATH;
+// directory = ANNOTATING_ICDAR_R_MGK10_RET_PATH;
+ output_histo = change_extension(directory / leaf, ".sh");
+ output_map = change_extension(directory / leaf, ".pgm");
+
+ histo(dir_iter->path().string(),
+ output_map.string(),
+ output_histo.string(),
+ 'r');
+
+// directory = ANNOTATING_AFP_G_INPUT_RET_PATH;
+// directory = ANNOTATING_AFP_G_GMP30_RET_PATH;
+// directory = ANNOTATING_AFP_G_GMP20_RET_PATH;
+// directory = ANNOTATING_AFP_G_GMP10_RET_PATH;
+// directory = ANNOTATING_AFP_G_MGK30_RET_PATH;
+// directory = ANNOTATING_AFP_G_MGK20_RET_PATH;
+// directory = ANNOTATING_AFP_G_MGK10_RET_PATH;
+
+// directory = ANNOTATING_ICDAR_G_INPUT_RET_PATH;
+// directory = ANNOTATING_ICDAR_G_GMP30_RET_PATH;
+ directory = ANNOTATING_ICDAR_G_GMP20_RET_PATH;
+// directory = ANNOTATING_ICDAR_G_GMP10_RET_PATH;
+// directory = ANNOTATING_ICDAR_G_MGK30_RET_PATH;
+// directory = ANNOTATING_ICDAR_G_MGK20_RET_PATH;
+// directory = ANNOTATING_ICDAR_G_MGK10_RET_PATH;
+ output_histo = change_extension(directory / leaf, ".sh");
+ output_map = change_extension(directory / leaf, ".pgm");
+
+ histo(dir_iter->path().string(),
+ output_map.string(),
+ output_histo.string(),
+ 'g');
+
+// directory = ANNOTATING_AFP_B_INPUT_RET_PATH;
+// directory = ANNOTATING_AFP_B_GMP30_RET_PATH;
+// directory = ANNOTATING_AFP_B_GMP20_RET_PATH;
+// directory = ANNOTATING_AFP_B_GMP10_RET_PATH;
+// directory = ANNOTATING_AFP_B_MGK30_RET_PATH;
+// directory = ANNOTATING_AFP_B_MGK20_RET_PATH;
+// directory = ANNOTATING_AFP_B_MGK10_RET_PATH;
+
+// directory = ANNOTATING_ICDAR_B_INPUT_RET_PATH;
+// directory = ANNOTATING_ICDAR_B_GMP30_RET_PATH;
+ directory = ANNOTATING_ICDAR_B_GMP20_RET_PATH;
+// directory = ANNOTATING_ICDAR_B_GMP10_RET_PATH;
+// directory = ANNOTATING_ICDAR_B_MGK30_RET_PATH;
+// directory = ANNOTATING_ICDAR_B_MGK20_RET_PATH;
+// directory = ANNOTATING_ICDAR_B_MGK10_RET_PATH;
+ output_histo = change_extension(directory / leaf, ".sh");
+ output_map = change_extension(directory / leaf, ".pgm");
+
+ histo(dir_iter->path().string(),
+ output_map.string(),
+ output_histo.string(),
+ 'b');
+
+// directory = ANNOTATING_AFP_H_INPUT_RET_PATH;
+// directory = ANNOTATING_AFP_H_GMP30_RET_PATH;
+// directory = ANNOTATING_AFP_H_GMP20_RET_PATH;
+// directory = ANNOTATING_AFP_H_GMP10_RET_PATH;
+// directory = ANNOTATING_AFP_H_MGK30_RET_PATH;
+// directory = ANNOTATING_AFP_H_MGK20_RET_PATH;
+// directory = ANNOTATING_AFP_H_MGK10_RET_PATH;
+
+// directory = ANNOTATING_ICDAR_H_INPUT_RET_PATH;
+// directory = ANNOTATING_ICDAR_H_GMP30_RET_PATH;
+ directory = ANNOTATING_ICDAR_H_GMP20_RET_PATH;
+// directory = ANNOTATING_ICDAR_H_GMP10_RET_PATH;
+// directory = ANNOTATING_ICDAR_H_MGK30_RET_PATH;
+// directory = ANNOTATING_ICDAR_H_MGK20_RET_PATH;
+// directory = ANNOTATING_ICDAR_H_MGK10_RET_PATH;
+ output_histo = change_extension(directory / leaf, ".sh");
+ output_map = change_extension(directory / leaf, ".pgm");
+
+ histo(dir_iter->path().string(),
+ output_map.string(),
+ output_histo.string(),
+ 'h');
+
+// directory = ANNOTATING_AFP_S_INPUT_RET_PATH;
+// directory = ANNOTATING_AFP_S_GMP30_RET_PATH;
+// directory = ANNOTATING_AFP_S_GMP20_RET_PATH;
+// directory = ANNOTATING_AFP_S_GMP10_RET_PATH;
+// directory = ANNOTATING_AFP_S_MGK30_RET_PATH;
+// directory = ANNOTATING_AFP_S_MGK20_RET_PATH;
+// directory = ANNOTATING_AFP_S_MGK10_RET_PATH;
+
+// directory = ANNOTATING_ICDAR_S_INPUT_RET_PATH;
+// directory = ANNOTATING_ICDAR_S_GMP30_RET_PATH;
+ directory = ANNOTATING_ICDAR_S_GMP20_RET_PATH;
+// directory = ANNOTATING_ICDAR_S_GMP10_RET_PATH;
+// directory = ANNOTATING_ICDAR_S_MGK30_RET_PATH;
+// directory = ANNOTATING_ICDAR_S_MGK20_RET_PATH;
+// directory = ANNOTATING_ICDAR_S_MGK10_RET_PATH;
+ output_histo = change_extension(directory / leaf, ".sh");
+ output_map = change_extension(directory / leaf, ".pgm");
+
+ histo(dir_iter->path().string(),
+ output_map.string(),
+ output_histo.string(),
+ 's');
+
+// directory = ANNOTATING_AFP_V_INPUT_RET_PATH;
+// directory = ANNOTATING_AFP_V_GMP30_RET_PATH;
+// directory = ANNOTATING_AFP_V_GMP20_RET_PATH;
+// directory = ANNOTATING_AFP_V_GMP10_RET_PATH;
+// directory = ANNOTATING_AFP_V_MGK30_RET_PATH;
+// directory = ANNOTATING_AFP_V_MGK20_RET_PATH;
+// directory = ANNOTATING_AFP_V_MGK10_RET_PATH;
+
+// directory = ANNOTATING_ICDAR_V_INPUT_RET_PATH;
+// directory = ANNOTATING_ICDAR_V_GMP30_RET_PATH;
+ directory = ANNOTATING_ICDAR_V_GMP20_RET_PATH;
+// directory = ANNOTATING_ICDAR_V_GMP10_RET_PATH;
+// directory = ANNOTATING_ICDAR_V_MGK30_RET_PATH;
+// directory = ANNOTATING_ICDAR_V_MGK20_RET_PATH;
+// directory = ANNOTATING_ICDAR_V_MGK10_RET_PATH;
+ output_histo = change_extension(directory / leaf, ".sh");
+ output_map = change_extension(directory / leaf, ".pgm");
+
+ histo(dir_iter->path().string(),
+ output_map.string(),
+ output_histo.string(),
+ 'v');
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/hsv/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/hsv/Makefile.am
diff --git a/scribo/sandbox/green/exp/annotating/hsv/hsv.cc
b/scribo/sandbox/green/exp/annotating/hsv/hsv.cc
new file mode 100644
index 0000000..507d07b
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/hsv/hsv.cc
@@ -0,0 +1,912 @@
+// 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 Implement the Millet HSV operator [millet.phd.2008.pdf]
+///
+/// This is the Millet code for moving from RGB space to Hue
+/// one. Formulae are classical, we can find them on the web.
+///
+/// Val = max(R,G,B).
+/// Sat = (max(R,G,B) - min(R,G,B))/max(R,G,B).
+/// IF R = max(R,G,B) THEN Hue = 60 * [(V-B)/(max(R,G,B)-min(R,G,B))].
+/// IF G = max(R,G,B) THEN Hue = 60 * [2 + (B-R)/(max(R,G,B)-min(R,G,B))].
+/// IF B = max(R,G,B) THEN Hue = 60 * [4 + (R-G)/(max(R,G,B)-min(R,G,B))].
+///
+/// This operator try to integrate many processing in one shot, after
+/// HSV transformation.
+
+
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/arith/minus.hh>
+#include <mln/arith/div.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+
+#include <mln/data/convert.hh>
+#include <mln/data/compute.hh>
+#include <mln/data/stretch.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/literal/zero.hh>
+#include <mln/literal/colors.hh>
+#include <mln/literal/grays.hh>
+
+#include <mln/math/max.hh>
+#include <mln/math/min.hh>
+#include <mln/math/sqr.hh>
+#include <mln/math/sqrt.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/geom/nsites.hh>
+
+#include <mln/fun/v2v/rgb_to_hue_map.hh>
+#include <mln/fun/v2v/rgb_to_saturation_map.hh>
+#include <mln/fun/v2v/rgb_to_value_map.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/value/rgb8.hh>
+
+//============================================================================//
+// HISTOGRAM
+//============================================================================//
+
+/// Histogram
+/// \{
+/// \brief Histogram processing methods.
+///
+/// In this part, we define methods for histogram processing as average,
+/// peak, variance etc ...
+
+
+/// \brief Sum all the bins of the histogram.
+///
+/// \param[in] img the histogram based on image.
+///
+/// \return the sum of the overall bins.
+///
+/// Sum evry bins and return the result.
+template <typename I>
+mln_value(I) count_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) result = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ result += histo(p);
+
+ return result;
+}
+
+/// \brief Sum the whole frequencies.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the number of pixels in the domain.
+///
+/// By summing all the frequencies of the domain, we count in fact the
+/// number of pixels in the image.
+template <typename I>
+mln_value(I) sum_frequency_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) sum = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ sum += histo(p);
+
+ return sum;
+}
+
+/// \brief Count the null frequencies.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the number of null frequencies.
+///
+/// It's a way to access the number of distinct colors in the
+/// histogram by comparing it with the histogram domain.
+template <typename I>
+mln_value(I) count_null_frequency_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ mln_value(I) count = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ if (0 == histo(p))
+ count++;
+
+ return count;
+}
+
+/// \brief Find the peak of the histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the bin which contains the greatest value.
+///
+/// Compute the position of the peak of the histogram. To do this, we
+/// view evrey bin and we maintain the maxima of the values and the
+/// position. At the end, we return the position which contains the
+/// greatest value.
+template <typename I>
+mln_coord(mln_site_(I)) peak_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the peak of the histogram
+ mln_value(I) v_max = mln::opt::at(histo, mln::literal::zero);
+ mln_coord(mln_site_(I)) p_max = mln::literal::zero;
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ if (v_max < histo(p))
+ {
+ v_max = histo(p);
+ p_max = p.ind();
+ }
+ }
+
+ return p_max;
+}
+
+/// \brief Find the maximum frequency of the histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the maximum frequency of the histogram.
+///
+/// Find the peak and return its value, not its position. We use that
+/// function to normalize histograms.
+template <typename I>
+mln_value(I) max_frequency_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the value of the peak from the histogram
+ mln_value(I) max = mln::opt::at(histo, mln::literal::zero);
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ max = mln::math::max(histo(p),max);
+ }
+
+ return max;
+}
+
+/// \brief Find the mean of the histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the aveerage of the histogram.
+///
+/// Compute the mean.
+template <typename I>
+float mean_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the mean of the histogram
+ float sum = 0;
+ float mean = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ sum += histo(p);
+ mean += p.ind()*histo(p);
+ }
+
+ mean = mean / sum;
+
+ return mean;
+}
+
+/// \brief Compare the histogram with the equi distributed histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the distance between the equi distributed histogram.
+///
+/// Compute the square euclidian distance between histogram and the
+/// equi distributed histogram. The equi distributed histogram is an
+/// histogram in which each bin has the same frequency (id est 1/256
+/// for instance). The integral equals one for this two
+/// histograms. This is a major contribution test to differentiate
+/// image database.
+template <typename I>
+float cmp_equi_frequency_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the mean of the histogram
+ float sum = 0;
+ float var = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ sum += histo(p);
+ var += mln::math::sqr(histo(p) - (1/256.0));
+ }
+
+ var = var / sum;
+
+ return var;
+}
+
+/// \brief Compute the variance on the histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the variance.
+///
+/// Compute the variance by substracting the mean.
+template <typename I>
+float var_histo(const mln::Image<I>& histo_, float mean)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the mean of the histogram
+ float sum = 0;
+ float var = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ sum += histo(p);
+ var += mln::math::sqr(p.ind() - mean) * histo(p);
+ }
+
+ var = var / sum;
+
+ return var;
+}
+
+/// \brief Find the mean of the histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the aveerage of the histogram.
+///
+/// Compute the mean.
+template <typename I>
+float mean_frequency_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the mean of the histogram
+ float sum = 0;
+ float mean = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ sum++;
+ mean += histo(p);
+ }
+
+ mean = mean / sum;
+
+ return mean;
+}
+
+/// \brief Compute the standard deviation on the histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the dstandard deviation.
+///
+/// Compute the standard deviation by substracting the mean
+template <typename I>
+float stddev_frequency_histo(const mln::Image<I>& histo_, float mean)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the var of the histogram
+ float sum = 0;
+ float var = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ sum++;
+ var += mln::math::sqr(histo(p)-mean);
+ }
+
+ var = mln::math::sqrt(var / sum);
+
+ return var;
+}
+/// \}
+
+//============================================================================//
+// HUE TEST
+//============================================================================//
+
+/// Hue test
+/// \{
+/// \brief Hue test image processing stuff.
+///
+/// In this part, we define every thing that is correlated to the hue analysis.
+
+
+/// \brief Label a grey value.
+///
+/// \param[in] int_u8 the grey value.
+///
+/// \return the reference color for this grey value.
+///
+/// Classify grey value in three class, white, black and medium_gray.
+mln::value::rgb8 label_val(const mln::value::int_u8 val)
+{
+ mln::value::rgb8 result;
+
+ if (82 > val)
+ result = mln::literal::black;
+ else if (179 > val)
+ result= mln::literal::medium_gray;
+ else
+ result = mln::literal::white;
+
+ return result;
+}
+
+
+/// \brief Label color with orange reference or brown reference.
+///
+/// \param[in] color the rgb8 color.
+/// \param[in] sat the HSV saturation.
+/// \param[in] val the HSV value.
+///
+/// \return the reference color with which it has been associated to.
+mln::value::rgb8 label_orange_or_brown(const mln::value::rgb8 color,
+ const mln::value::int_u8 sat,
+ const mln::value::int_u8 val)
+{
+ mln::value::rgb8 result;
+
+ if (mln::literal::orange == color)
+ {
+ unsigned dist_orange = mln::math::abs(sat - 184)
+ + mln::math::abs(val - 65);
+
+ unsigned dist_brown = mln::math::abs(sat - 255)
+ + mln::math::abs(val - 125);
+
+ if (dist_orange < dist_brown)
+ result = mln::literal::orange;
+ else
+ result = mln::literal::brown;
+ }
+ else
+ result = color;
+
+ return result;
+}
+
+
+/// \brief Label between yellow and green color.
+///
+/// \param[in] color the rgb8 color.
+/// \param[in] val the HSV value.
+///
+/// \return the reference color associated to that color.
+mln::value::rgb8 label_yellow_or_green(const mln::value::rgb8 color,
+ const mln::value::int_u8 val)
+{
+ mln::value::rgb8 result;
+
+ if (mln::literal::yellow == color)
+ {
+ // Is it green or yellow ?
+ if (80 > val)
+ result = mln::literal::green;
+ else
+ result = mln::literal::yellow;
+ }
+ else
+ return color;
+
+ return result;
+}
+
+
+/// \brief Label hue color.
+///
+/// \param[in] hue the HSV hue canal for a pixel.
+///
+/// \return a hue segmentation of the hue wheel.
+///
+/// The old classification given by Millet is commented. Mine is ready
+/// to use. We need to change reference colors to make the
+/// primary colors, the secondary ones, etc...
+mln::value::rgb8 label_hue(const mln::value::int_u8 hue)
+{
+ mln::value::rgb8 result;
+
+
+ if (10 > hue)
+ result = mln::literal::red;
+ else if (32 > hue)
+ result = mln::literal::orange;
+ else if (53 > hue)
+ result = mln::literal::yellow;
+ else if (74 > hue)
+ result = mln::literal::green; // chartreuse
+ else if (96 > hue)
+ result = mln::literal::green;
+ else if (116 > hue)
+ result = mln::literal::green;// turquoise, aigue-marine
+ else if (138 > hue)
+ result = mln::literal::green; // cyan
+ else if (159 > hue)
+ result = mln::literal::blue; // azur
+ else if (181 > hue)
+ result = mln::literal::blue;
+ else if (202 > hue)
+ result = mln::literal::violet;
+ else if (223 > hue)
+ result = mln::literal::pink;
+ else // if (244 > hue)
+ result = mln::literal::red;
+
+ return result;
+}
+
+/// \brief The hue test.
+///
+/// \param[in] input the name of the input image.
+/// \param[in] output the name of the histogram to output.
+/// \param[in] tmp the name of the hue map to output.
+/// \param[in] threshold the limit to compute the histogram contribution.
+///
+/// \return the proportion of pixels that pass the test.
+///
+/// This is an augmented test. We first normalized the histogram to
+/// obtain a discrete distribution. Then we compute the mean (or the
+/// peak, i don't really know what is the best) and we look at the
+/// proportion of the pixels around the mean or the peak. This
+/// proportion tell us how histogram distribution is concentrated
+/// around the modal value. If a hue modal value exist, we can say
+/// that the image is colorized.
+float hue_test(const std::string input,
+ const std::string output,
+ const std::string tmp,
+ const short threshold)
+
+{
+ typedef mln::fun::v2v::rgb_to_hue_map<8> t_rgb_to_hue_map;
+
+ mln::image2d<mln::value::rgb8> input_rgb8;
+ mln::image2d<mln::value::int_u8> map;
+ mln::image1d<unsigned> histo;
+ mln::image1d<float> histo_float;
+ float cnt1;
+ float cnt2;
+ float prop;
+ short peak;
+ mln::value::rgb8 color;
+ float sum;
+ mln::point1d inf;
+ mln::point1d sup;
+
+ mln::io::ppm::load(input_rgb8, input.c_str());
+
+ map = mln::data::transform(input_rgb8, t_rgb_to_hue_map());
+ histo = mln::data::compute(mln::accu::meta::stat::histo1d(), map);
+ sum = sum_frequency_histo(histo);
+ histo_float = mln::data::convert(float(), histo) / sum;
+ peak = mean_histo(histo); //peak_histo(histo);
+ color = label_hue(peak);
+ inf = mln::point1d(mln::math::max(0, peak-threshold));
+ sup = mln::point1d(mln::math::min(255, peak+threshold));
+ cnt1 = count_histo(histo_float|mln::box1d(inf,sup));
+ cnt2 = count_histo(histo_float);
+ prop = ((100.0 * cnt1) / cnt2);
+
+ mln::io::plot::save_image_sh(histo_float, output.c_str());
+ mln::io::pgm::save(map, tmp.c_str());
+// std::cout << "peak = " << peak << std::endl;
+// std::cout << "color = " << color << std::endl;
+
+ return prop;
+}
+/// \}
+
+//============================================================================//
+// SATURATION TEST
+//============================================================================//
+
+/// Saturation test
+/// \{
+/// \brief Saturation test image processing stuff.
+///
+/// In this part, we define every thing that is correlated to the
+/// saturation analysis.
+
+
+/// \brief The saturation test.
+///
+/// \param[in] input the name of the input image.
+/// \param[in] output the name of the histogram to output.
+/// \param[in] tmp the name of the hue map to output.
+/// \param[in] threshold for deciding which is low saturation or not.
+///
+/// \return the proportion of pixels which pass the test.
+///
+/// This is the augmented test, we normalized the histogram and then
+/// we count the proportion of the histogram below the threshold.
+float saturation_test(const std::string input,
+ const std::string output,
+ const std::string tmp,
+ const short threshold)
+
+{
+ typedef mln::fun::v2v::rgb_to_saturation_map<8> t_rgb_to_saturation_map;
+
+ mln::image2d<mln::value::rgb8> input_rgb8;
+ mln::image2d<mln::value::int_u8> map;
+ mln::image1d<unsigned> histo;
+ mln::image1d<float> histo_float;
+ float cnt1;
+ float cnt2;
+ float sum;
+ float prop;
+
+ mln::io::ppm::load(input_rgb8, input.c_str());
+
+ map = mln::data::transform(input_rgb8, t_rgb_to_saturation_map());
+ histo = mln::data::compute(mln::accu::meta::stat::histo1d(), map);
+ sum = sum_frequency_histo(histo);
+ histo_float = mln::data::convert(float(), histo) / sum;
+ cnt1 = count_histo(histo_float | mln::box1d(mln::point1d(0),
+ mln::point1d(threshold)));
+ cnt2 = count_histo(histo_float);
+ prop = ((100.0 * cnt1) / cnt2);
+
+ mln::io::plot::save_image_sh(histo_float, output.c_str());
+ mln::io::pgm::save(map, tmp.c_str());
+
+ return prop;
+}
+/// \}
+
+//============================================================================//
+// VALUE TEST
+//============================================================================//
+
+/// Value test
+/// \{
+/// \brief Value test image processing stuff.
+///
+/// In this part, we define every thing that is correlated to the
+/// value analysis.
+
+
+
+/// \brief The R function of Millet
+///
+/// \param[in] p the position of the pic.
+/// \param[in] histo_p the histo value of the pic.
+/// \param[in] x the position of the element which we compute the contrib.
+/// \param[in] histo_x the histo value of that element.
+///
+/// \result the contribution of the element x.
+///
+/// This function compute the variance-like contribution of an element
+/// x linked to the pic of the histogram. In fact, every thing is like
+/// we compute a square distance-like between the element x and the
+/// pic in the normalized histogram. Notice that the normalized
+/// histogram is the histogram divide by the value of it's pic. So at
+/// the pic, the value equals 1. It's a current representation of the
+/// histogram in image processing, we can find it in gimp for exemple.
+float r(short p, unsigned histo_p, short x, unsigned histo_x)
+{
+ float result = mln::math::sqr(((float)histo_x / histo_p) * (x-p));
+
+ return result;
+}
+
+/// \brief The stddev3 is an internal stuff.
+///
+/// \param[in] histo_ the image which represents the histogram.
+/// \param[in] peak the position of the histogram peak.
+///
+/// \return simple computing of deviation.
+///
+/// This is an internal stuff. It splits the computing for easy
+/// reusing practice. Sum the R contribution.
+template <typename I>
+float stddev3(const mln::Image<I>& histo_, unsigned peak)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Compute stddev
+
+ float stddev = 0.0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ stddev += r((short)peak, mln::opt::at(histo,peak), p.ind(), histo(p));
+ }
+
+ return stddev;
+}
+
+/// Brief compute the whole deviation of Millet
+///
+/// \param[in] image the input image to analyze.
+///
+/// \return the deviation.
+///
+/// The deviation uses the R function. It stats by finding the pic. If
+/// the pic is near the rigth border of the histo, compute the R
+/// function on the left neighbouring of the pic. If the pic is near
+/// the left border of the histo, compute the R function on the right
+/// neigbouring. Otherwise, compute the average of the right and left
+/// results. The selected neighbouring is composed of five pixels at
+/// the right or at the left of the pic. The detection of clipart
+/// assumes that the majority of the energy of the histogram is closed
+/// to the pic (five pixels around it). The test is generalized by
+/// making constants as parameters.
+template <typename I>
+float stddev2(const mln::Image<I>& histo_, unsigned peak, unsigned limit)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ float stddev_low = 0.0;
+ float stddev_up = 0.0;
+ float ret = 0.0;
+
+ // A transformer avec des iterators
+
+ if (250 > peak)
+ stddev_up = stddev3(histo |mln::box1d(mln::point1d(peak+1),
+ mln::point1d(peak+limit)), peak);
+
+ if (5 < peak)
+ stddev_low = stddev3(histo |mln::box1d(mln::point1d(peak-limit),
+ mln::point1d(peak-1)), peak);
+
+ ret = (250 < peak)? stddev_low : (5 > peak)? stddev_up :
+ (stddev_low + stddev_up)/2;
+
+ return ret;
+}
+
+
+/// \brief This is the Value test.
+///
+/// \param[in] input the name of the input image.
+/// \param[in] output the name of result histogram.
+/// \param[in] tmp the name of the output value (HSV) map.
+/// \param[in] threshold the range around the peak where R is computed.
+///
+/// \return the proportion of pixels that pass the test.
+///
+/// This is the augmented version of the Millet test. This code is not
+/// stable. There is a lots of tests on. The Millet test is computed
+/// with stddev2 call. We test simple counting around the pic as we
+/// do for other tests but it's not really insteresting. The prop4 is
+/// the best for me. We test the difference between the distribution and the
+/// equi-distribution.
+float value_test(const std::string input,
+ const std::string output,
+ const std::string tmp,
+ const short threshold)
+
+{
+ typedef mln::fun::v2v::rgb_to_value_map<8> t_rgb_to_value_map;
+
+ mln::image2d<mln::value::rgb8> input_rgb8;
+ mln::image2d<mln::value::int_u8> map;
+ mln::image1d<unsigned> histo;
+ mln::image1d<float> histo_float;
+ float cnt1;
+ float cnt2;
+ float prop;
+ float sum;
+ float prop4;
+ short peak;
+ mln::point1d inf;
+ mln::point1d sup;
+
+
+ mln::io::ppm::load(input_rgb8, input.c_str());
+
+ map = mln::data::transform(input_rgb8, t_rgb_to_value_map());
+ histo = mln::data::compute(mln::accu::meta::stat::histo1d(), map);
+ sum = sum_frequency_histo(histo);
+ histo_float = mln::data::convert(float(), histo) / sum;
+ prop4 = cmp_equi_frequency_histo(histo_float);
+ peak = peak_histo(histo); // mean_histo(histo);
+ //prop = stddev2(histo, peak, threshold);
+ inf = mln::point1d(mln::math::max(0, peak-threshold));
+ sup = mln::point1d(mln::math::min(255, peak+threshold));
+ cnt1 = count_histo(histo_float|mln::box1d(inf,sup));
+ cnt2 = count_histo(histo_float);
+ prop = ((100.0 * cnt1) / cnt2);
+
+ std::cerr << "peak = " << peak << std::endl;
+ std::cerr << "inf = " << inf << std::endl;
+ std::cerr << "sup = " << sup << std::endl;
+ std::cerr << "cnt1 = " << cnt1 << std::endl;
+ std::cerr << "cnt2 = " << cnt2 << std::endl;
+ std::cerr << "prop = " << prop << std::endl;
+ std::cerr << "prop4= " << prop4 << std::endl;
+
+ mln::io::plot::save_image_sh(histo_float, output.c_str());
+ mln::io::pgm::save(map, tmp.c_str());
+
+ return prop;
+}
+
+//============================================================================//
+// MAIN
+//============================================================================//
+
+
+/// \brief The main entry.
+///
+/// This is a front end for launching image processing test. We deal
+/// with boost library to walk on image database directories. Nothing
+/// very interesting here, it is a lot of plumberies.
+int main()
+{
+ typedef boost::filesystem::path t_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+
+// t_path full_path[] = {t_path(ICDAR_20P_TEXT_ONLY_IMG_PATH),
+// t_path(ICDAR_20P_TEXT_COLOR_IMG_PATH),
+// t_path(ICDAR_20P_TEXT_PHOTO_IMG_PATH)};
+
+ t_path full_path[] = {t_path(AFP_PPM_IMG_PATH)};
+
+ std::cout << "#!/usr/bin/gnuplot" <<
std::endl;
+ std::cout << "set terminal x11 persist 1" <<
std::endl;
+ std::cout << "#HUE - SATURATION - VALUE" <<
std::endl;
+ std::cout << "plot '-' using 1:2 with point notitle,\\"
<< std::endl;
+ std::cout << " '-' using 1:2 with point notitle,\\"
<< std::endl;
+ std::cout << " '-' using 1:2 with point notitle"
<< std::endl;
+
+ for (int i = 0; i < 1; ++i)
+ {
+ if (boost::filesystem::exists(full_path[i]) &&
+ boost::filesystem::is_directory(full_path[i]))
+ {
+ boost::filesystem::system_complete(full_path[i]);
+ const t_iter_path end_iter;
+ float prop = 0.0;
+ t_path directory;
+ t_path leaf;
+ t_path output;
+ t_path tmp;
+
+ std::cerr << "entering " << full_path[i] <<
std::endl;
+
+ for (t_iter_path dir_iter(full_path[i]); end_iter != dir_iter; ++dir_iter)
+ {
+ std::cerr << dir_iter->path() << std::endl;
+ // concatenation de chaine
+// directory = (ANNOTATING_ICDAR_H_INPUT_RET_PATH);
+ directory = (ANNOTATING_AFP_H_INPUT_RET_PATH);
+ leaf = dir_iter->path().leaf();
+ output = change_extension(directory / leaf, ".sh");
+ tmp = change_extension(directory / leaf, ".pgm");
+
+ prop = hue_test(dir_iter->path().string(),
+ output.string(),
+ tmp.string(),
+ 20);
+
+ std::cout << prop << " ";
+
+// directory = (ANNOTATING_ICDAR_S_INPUT_RET_PATH);
+ directory = (ANNOTATING_AFP_S_INPUT_RET_PATH);
+ leaf = dir_iter->path().leaf();
+ output = change_extension(directory / leaf, ".sh");
+ tmp = change_extension(directory / leaf, ".pgm");
+
+ prop = saturation_test(dir_iter->path().string(),
+ output.string(),
+ tmp.string(),
+ 25);
+
+ std::cout << prop << " ";
+
+// directory = (ANNOTATING_ICDAR_V_INPUT_RET_PATH);
+ directory = (ANNOTATING_AFP_V_INPUT_RET_PATH);
+ leaf = dir_iter->path().leaf();
+ output = change_extension(directory / leaf, ".sh");
+ tmp = change_extension(directory / leaf, ".pgm");
+
+ prop = value_test(dir_iter->path().string(),
+ output.string(),
+ tmp.string(),
+ 15);
+
+ std::cout << prop << " ";
+ std::cout << "# " << dir_iter->path().leaf() <<
std::endl;
+ }
+ std::cout << "e" << std::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/hue/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/hue/Makefile.am
diff --git a/scribo/sandbox/green/exp/annotating/hue/hue.cc
b/scribo/sandbox/green/exp/annotating/hue/hue.cc
new file mode 100644
index 0000000..6e1195c
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/hue/hue.cc
@@ -0,0 +1,402 @@
+// 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 Implement the Millet hue operator [millet.phd.2008.pdf]
+///
+/// This is the Millet code for moving from RGB space to Hue
+/// one. Formulae are classical, we can find them on the web.
+///
+/// Val = max(R,G,B).
+/// Sat = (max(R,G,B) - min(R,G,B))/max(R,G,B).
+/// IF R = max(R,G,B) THEN Hue = 60 * [(V-B)/(max(R,G,B)-min(R,G,B))].
+/// IF G = max(R,G,B) THEN Hue = 60 * [2 + (B-R)/(max(R,G,B)-min(R,G,B))].
+/// IF B = max(R,G,B) THEN Hue = 60 * [4 + (R-G)/(max(R,G,B)-min(R,G,B))].
+
+
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/stretch.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/literal/colors.hh>
+#include <mln/literal/grays.hh>
+
+#include <mln/math/max.hh>
+#include <mln/math/min.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/geom/nsites.hh>
+
+#include <mln/fun/v2v/rgb_to_hue_map.hh>
+#include <mln/value/rgb8.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+
+
+/// \brief Label a grey value.
+///
+/// \param[in] int_u8 the grey value.
+///
+/// \return the reference color for this grey value.
+///
+/// Classify grey value in three class, white, black and medium_gray.
+mln::value::rgb8 label_val(const mln::value::int_u8 val)
+{
+ mln::value::rgb8 result;
+
+ if (82 > val)
+ result = mln::literal::black;
+ else if (179 > val)
+ result= mln::literal::medium_gray;
+ else
+ result = mln::literal::white;
+
+ return result;
+}
+
+
+/// \brief Label color with orange reference or brown reference.
+///
+/// \param[in] color the rgb8 color.
+/// \param[in] sat the HSV saturation.
+/// \param[in] val the HSV value.
+///
+/// \return the reference color with which it has been associated to.
+mln::value::rgb8 label_orange_or_brown(const mln::value::rgb8 color,
+ const mln::value::int_u8 sat,
+ const mln::value::int_u8 val)
+{
+ mln::value::rgb8 result;
+
+ if (mln::literal::orange == color)
+ {
+ unsigned dist_orange = mln::math::abs(sat - 184)
+ + mln::math::abs(val - 65);
+
+ unsigned dist_brown = mln::math::abs(sat - 255)
+ + mln::math::abs(val - 125);
+
+ if (dist_orange < dist_brown)
+ result = mln::literal::orange;
+ else
+ result = mln::literal::brown;
+ }
+ else
+ result = color;
+
+ return result;
+}
+
+/// \brief Label between yellow and green color.
+///
+/// \param[in] color the rgb8 color.
+/// \param[in] val the HSV value.
+///
+/// \return the reference color associated to that color.
+mln::value::rgb8 label_yellow_or_green(const mln::value::rgb8 color,
+ const mln::value::int_u8 val)
+{
+ mln::value::rgb8 result;
+
+ if (mln::literal::yellow == color)
+ {
+ // Is it green or yellow ?
+ if (80 > val)
+ result = mln::literal::green;
+ else
+ result = mln::literal::yellow;
+ }
+ else
+ return color;
+
+ return result;
+}
+
+
+/// \brief Label hue color.
+///
+/// \param[in] hue the HSV hue canal for a pixel.
+///
+/// \return a hue segmentation of the hue wheel.
+///
+/// The old classification given by Millet is commented. Mine is ready
+/// to use. We need to change reference colors to make the
+/// primary colors, the secondary ones, etc...
+mln::value::rgb8 label_hue(const mln::value::int_u8 hue)
+{
+ mln::value::rgb8 result;
+
+
+ if (10 > hue)
+ result = mln::literal::red;
+ else if (32 > hue)
+ result = mln::literal::orange;
+ else if (53 > hue)
+ result = mln::literal::yellow;
+ else if (74 > hue)
+ result = mln::literal::green; // chartreuse
+ else if (96 > hue)
+ result = mln::literal::green;
+ else if (116 > hue)
+ result = mln::literal::green;// turquoise, aigue-marine
+ else if (138 > hue)
+ result = mln::literal::green; // cyan
+ else if (159 > hue)
+ result = mln::literal::blue; // azur
+ else if (181 > hue)
+ result = mln::literal::blue;
+ else if (202 > hue)
+ result = mln::literal::violet;
+ else if (223 > hue)
+ result = mln::literal::pink;
+ else // if (244 > hue)
+ result = mln::literal::red;
+
+
+// if (14 > hue)
+// result = mln::literal::red;
+// else if (29 > hue)
+// result = mln::literal::orange;
+// else if (45 > hue)
+// result = mln::literal::yellow;
+// else if (113 > hue)
+// result = mln::literal::green;
+// else if (149 > hue)
+// result = mln::literal::cyan;
+// else if (205 > hue)
+// result = mln::literal::blue;
+// else if (235 > hue)
+// result = mln::literal::violet;
+// else if (242 > hue)
+// result = mln::literal::pink;
+// else
+// result = mln::literal::red;
+
+ return result;
+}
+
+
+/// \brief Sum all the bins of the histogram.
+///
+/// \param[in] img the histogram based on image.
+///
+/// \return the sum of the overall bins.
+///
+/// Sum evry bins and return the result.
+template <typename I>
+unsigned count_histo(const mln::Image<I>& img_)
+{
+ const I& img = exact(img_);
+
+ mln_precondition(img.is_valid());
+
+ unsigned result = 0;
+
+ mln_piter(I) p(img.domain());
+
+ for_all(p)
+ result += img(p);
+
+ return result;
+}
+
+/// \brief Find the peak of the histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the bin which contains the greatest value.
+///
+/// Compute the position of the peak of the histogram. To do this, we
+/// view evrey bin and we maintain the maxima of the values and the
+/// position. At the end, we return the position which contains the
+/// greatest value.
+template <typename I>
+unsigned peak_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the peak of the histogram
+ unsigned v_max = mln::opt::at(histo, 0);
+ short p_max = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ if (v_max < histo(p))
+ {
+ v_max = histo(p);
+ p_max = p.ind();
+ }
+ }
+
+ return p_max;
+}
+
+/// \brief Compute the average of the histogram.
+///
+/// \param[in] histo_ the histogram.
+///
+/// \return the average of the histogram.
+///
+/// Compute the mean of the histogram by summing the values of each
+/// bin ponderated by its frequency. The result is divided by the sum
+/// of the frequencies.
+template <typename I>
+unsigned mean_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the mean of the histogram
+ float sum = 0;
+ float mean = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ sum += histo(p);
+ mean += p.ind()*histo(p);
+ }
+
+ mean = mean / sum;
+
+ return mean;
+}
+
+
+/// \brief The hue test.
+///
+/// \param[in] input the name of the input image.
+/// \param[in] output the name of the histogram to output.
+/// \param[in] tmp the name of the hue map to output.
+///
+/// \return the proportion of pixels that pass the test.
+///
+/// Load the input image, transform it to get the hue_map and compute
+/// the histogram. Then count the number of pixels that are between
+/// peak-threshold and peak +threshold. Print the peak and the
+/// percentage of pixels around the pic.
+float hue_test(const std::string input,
+ const std::string output,
+ const std::string tmp,
+ const unsigned threshold)
+
+{
+ typedef mln::fun::v2v::rgb_to_hue_map<8> t_rgb_to_hue_map;
+
+ mln::image2d<mln::value::rgb8> input_rgb8;
+ mln::image2d<mln::value::int_u8> map;
+ mln::image1d<unsigned> histo;
+ unsigned cnt1;
+ unsigned cnt2;
+ float prop;
+ unsigned peak;
+ mln::value::rgb8 color;
+
+ mln::io::ppm::load(input_rgb8, input.c_str());
+
+ map = mln::data::transform(input_rgb8, t_rgb_to_hue_map());
+ histo = mln::data::compute(mln::accu::meta::stat::histo1d(), map);
+ peak = mean_histo(histo); //peak_histo(histo);
+ color = label_hue(peak);
+ cnt1 = count_histo(histo | mln::box1d(mln::point1d(peak-threshold),
+ mln::point1d(peak+threshold)));
+ cnt2 = mln::geom::nsites(input_rgb8);
+ prop = ((100.0 * cnt1) / cnt2);
+
+ mln::io::plot::save_image_sh(histo, output.c_str());
+ mln::io::pgm::save(map, tmp.c_str());
+ std::cout << "peak = " << peak << std::endl;
+ std::cout << "color = " << color << std::endl;
+
+ return prop;
+}
+
+
+/// \brief Main entry.
+///
+/// It is a front end which managing the iteration through one image
+/// data base with boost. Save hue map and hue histogram.
+int main()
+{
+ typedef boost::filesystem::path t_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+
+ t_path full_path[] = {t_path(ICDAR_20P_PPM_IMG_PATH)};
+
+ for (int i = 0; i < 1; ++i)
+ {
+ std::cout << "entering " << full_path[i] << std::endl;
+
+ if (boost::filesystem::exists(full_path[i]) &&
+ boost::filesystem::is_directory(full_path[i]))
+ {
+ boost::filesystem::system_complete(full_path[i]);
+ const t_iter_path end_iter;
+ float prop = 0.0;
+
+ for (t_iter_path dir_iter(full_path[i]); end_iter != dir_iter; ++dir_iter)
+ {
+ // concatenation de chaine
+ t_path directory(ANNOTATING_ICDAR_RET_PATH);
+ t_path leaf = dir_iter->path().leaf();
+ t_path output = change_extension(directory / leaf, ".sh");
+ t_path tmp = change_extension(directory / leaf, ".pgm");
+
+ prop = hue_test(dir_iter->path().string(),
+ output.string(),
+ tmp.string(),
+ 20);
+
+ std::cout << output << " : " << prop << std::endl;
+ std::cerr << output << " : " << prop << std::endl;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-color.txt
b/scribo/sandbox/green/exp/annotating/hue/text-color.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-color.txt
copy to scribo/sandbox/green/exp/annotating/hue/text-color.txt
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-img.txt
b/scribo/sandbox/green/exp/annotating/hue/text-img.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-img.txt
copy to scribo/sandbox/green/exp/annotating/hue/text-img.txt
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-only.txt
b/scribo/sandbox/green/exp/annotating/hue/text-only.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-only.txt
copy to scribo/sandbox/green/exp/annotating/hue/text-only.txt
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/nb_color/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/nb_color/Makefile.am
diff --git a/scribo/sandbox/green/exp/annotating/nb_color/nb_color.cc
b/scribo/sandbox/green/exp/annotating/nb_color/nb_color.cc
new file mode 100644
index 0000000..2331c61
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/nb_color/nb_color.cc
@@ -0,0 +1,171 @@
+// 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 Compute the number of colors in an image.
+///
+/// Build histogram of colors and count the bins different from zero.
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/math/count.hh>
+#include <mln/accu/stat/histo3d_rgb.hh>
+
+#include <mln/binarization/threshold.hh>
+
+#include <mln/core/alias/neighb3d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/image3d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/fun/v2v/rgb8_to_rgbn.hh>
+
+// #include <mln/morpho/opening/volume.hh>
+
+#include <mln/io/ppm/load.hh>
+
+#include <mln/pw/value.hh>
+#include <mln/pw/cst.hh>
+
+#include <mln/util/timer.hh>
+
+#include <mln/value/rgb8.hh>
+//#include <mln/value/rgb.hh>
+
+
+/// \brief Count the colors.
+///
+/// \param[in] image the name of the image to process.
+///
+/// \return the number of colors.
+///
+/// Count the color by building histogram. Strange filtering is
+/// done. We use also the technique of regional maxima in
+/// comment. Quantification is done to reduce the size of the
+/// histogram as well.
+
+// n < 8, n is the degree of quantification
+template <unsigned n>
+unsigned count_image_color(const std::string& image)
+{
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::rgb<n> t_rgbn;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_rgbn> t_image2d_rgbn;
+ typedef mln::image3d<unsigned> t_histo3d;
+ typedef mln::image3d<bool> t_histo3d_bool;
+ typedef mln::fun::v2v::rgb8_to_rgbn<n> t_rgb8_to_rgbn;
+ typedef mln::accu::meta::stat::histo3d_rgb t_histo3d_fun;
+ typedef mln::accu::meta::math::count t_count_fun;
+
+ t_image2d_rgb8 input_rgb8;
+ t_image2d_rgbn input_rgbn;
+ t_image2d_rgbn output_rgbn;
+ t_histo3d histo;
+// t_histo3d opened;
+ t_histo3d_bool filtered;
+
+ mln::io::ppm::load(input_rgb8, image.c_str());
+
+ unsigned nb_pixel = input_rgb8.ncols() * input_rgb8.nrows();
+ unsigned min_volume = (unsigned)(nb_pixel * 0.0001);
+ unsigned nb_color = 0;
+
+// input_rgbn = mln::data::transform(input_rgb8, t_rgb8_to_rgbn());
+ histo = mln::data::compute(t_histo3d_fun(), input_rgb8);
+// opened = mln::morpho::opening::volume(histo, mln::c6(), min_volume);
+ filtered = mln::binarization::threshold(histo, min_volume);
+ nb_color = mln::data::compute(t_count_fun(),
+ (filtered|(mln::pw::value(filtered)!=0)).rw());
+
+ return nb_color;
+}
+
+
+/// \brief Main entry.
+///
+/// The main routine makes the base driver job. It looks after many
+/// directories and lists every images in it. We use the boost library
+/// to do it. Statistics are computed on the number of colors. The
+/// first idea was to answer the question is this descriptor allow to
+/// recognize a specific base.
+int main()
+{
+ typedef boost::filesystem::path t_path;
+ //typedef boost::filesystem::initial_path<t_path()> t_init_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+
+ t_path full_path[] = {t_path(ANNOTATING_1_BILL_IMG_PATH),
+ t_path(ANNOTATING_1_FAX_IMG_PATH),
+ t_path(ANNOTATING_1_HANDWRITTEN_IMG_PATH),
+ t_path(ANNOTATING_1_LOGO_IMG_PATH),
+ t_path(ANNOTATING_1_MAP_IMG_PATH),
+ t_path(ANNOTATING_1_PHOTO_IMG_PATH),
+ t_path(ANNOTATING_1_SCREENSHOT_IMG_PATH),
+ t_path(ANNOTATING_1_SLIDE_IMG_PATH),
+ t_path(ANNOTATING_1_TYPED_IMG_PATH)};
+
+ for (int i = 0; i < 9; ++i)
+ {
+ std::cerr << "entering " << full_path[i] << std::endl;
+ std::cout << "entering " << full_path[i] << std::endl;
+
+ if (boost::filesystem::exists(full_path[i]) &&
+ boost::filesystem::is_directory(full_path[i]))
+ {
+ boost::filesystem::system_complete(full_path[i]);
+ const t_iter_path end_iter;
+ unsigned count = 0;
+ unsigned sum1 = 0;
+ unsigned sum2 = 0;
+
+ for (t_iter_path dir_iter(full_path[i]); end_iter != dir_iter; ++dir_iter)
+ {
+ unsigned val = count_image_color<8>(dir_iter->path().string());
+
+ ++count;
+ sum1 += val;
+ sum2 += val*val;
+
+ std::cout << dir_iter->path().string() << " => " <<
val << std::endl;
+ }
+
+ float mean = sum1 / count;
+ float var = ((float)sum2 / count) - (mean * mean);
+
+ std::cout << "mean : " << mean << std::endl;
+ std::cout << "var : " << var << std::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/saturation/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/saturation/Makefile.am
diff --git a/scribo/sandbox/green/exp/annotating/saturation/saturation.cc
b/scribo/sandbox/green/exp/annotating/saturation/saturation.cc
new file mode 100644
index 0000000..b5834a1
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/saturation/saturation.cc
@@ -0,0 +1,175 @@
+// 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 Implement the Millet saturation operator [millet.phd.2008.pdf]
+///
+/// This is the Millet code for moving from RGB space to Sat
+/// one. Formulae are classical, we can find them on the web.
+///
+/// Val = max(R,G,B).
+/// Sat = (max(R,G,B) - min(R,G,B))/max(R,G,B).
+/// IF R = max(R,G,B) THEN Hue = 60 * [(V-B)/(max(R,G,B)-min(R,G,B))].
+/// IF G = max(R,G,B) THEN Hue = 60 * [2 + (B-R)/(max(R,G,B)-min(R,G,B))].
+/// IF B = max(R,G,B) THEN Hue = 60 * [4 + (R-G)/(max(R,G,B)-min(R,G,B))].
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/stretch.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/math/max.hh>
+#include <mln/math/min.hh>
+
+#include <mln/geom/nsites.hh>
+
+#include <mln/fun/v2v/rgb_to_saturation_map.hh>
+
+#include <mln/io/ppm/load.hh>
+//#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/value/rgb8.hh>
+
+/// \brief Sum all the bins of the histogram.
+///
+/// \param[in] img the histogram based on image.
+///
+/// \return the sum of the overall bins.
+///
+/// Sum evry bins and return the result.
+template <typename I>
+unsigned count_histo(const mln::Image<I>& img_)
+{
+ const I& img = exact(img_);
+
+ mln_precondition(img.is_valid());
+
+ unsigned result = 0;
+
+ mln_piter(I) p(img.domain());
+
+ for_all(p)
+ result += img(p);
+
+ return result;
+}
+
+/// \brief The saturation test.
+///
+/// \param[in] input the name of the input image.
+/// \param[in] output the name of the histogram to output.
+/// \param[in] threshold for deciding which is low saturation or not.
+///
+/// \return the proportion of pixels that pass the test.
+///
+/// Load the input image, transform it to get the saturation_map and compute
+/// the histogram. Then count the number of pixels that are under the threshold.
+/// Then return the proportion of pixels.
+float saturation_test(const std::string input,
+ const std::string output,
+// const std::string tmp,
+ const unsigned threshold)
+
+{
+ typedef mln::fun::v2v::rgb_to_saturation_map<8> t_rgb_to_saturation_map;
+
+ mln::image2d<mln::value::rgb8> input_rgb8;
+ mln::image2d<mln::value::int_u8> map;
+ mln::image1d<unsigned> histo;
+ unsigned cnt1;
+ unsigned cnt2;
+ float prop;
+
+ mln::io::ppm::load(input_rgb8, input.c_str());
+
+ map = mln::data::transform(input_rgb8, t_rgb_to_saturation_map());
+ histo = mln::data::compute(mln::accu::meta::stat::histo1d(), map);
+ cnt1 = count_histo(histo | mln::box1d(mln::point1d(0),
+ mln::point1d(threshold)));
+ cnt2 = mln::geom::nsites(input_rgb8);
+ prop = ((100.0 * cnt1) / cnt2);
+
+ mln::io::plot::save_image_sh(histo, output.c_str());
+// mln::io::pgm::save(map, tmp.c_str());
+
+ return prop;
+}
+
+
+/// \brief the main entry.
+///
+/// This is a front end for image processing routine. It manages the
+/// calling of every image in the database.
+int main()
+{
+ typedef boost::filesystem::path t_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+
+ t_path full_path[] = {t_path(ICDAR_20P_PPM_IMG_PATH)};
+
+ for (int i = 0; i < 1; ++i)
+ {
+ std::cout << "entering " << full_path[i] << std::endl;
+
+ if (boost::filesystem::exists(full_path[i]) &&
+ boost::filesystem::is_directory(full_path[i]))
+ {
+ boost::filesystem::system_complete(full_path[i]);
+ const t_iter_path end_iter;
+ float prop = 0.0;
+
+ for (t_iter_path dir_iter(full_path[i]); end_iter != dir_iter; ++dir_iter)
+ {
+ // concatenation de chaine
+ t_path directory(ANNOTATING_ICDAR_RET_PATH);
+ t_path leaf = dir_iter->path().leaf();
+ t_path output = change_extension(directory / leaf, ".sh");
+ t_path tmp = change_extension(directory / leaf, ".pgm");
+
+ prop = saturation_test(dir_iter->path().string(),
+ output.string(),
+// tmp.string(),
+ 25);
+
+ std::cout << output << " : " << prop << std::endl;
+ std::cerr << output << " : " << prop << std::endl;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-color.txt
b/scribo/sandbox/green/exp/annotating/saturation/text-color.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-color.txt
copy to scribo/sandbox/green/exp/annotating/saturation/text-color.txt
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-img.txt
b/scribo/sandbox/green/exp/annotating/saturation/text-img.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-img.txt
copy to scribo/sandbox/green/exp/annotating/saturation/text-img.txt
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-only.txt
b/scribo/sandbox/green/exp/annotating/saturation/text-only.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-only.txt
copy to scribo/sandbox/green/exp/annotating/saturation/text-only.txt
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/stddev_color/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/stddev_color/Makefile.am
diff --git a/scribo/sandbox/green/exp/annotating/stddev_color/stddev_color.cc
b/scribo/sandbox/green/exp/annotating/stddev_color/stddev_color.cc
new file mode 100644
index 0000000..365a9c3
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/stddev_color/stddev_color.cc
@@ -0,0 +1,216 @@
+// 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 Implement the Millet clipart detection [millet.phd.2008.pdf]
+///
+/// The aim of this descriptor is to recognize clipart. To do this, we
+/// assume that clipart have their histogram concentrated around their
+/// mode. This is particularly true if the clipart is design by hand,
+/// because a very small number of grey tones or colors are used to
+/// draw it. But sometimes, computer assists their creation and we can
+/// find some continuous set of tones and this artefact create noise
+/// for the detection technique describe bellow.
+
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/max_site.hh>
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/core/macros.hh>
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/fill.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/fun/v2v/rgb8_to_int_u8.hh>
+
+#include <mln/io/ppm/load.hh>
+
+#include <mln/math/sqr.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/int_u.hh>
+
+/// \brief The R function of Millet
+///
+/// \param[in] p the position of the pic.
+/// \param[in] histo_p the histo value of the pic.
+/// \param[in] x the position of the element which we compute the contrib.
+/// \param[in] histo_x the histo value of that element.
+///
+/// \result the contribution of the element x.
+///
+/// This function compute the variance-like contribution of an element
+/// x linked to the pic of the histogram. In fact, every thing is like
+/// we compute a square distance-like between the element x and the
+/// pic in the normalized histogram. Notice that the normalized
+/// histogram is the histogram divide by the value of it's pic. So at
+/// the pic, the value equals 1. It's a current representation of the
+/// histogram in image processing, we can find it in gimp for exemple.
+float r(short p, unsigned histo_p, short x, unsigned histo_x)
+{
+ float result = mln::math::sqr(((float)histo_x / histo_p) * (x-p));
+
+ return result;
+}
+
+/// Brief compute the whole deviation of Millet
+///
+/// \param[in] image the input image to analyze.
+///
+/// \return the deviation.
+///
+/// The deviation uses the R function. It stats by finding the pic. If
+/// the pic is near the rigth border of the histo, compute the R
+/// function on the left neighbouring of the pic. If the pic is near
+/// the left border of the histo, compute the R function on the right
+/// neigbouring. Otherwise, compute the average of the right and left
+/// results. The selected neighbouring is composed of five pixels at
+/// the right or at the left of the pic. The detection of clipart
+/// assumes that the majority of the energy of the histogram is closed
+/// to the pic (five pixels around it).
+float stddev_color(const std::string& image)
+{
+ typedef mln::point1d t_point1d;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ typedef mln::image1d<unsigned> t_histo1d;
+ typedef mln::fun::v2v::rgb8_to_int_u8 t_rgb8_to_int_u8;
+ typedef mln::accu::meta::stat::histo1d t_histo1d_fun;
+ typedef mln::accu::max_site<t_histo1d> t_max_site_fun;
+
+ t_image2d_rgb8 input_rgb8;
+ t_image2d_int_u8 input_int_u8;
+ t_histo1d histo;
+ t_point1d max_site;
+
+ mln::io::ppm::load(input_rgb8, image.c_str());
+ input_int_u8 = mln::data::transform(input_rgb8, t_rgb8_to_int_u8());
+ histo = mln::data::compute(t_histo1d_fun(), input_int_u8);
+
+ // Find the peak of the histogram
+ unsigned v_max = mln::opt::at(histo, 0);
+ short p_max = 0;
+
+ mln_piter_(t_histo1d) p(histo.domain());
+
+ for_all(p)
+ {
+ if (v_max < histo(p))
+ {
+ v_max = histo(p);
+ p_max = p.ind();
+ }
+ }
+
+ // Compute the specific stddev
+
+ float stddev_low = 0.0;
+ float stddev_up = 0.0;
+ float stddev = 0.0;
+
+ if (250 > p_max)
+ for (short i = p_max+1; i < p_max+6; ++i)
+ stddev_up += r(p_max, mln::opt::at(histo,p_max),
+ i, mln::opt::at(histo,i));
+
+ if (5 < p_max)
+ for (short i = p_max-1; i > p_max-6; --i)
+ stddev_low += r(p_max, mln::opt::at(histo,p_max),
+ i, mln::opt::at(histo,i));
+
+ stddev = (250 < p_max)? stddev_low : (5 > p_max)? stddev_up :
+ (stddev_low + stddev_up)/2;
+
+ return stddev;
+}
+
+
+/// \brief Main entry.
+///
+/// Front end for image processing. It is in the main routine where we
+/// go through the image data base (using boost to do it).
+int main()
+{
+ typedef boost::filesystem::path t_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+
+ t_path full_path[] = {t_path(ANNOTATING_1_BILL_IMG_PATH),
+ t_path(ANNOTATING_1_FAX_IMG_PATH),
+ t_path(ANNOTATING_1_HANDWRITTEN_IMG_PATH),
+ t_path(ANNOTATING_1_LOGO_IMG_PATH),
+ t_path(ANNOTATING_1_MAP_IMG_PATH),
+ t_path(ANNOTATING_1_PHOTO_IMG_PATH),
+ t_path(ANNOTATING_1_SCREENSHOT_IMG_PATH),
+ t_path(ANNOTATING_1_SLIDE_IMG_PATH),
+ t_path(ANNOTATING_1_TYPED_IMG_PATH)};
+
+ for (int i = 0; i < 9; ++i)
+ {
+ std::cerr << "entering " << full_path[i] << std::endl;
+ std::cout << "entering " << full_path[i] << std::endl;
+
+ if (boost::filesystem::exists(full_path[i]) &&
+ boost::filesystem::is_directory(full_path[i]))
+ {
+ boost::filesystem::system_complete(full_path[i]);
+ const t_iter_path end_iter;
+ float count = 0;
+ float sum1 = 0;
+ float sum2 = 0;
+
+ for (t_iter_path dir_iter(full_path[i]); end_iter != dir_iter; ++dir_iter)
+ {
+ float val = stddev_color(dir_iter->path().string());
+
+ ++count;
+ sum1 += val;
+ sum2 += val*val;
+
+ std::cout << dir_iter->path().string() << " => " <<
val << std::endl;
+ }
+
+ float mean = sum1 / count;
+ float var = ((float)sum2 / count) - (mean * mean);
+
+ std::cout << "mean : " << mean << std::endl;
+ std::cout << "var : " << var << std::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/stddev_color_16/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/stddev_color_16/Makefile.am
diff --git a/scribo/sandbox/green/exp/annotating/stddev_color_16/stddev_color_16.cc
b/scribo/sandbox/green/exp/annotating/stddev_color_16/stddev_color_16.cc
new file mode 100644
index 0000000..fc55547
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/stddev_color_16/stddev_color_16.cc
@@ -0,0 +1,277 @@
+// 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 Implement the Millet clipart detection [millet.phd.2008.pdf]
+///
+/// The aim of this descriptor is to recognize clipart. To do this, we
+/// assume that clipart have their histogram concentrated around their
+/// mode. This is particularly true if the clipart is design by hand,
+/// because a very small number of grey tones or colors are used to
+/// draw it. But sometimes, computer assists their creation and we can
+/// find some continuous set of tones and this artefact create noise
+/// for the detection technique describe bellow. When photographies
+/// has some large uniform border, the detection can fail. To improve
+/// the method, Millet decide to subdivise the image in 16 sub images
+/// on which it applies the test.
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/max_site.hh>
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/core/macros.hh>
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/image3d.hh>
+
+#include <mln/debug/println.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/fill.hh>
+#include <mln/data/transform.hh>
+#include <mln/data/paste.hh>
+
+#include <mln/fun/v2v/rgb8_to_int_u8.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/math/sqr.hh>
+#include <mln/math/max.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/value/rgb8.hh>
+#include <mln/value/int_u.hh>
+
+/// \brief The R function of Millet
+///
+/// \param[in] p the position of the pic.
+/// \param[in] histo_p the histo value of the pic.
+/// \param[in] x the position of the element which we compute the contrib.
+/// \param[in] histo_x the histo value of that element.
+///
+/// \result the contribution of the element x.
+///
+/// This function compute the variance-like contribution of an element
+/// x linked to the pic of the histogram. In fact, every thing is like
+/// we compute a square distance-like between the element x and the
+/// pic in the normalized histogram. Notice that the normalized
+/// histogram is the histogram divide by the value of it's pic. So at
+/// the pic, the value equals 1. It's a current representation of the
+/// histogram in image processing, we can find it in gimp for exemple.
+float r(short p, unsigned histo_p, short x, unsigned histo_x)
+{
+ float result = mln::math::sqr(((float)histo_x / histo_p) * (x-p));
+
+ return result;
+}
+
+/// Brief compute the whole deviation of Millet
+///
+/// \param[in] input_int_u8 the 8 bits input image to analyze.
+/// \param[in] name_histo the name of the output histogram.
+/// \param[in] name_image the name of the ouput sub image.
+///
+/// \return the deviation, but at this time nothing..
+///
+/// The deviation uses the R function. It stats by finding the pic. If
+/// the pic is near the rigth border of the histo, compute the R
+/// function on the left neighbouring of the pic. If the pic is near
+/// the left border of the histo, compute the R function on the right
+/// neigbouring. Otherwise, compute the average of the right and left
+/// results. The selected neighbouring is composed of five pixels at
+/// the right or at the left of the pic. The detection of clipart
+/// assumes that the majority of the energy of the histogram is closed
+/// to the pic (five pixels around it).
+float stddev_color(mln::image2d<mln::value::int_u8> input_int_u8)
+{
+ typedef mln::point1d t_point1d;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ typedef mln::image1d<unsigned> t_histo1d;
+ typedef mln::fun::v2v::rgb8_to_int_u8 t_rgb8_to_int_u8;
+ typedef mln::accu::meta::stat::histo1d t_histo1d_fun;
+ typedef mln::accu::max_site<t_histo1d> t_max_site_fun;
+
+ t_histo1d histo;
+
+ histo = mln::data::compute(t_histo1d_fun(), input_int_u8);
+
+ // Find the peak of the histogram
+ unsigned v_max = mln::opt::at(histo, 0);
+ short p_max = 0;
+
+ mln_piter_(t_histo1d) p(histo.domain());
+
+ for_all(p)
+ {
+ if (v_max < histo(p))
+ {
+ v_max = histo(p);
+ p_max = p.ind();
+ }
+ }
+
+ // Compute the specific stddev
+
+ float stddev_low = 0.0;
+ float stddev_up = 0.0;
+ float stddev = 0.0;
+
+ if (250 > p_max)
+ for (short i = p_max+1; i < p_max+6; ++i)
+ stddev_up += r(p_max, mln::opt::at(histo,p_max),
+ i, mln::opt::at(histo,i));
+
+ if (5 < p_max)
+ for (short i = p_max-1; i > p_max-6; --i)
+ stddev_low += r(p_max, mln::opt::at(histo,p_max),
+ i, mln::opt::at(histo,i));
+
+ stddev = (250 < p_max)? stddev_low : (5 > p_max)? stddev_up :
+ (stddev_low + stddev_up)/2;
+
+ return stddev;
+}
+
+/// \brief Divide the image in 16 sub images.
+///
+/// \param[in] image the input image.
+///
+/// \result nothing.
+///
+/// Divive the input image in 16 by uniform and geometrical
+/// method. When a sub image is ready, call the stddev routine to show
+/// stats on it.
+float stddev_color_16(const std::string& image)
+{
+ typedef mln::point1d t_point1d;
+ typedef mln::value::rgb8 t_rgb8;
+ typedef mln::value::int_u8 t_int_u8;
+ typedef mln::image2d<t_rgb8> t_image2d_rgb8;
+ typedef mln::image2d<t_int_u8> t_image2d_int_u8;
+ typedef mln::image1d<unsigned> t_histo1d;
+ typedef mln::fun::v2v::rgb8_to_int_u8 t_rgb8_to_int_u8;
+ typedef mln::accu::meta::stat::histo1d t_histo1d_fun;
+ typedef mln::accu::max_site<t_histo1d> t_max_site_fun;
+
+ t_image2d_rgb8 input_rgb8;
+ t_image2d_int_u8 input_int_u8;
+
+ mln::io::ppm::load(input_rgb8, image.c_str());
+ input_int_u8 = mln::data::transform(input_rgb8, t_rgb8_to_int_u8());
+
+ // IMAGE SPLITTING PHASE
+ mln::box2d domain = input_int_u8.domain();
+ mln::point2d pmin = domain.pmin();
+ mln::point2d pmax = domain.pmax();
+
+ unsigned sz_row = (pmax.row() - pmin.row())/ 4;
+ unsigned sz_col = (pmax.col() - pmin.col())/ 4;
+ float stddev = 0.0;
+
+ // Divide the domain in nine sub-domains.
+ for (unsigned i = 0; i < 4; ++i)
+ for (unsigned j = 0; j < 4; ++j)
+ {
+ mln::point2d min(pmin.row()+sz_row*i,pmin.col()+sz_col*j);
+ mln::point2d max(pmin.row()+sz_row*(i+1),pmin.col()+sz_col*(j+1));
+ mln::box2d dom(min,max);
+
+ // Save it
+ t_image2d_int_u8 input_1o16_int_u8(dom);
+
+ mln::data::paste(input_int_u8 | dom, input_1o16_int_u8);
+
+ stddev = mln::math::max(stddev, stddev_color(input_1o16_int_u8));
+ }
+
+ return stddev;
+}
+
+
+/// \brief Main entry.
+///
+/// Just a front end for image processing routine. Use boost to go
+/// through the image database.
+int main()
+{
+ typedef boost::filesystem::path t_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+
+ t_path full_path[] = {t_path(ANNOTATING_1_BILL_IMG_PATH),
+ t_path(ANNOTATING_1_FAX_IMG_PATH),
+ t_path(ANNOTATING_1_HANDWRITTEN_IMG_PATH),
+ t_path(ANNOTATING_1_LOGO_IMG_PATH),
+ t_path(ANNOTATING_1_MAP_IMG_PATH),
+ t_path(ANNOTATING_1_PHOTO_IMG_PATH),
+ t_path(ANNOTATING_1_SCREENSHOT_IMG_PATH),
+ t_path(ANNOTATING_1_SLIDE_IMG_PATH),
+ t_path(ANNOTATING_1_TYPED_IMG_PATH)};
+
+ for (int i = 0; i < 9; ++i)
+ {
+ std::cerr << "entering " << full_path[i] << std::endl;
+ std::cout << "entering " << full_path[i] << std::endl;
+
+ if (boost::filesystem::exists(full_path[i]) &&
+ boost::filesystem::is_directory(full_path[i]))
+ {
+ boost::filesystem::system_complete(full_path[i]);
+ const t_iter_path end_iter;
+ float count = 0;
+ float sum1 = 0;
+ float sum2 = 0;
+
+ for (t_iter_path dir_iter(full_path[i]); end_iter != dir_iter; ++dir_iter)
+ {
+ float val = stddev_color_16(dir_iter->path().string());
+
+ ++count;
+ sum1 += val;
+ sum2 += val*val;
+
+ std::cout << dir_iter->path().string() << " => " <<
val << std::endl;
+ }
+
+ float mean = sum1 / count;
+ float var = ((float)sum2 / count) - (mean * mean);
+
+ std::cout << "mean : " << mean << std::endl;
+ std::cout << "var : " << var << std::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/exp/regional_maxima/Makefile.am
b/scribo/sandbox/green/exp/annotating/value/Makefile.am
similarity index 100%
copy from scribo/sandbox/green/exp/regional_maxima/Makefile.am
copy to scribo/sandbox/green/exp/annotating/value/Makefile.am
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-color.txt
b/scribo/sandbox/green/exp/annotating/value/text-color.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-color.txt
copy to scribo/sandbox/green/exp/annotating/value/text-color.txt
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-img.txt
b/scribo/sandbox/green/exp/annotating/value/text-img.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-img.txt
copy to scribo/sandbox/green/exp/annotating/value/text-img.txt
diff --git a/milena/sandbox/green/exp/annotating/achromastism/text-only.txt
b/scribo/sandbox/green/exp/annotating/value/text-only.txt
similarity index 100%
copy from milena/sandbox/green/exp/annotating/achromastism/text-only.txt
copy to scribo/sandbox/green/exp/annotating/value/text-only.txt
diff --git a/scribo/sandbox/green/exp/annotating/value/value.cc
b/scribo/sandbox/green/exp/annotating/value/value.cc
new file mode 100644
index 0000000..cade88b
--- /dev/null
+++ b/scribo/sandbox/green/exp/annotating/value/value.cc
@@ -0,0 +1,468 @@
+// 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 Implement the Millet value operator [millet.phd.2008.pdf]
+///
+/// This is the Millet code for moving from RGB space to value
+/// one. Formulae are classical, we can find them on the web.
+///
+/// Val = max(R,G,B).
+/// Sat = (max(R,G,B) - min(R,G,B))/max(R,G,B).
+/// IF R = max(R,G,B) THEN Hue = 60 * [(V-B)/(max(R,G,B)-min(R,G,B))].
+/// IF G = max(R,G,B) THEN Hue = 60 * [2 + (B-R)/(max(R,G,B)-min(R,G,B))].
+/// IF B = max(R,G,B) THEN Hue = 60 * [4 + (R-G)/(max(R,G,B)-min(R,G,B))].
+#include <iostream>
+#include <sstream>
+#include <boost/filesystem.hpp>
+
+#include <mln/img_path.hh>
+
+#include <mln/accu/stat/histo1d.hh>
+
+#include <mln/core/image/image1d.hh>
+#include <mln/core/image/image2d.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+
+#include <mln/data/compute.hh>
+#include <mln/data/stretch.hh>
+#include <mln/data/transform.hh>
+
+#include <mln/literal/colors.hh>
+#include <mln/literal/grays.hh>
+
+#include <mln/math/max.hh>
+#include <mln/math/min.hh>
+
+#include <mln/opt/at.hh>
+
+#include <mln/geom/nsites.hh>
+
+#include <mln/fun/v2v/rgb_to_value_map.hh>
+
+#include <mln/io/ppm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/plot/save_image_sh.hh>
+
+#include <mln/value/rgb8.hh>
+
+/// \brief Label the value.
+///
+/// \param[in] val the value in [0..255].
+///
+/// \return the reference color.
+///
+/// Segment the grey value in three classes.
+mln::value::rgb8 label_val(const mln::value::int_u8 val)
+{
+ mln::value::rgb8 result;
+
+ if (82 > val)
+ result = mln::literal::black;
+ else if (179 > val)
+ result= mln::literal::medium_gray;
+ else
+ result = mln::literal::white;
+
+ return result;
+}
+
+
+/// \brief Label color with orange reference or brown reference.
+///
+/// \param[in] color the rgb8 color.
+/// \param[in] sat the HSV saturation.
+/// \param[in] val the HSV value.
+///
+/// \return the reference color with which it has been associated to.
+///
+/// Discriminate between orange and brown colors which are at the same
+/// position on the hue wheel.
+mln::value::rgb8 label_orange_or_brown(const mln::value::rgb8 color,
+ const mln::value::int_u8 sat,
+ const mln::value::int_u8 val)
+{
+ mln::value::rgb8 result;
+
+ if (mln::literal::orange == color)
+ {
+ unsigned dist_orange = mln::math::abs(sat - 184)
+ + mln::math::abs(val - 65);
+
+ unsigned dist_brown = mln::math::abs(sat - 255)
+ + mln::math::abs(val - 125);
+
+ if (dist_orange < dist_brown)
+ result = mln::literal::orange;
+ else
+ result = mln::literal::brown;
+ }
+ else
+ result = color;
+
+ return result;
+}
+
+/// \brief Label between yellow and green color.
+///
+/// \param[in] color the rgb8 color.
+/// \param[in] val the HSV value.
+///
+/// \return the reference color associated to that color.
+///
+/// Segment between yellow and green because the discrimination is not
+/// so easy based on the hue wheel.
+mln::value::rgb8 label_yellow_or_green(const mln::value::rgb8 color,
+ const mln::value::int_u8 val)
+{
+ mln::value::rgb8 result;
+
+ if (mln::literal::yellow == color)
+ {
+ // Is it green or yellow ?
+ if (80 > val)
+ result = mln::literal::green;
+ else
+ result = mln::literal::yellow;
+ }
+ else
+ return color;
+
+ return result;
+}
+
+/// \brief Label hue color.
+///
+/// \param[in] hue the HSV hue canal for a pixel.
+///
+/// \return a hue segmentation of the hue wheel.
+///
+/// The old classification given by Millet is commented. Mine is ready
+/// to use. We need to change reference colors to make the primary
+/// colors, the secondary ones, etc...
+mln::value::rgb8 label_hue(const mln::value::int_u8 hue)
+{
+ mln::value::rgb8 result;
+
+ if (14 > hue)
+ result = mln::literal::red;
+ else if (29 > hue)
+ result = mln::literal::orange;
+ else if (45 > hue)
+ result = mln::literal::yellow;
+ else if (113 > hue)
+ result = mln::literal::green;
+ else if (149 > hue)
+ result = mln::literal::cyan;
+ else if (205 > hue)
+ result = mln::literal::blue;
+ else if (235 > hue)
+ result = mln::literal::violet;
+ else if (242 > hue)
+ result = mln::literal::pink;
+ else
+ result = mln::literal::red;
+
+ return result;
+}
+
+/// \brief Sum all the bins of the histogram.
+///
+/// \param[in] img the histogram based on image.
+///
+/// \return the sum of the overall bins.
+///
+/// Sum evry bins and return the result.
+template <typename I>
+unsigned count_histo(const mln::Image<I>& img_)
+{
+ const I& img = exact(img_);
+
+ mln_precondition(img.is_valid());
+
+ unsigned result = 0;
+
+ mln_piter(I) p(img.domain());
+
+ for_all(p)
+ result += img(p);
+
+ return result;
+}
+
+/// \brief Detect the peak of the histogram.
+///
+/// \param[in] histo_ the image which represents the histogram.
+///
+/// \return the position of the peak.
+///
+/// This is a typical accumulator use case but as it needs the
+/// position it couldn't be one of them. Look at the last maxima in
+/// the curve and return its position.
+template <typename I>
+unsigned peak_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the peak of the histogram
+ unsigned v_max = mln::opt::at(histo, 0);
+ short p_max = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ if (v_max < histo(p))
+ {
+ v_max = histo(p);
+ p_max = p.ind();
+ }
+ }
+
+ return p_max;
+}
+
+/// \brief Compute the average of the histogram.
+///
+/// \param[in] histo_ the image which represents the histogram.
+///
+/// \return the average of the histogram.
+///
+/// This code should be an accumulator. It computes the mean of the
+/// histogram, just stats in loop. Compute the sum, compute the
+/// ponderate sum and divide the second by the first.
+template <typename I>
+unsigned mean_histo(const mln::Image<I>& histo_)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Find the mean of the histogram
+ float sum = 0;
+ float mean = 0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ sum += histo(p);
+ mean += p.ind()*histo(p);
+ }
+
+ mean = mean / sum;
+
+ return mean;
+}
+
+/// \brief The R function of Millet
+///
+/// \param[in] p the position of the pic.
+/// \param[in] histo_p the histo value of the pic.
+/// \param[in] x the position of the element which we compute the contrib.
+/// \param[in] histo_x the histo value of that element.
+///
+/// \result the contribution of the element x.
+///
+/// This function compute the variance-like contribution of an element
+/// x linked to the pic of the histogram. In fact, every thing is like
+/// we compute a square distance-like between the element x and the
+/// pic in the normalized histogram. Notice that the normalized
+/// histogram is the histogram divide by the value of it's pic. So at
+/// the pic, the value equals 1. It's a current representation of the
+/// histogram in image processing, we can find it in gimp for exemple.
+float r(short p, unsigned histo_p, short x, unsigned histo_x)
+{
+ float result = mln::math::sqr(((float)histo_x / histo_p) * (x-p));
+
+ return result;
+}
+
+
+/// \brief The stddev3 is an internal stuff.
+///
+/// \param[in] histo_ the image which represents the histogram.
+/// \param[in] peak the position of the histogram peak.
+///
+/// \return simple computing of deviation.
+///
+/// This is an internal stuff. It splits the computing for easy
+/// reusing practice. Sum the R contribution.
+template <typename I>
+float stddev3(const mln::Image<I>& histo_, unsigned peak)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ // Compute stddev
+
+ float stddev = 0.0;
+
+ mln_piter(I) p(histo.domain());
+
+ for_all(p)
+ {
+ stddev += r((short)peak, mln::opt::at(histo,peak), p.ind(), histo(p));
+ }
+
+ return stddev;
+}
+
+
+/// Brief compute the whole deviation of Millet
+///
+/// \param[in] image the input image to analyze.
+/// \param[in] peak the peak of the histogram.
+/// \param[in] limit the threshold to compute the contribution.
+///
+/// \return the deviation.
+///
+/// The deviation uses the R function. It stats by finding the pic. If
+/// the pic is near the rigth border of the histo, compute the R
+/// function on the left neighbouring of the pic. If the pic is near
+/// the left border of the histo, compute the R function on the right
+/// neigbouring. Otherwise, compute the average of the right and left
+/// results. The selected neighbouring is composed of five pixels at
+/// the right or at the left of the pic. The detection of clipart
+/// assumes that the majority of the energy of the histogram is closed
+/// to the pic (five pixels around it). The test is generalized by
+/// making constants as parameters.
+template <typename I>
+float stddev2(const mln::Image<I>& histo_, unsigned peak, unsigned limit)
+{
+ const I& histo = exact(histo_);
+
+ mln_precondition(histo.is_valid());
+
+ float stddev_low = 0.0;
+ float stddev_up = 0.0;
+ float ret = 0.0;
+
+ // A transformer avec des iterators
+
+ if (250 > peak)
+ stddev_up = stddev3(histo |mln::box1d(mln::point1d(peak+1),
+ mln::point1d(peak+limit)), peak);
+
+ if (5 < peak)
+ stddev_low = stddev3(histo |mln::box1d(mln::point1d(peak-limit),
+ mln::point1d(peak-1)), peak);
+
+ ret = (250 < peak)? stddev_low : (5 > peak)? stddev_up :
+ (stddev_low + stddev_up)/2;
+
+ return ret;
+}
+
+
+/// \brief This is the main Millet test.
+///
+/// \param[in] input the name of the input image.
+/// \param[in] output the name of result histogram.
+/// \param[in] tmp the name of the output value (HSV) map.
+/// \param[in] threshold the range around the peak where R is computed.
+///
+/// \return the proportion of pixels that pass the test.
+float value_test(const std::string input,
+ const std::string output,
+ const std::string tmp,
+ const unsigned threshold)
+
+{
+ typedef mln::fun::v2v::rgb_to_value_map<8> t_rgb_to_value_map;
+
+ mln::image2d<mln::value::rgb8> input_rgb8;
+ mln::image2d<mln::value::int_u8> map;
+ mln::image1d<unsigned> histo;
+ unsigned cnt1;
+ unsigned cnt2;
+ float prop;
+ unsigned peak;
+
+ mln::io::ppm::load(input_rgb8, input.c_str());
+
+ map = mln::data::transform(input_rgb8, t_rgb_to_value_map());
+ histo = mln::data::compute(mln::accu::meta::stat::histo1d(), map);
+ peak = peak_histo(histo); // mean_histo(histo);
+ prop = stddev2(histo, peak, threshold);
+// cnt1 = count_histo(histo | mln::box1d(mln::point1d(peak-threshold),
+// mln::point1d(peak+threshold)));
+// cnt2 = mln::geom::nsites(input_rgb8);
+// prop = ((100.0 * cnt1) / cnt2);
+
+ mln::io::plot::save_image_sh(histo, output.c_str());
+ mln::io::pgm::save(map, tmp.c_str());
+
+ return prop;
+}
+
+
+/// \brief The main entry.
+///
+/// This is the front end for using directories with boost. It calls
+/// the true image processing routine.
+int main()
+{
+ typedef boost::filesystem::path t_path;
+ typedef boost::filesystem::directory_iterator t_iter_path;
+
+ t_path full_path[] = {t_path(ICDAR_20P_PPM_IMG_PATH)};
+
+ for (int i = 0; i < 1; ++i)
+ {
+ std::cout << "entering " << full_path[i] << std::endl;
+
+ if (boost::filesystem::exists(full_path[i]) &&
+ boost::filesystem::is_directory(full_path[i]))
+ {
+ boost::filesystem::system_complete(full_path[i]);
+ const t_iter_path end_iter;
+ float prop = 0.0;
+
+ for (t_iter_path dir_iter(full_path[i]); end_iter != dir_iter; ++dir_iter)
+ {
+ // concatenation de chaine
+ t_path directory(ANNOTATING_RET_PATH);
+ t_path leaf = dir_iter->path().leaf();
+ t_path output = change_extension(directory / leaf, ".sh");
+ t_path tmp = change_extension(directory / leaf, ".pgm");
+
+ prop = value_test(dir_iter->path().string(),
+ output.string(),
+ tmp.string(),
+ 15);
+
+ std::cout << output << " : " << prop << std::endl;
+ std::cerr << output << " : " << prop << std::endl;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/scribo/sandbox/green/mln/clustering/kmean2d.hh
b/scribo/sandbox/green/mln/clustering/kmean2d.hh
index 51aaf49..4539083 100644
--- a/scribo/sandbox/green/mln/clustering/kmean2d.hh
+++ b/scribo/sandbox/green/mln/clustering/kmean2d.hh
@@ -150,7 +150,7 @@ 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::rg<n> t_value;
@@ -179,7 +179,7 @@ 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;
- ///}
+ /// \}
/// \brief Constructor.
/// \param[in] point : the image as the population of pixels.
diff --git a/scribo/sandbox/green/mln/fun/p2b/achromatic.hh
b/scribo/sandbox/green/mln/fun/p2b/achromatic.hh
index 1f45b2d..91a2dc5 100644
--- a/scribo/sandbox/green/mln/fun/p2b/achromatic.hh
+++ b/scribo/sandbox/green/mln/fun/p2b/achromatic.hh
@@ -44,15 +44,29 @@ namespace mln
namespace p2b
{
- /// \brief Functor that compare the i-th component of a value.
- // V is for the type of the value received
- // i is the ith component to select
+ /// \brief Functor that compare the i-th component with a threshold.
+ ///
+ /// T_rgb is the kind of RGB we use.
template <typename T_rgb>
struct achromatic : public Function_v2b< achromatic<T_rgb> >
{
typedef bool result;
+
+ /// \brief Operator that makes the threshold [millet.phd.2008.pdf]
+ ///
+ /// \param[in] p the selected site
+ ///
+ /// \return if the site is achromatic or not.
+ ///
+ /// This a try for opimized the call to the achromatic
+ /// routine. The goal is to decide if a site has got an
+ /// achromatic status or not. This is the true Millet test.
bool operator()(const point2d& p) const;
+ /// \brief Cstor of the object.
+ ///
+ /// \param[in] img the RGB input image.
+ /// \param[in] threshold the value to compare with.
achromatic(const image2d<T_rgb>& img, const float threshold);
const float threshold_;
diff --git a/scribo/sandbox/green/mln/fun/v2v/hue_concentration.hh
b/scribo/sandbox/green/mln/fun/v2v/hue_concentration.hh
index 84d26c8..e776c9a 100644
--- a/scribo/sandbox/green/mln/fun/v2v/hue_concentration.hh
+++ b/scribo/sandbox/green/mln/fun/v2v/hue_concentration.hh
@@ -32,6 +32,10 @@
# include <mln/value/hsv.hh>
# include <mln/value/rgb8.hh>
+/// \file
+///
+/// This is the code for building hue_concentration_map.
+
namespace mln
{
@@ -41,12 +45,18 @@ namespace mln
namespace v2v
{
+ /// \brief internal method for detecting the histogram peak.
+ ///
+ /// \param[in] hue_histo the histogram of hue.
+ ///
+ /// \return the seed of the peek.
unsigned peak_histo(const mln::image1d<unsigned>& hue_histo);
struct hue_concentration : public Function_v2v< hue_concentration >
{
typedef float result;
+ /// \brief Gibe the distance map between actual hue and the peak.
float operator()(const float hue) const;
hue_concentration(const mln::image1d<unsigned>& hue_histo)
diff --git a/scribo/sandbox/green/mln/fun/v2v/rgb_to_achromatism_map.hh
b/scribo/sandbox/green/mln/fun/v2v/rgb_to_achromatism_map.hh
index 6de63ec..126f9bd 100644
--- a/scribo/sandbox/green/mln/fun/v2v/rgb_to_achromatism_map.hh
+++ b/scribo/sandbox/green/mln/fun/v2v/rgb_to_achromatism_map.hh
@@ -49,6 +49,11 @@ namespace mln
/// \brief Convert rgb value to achromatism map.
///
+ /// Convert rgb value to binary achromastism map using the
+ /// rebuilded Millet phd formulae [millet.phd.2008.pdf]. The
+ /// idea is to look at the minimum and maximum of the channels
+ /// and to return the difference.
+ ///
/// \ingroup modfunv2v
template <unsigned n>
diff --git a/scribo/sandbox/green/mln/fun/v2v/rgb_to_hsv.hh
b/scribo/sandbox/green/mln/fun/v2v/rgb_to_hsv.hh
index 3dd8eb0..a191095 100644
--- a/scribo/sandbox/green/mln/fun/v2v/rgb_to_hsv.hh
+++ b/scribo/sandbox/green/mln/fun/v2v/rgb_to_hsv.hh
@@ -34,6 +34,11 @@
#include <mln/value/hsv.hh>
#include <mln/value/rgb.hh>
+/// \fiie
+///
+/// This is the millet [millet.phd.2008.pdf] transformation from RGB
+/// space to HSV space.
+
namespace mln
{
@@ -57,7 +62,15 @@ namespace mln
typedef T_hsv result;
- /// HSV implementation from millet.2008.phd.pdf p67
+ /// \brief HSV implementation from millet.2008.phd.pdf p67
+ ///
+ /// \param[in] rgb the input rgb pixel.
+ ///
+ /// \return a HSV pixel.
+ ///
+ /// This is the Millet implementation of its transformation
+ /// operator to go from RGB space to HSV space. When pixels
+ /// are achromatic, hue equals -1.
template <typename T_rgb>
T_hsv operator()(const T_rgb& rgb) const;
--
1.5.6.5