
* doc/doxyfuns.sty: add new commands. * doc/examples/Makefile.am * doc/examples/examples.mk * doc/examples/fill.cc * doc/examples/tuto3/colorize.cc * doc/examples/tuto3/fill_non_generic.cc.raw * doc/examples/tuto3/first_routine.cc * doc/examples/tuto3/println.cc * doc/examples/tuto3/trace.cc: add new examples used in the doc. * doc/figures/colorize-1.pgm * doc/figures/colorize-2.ppm * doc/figures/figures.mk * doc/figures/fill-1.ppm * doc/figures/fill-2.ppm * doc/outputs/colorize.txt * doc/outputs/first_routine.txt * doc/outputs/outputs.mk * doc/outputs/println.txt * doc/outputs/trace.txt: add new reference files. * doc/ref_guide/ref_guide.tex: fix URL and missing spaces. * doc/tutorial/tutorial.tex: write chapter "Getting started with Milena". --- milena/ChangeLog | 31 ++ milena/doc/doxyfuns.sty | 4 + milena/doc/examples/Makefile.am | 16 +- milena/doc/examples/examples.mk | 8 + milena/doc/examples/fill.cc | 17 + milena/doc/examples/tuto3/colorize.cc | 25 ++ milena/doc/examples/tuto3/fill_non_generic.cc.raw | 8 + milena/doc/examples/tuto3/first_routine.cc | 98 ++++++ milena/doc/examples/tuto3/println.cc | 33 ++ milena/doc/examples/tuto3/trace.cc | 25 ++ milena/doc/figures/colorize-1.pgm | Bin 0 -> 141 bytes milena/doc/figures/colorize-2.ppm | Bin 0 -> 191 bytes milena/doc/figures/figures.mk | 2 + milena/doc/figures/fill-1.ppm | Bin 0 -> 12406 bytes milena/doc/figures/fill-2.ppm | Bin 0 -> 12406 bytes milena/doc/outputs/outputs.mk | 1 + milena/doc/outputs/println.txt | 22 ++ milena/doc/outputs/trace.txt | 12 + milena/doc/ref_guide/ref_guide.tex | 22 +- milena/doc/tutorial/tutorial.tex | 328 ++++++++++++++++++++- 20 files changed, 635 insertions(+), 17 deletions(-) create mode 100644 milena/doc/examples/tuto3/colorize.cc create mode 100644 milena/doc/examples/tuto3/fill_non_generic.cc.raw create mode 100644 milena/doc/examples/tuto3/first_routine.cc create mode 100644 milena/doc/examples/tuto3/println.cc create mode 100644 milena/doc/examples/tuto3/trace.cc create mode 100644 milena/doc/figures/colorize-1.pgm create mode 100644 milena/doc/figures/colorize-2.ppm create mode 100644 milena/doc/figures/fill-1.ppm create mode 100644 milena/doc/figures/fill-2.ppm create mode 100644 milena/doc/outputs/colorize.txt create mode 100644 milena/doc/outputs/first_routine.txt create mode 100644 milena/doc/outputs/println.txt create mode 100644 milena/doc/outputs/trace.txt diff --git a/milena/ChangeLog b/milena/ChangeLog index 6117e06..1c20f7d 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,3 +1,34 @@ +2009-04-17 Guillaume Lazzara <lazzara@lrde.epita.fr> + + Update tutorial - Write "Getting started with Milena". + + * doc/doxyfuns.sty: add new commands. + + * doc/examples/Makefile.am + * doc/examples/examples.mk + * doc/examples/fill.cc + * doc/examples/tuto3/colorize.cc + * doc/examples/tuto3/fill_non_generic.cc.raw + * doc/examples/tuto3/first_routine.cc + * doc/examples/tuto3/println.cc + * doc/examples/tuto3/trace.cc: add new examples used in the doc. + + * doc/figures/colorize-1.pgm + * doc/figures/colorize-2.ppm + * doc/figures/figures.mk + * doc/figures/fill-1.ppm + * doc/figures/fill-2.ppm + * doc/outputs/colorize.txt + * doc/outputs/first_routine.txt + * doc/outputs/outputs.mk + * doc/outputs/println.txt + * doc/outputs/trace.txt: add new reference files. + + * doc/ref_guide/ref_guide.tex: fix URL and missing spaces. + + * doc/tutorial/tutorial.tex: write chapter "Getting started with + Milena". + 2009-04-15 Guillaume Lazzara <lazzara@lrde.epita.fr> Small fixes. diff --git a/milena/doc/doxyfuns.sty b/milena/doc/doxyfuns.sty index 5424d05..a5fd47b 100644 --- a/milena/doc/doxyfuns.sty +++ b/milena/doc/doxyfuns.sty @@ -225,3 +225,7 @@ $$ \textbf{\textit{#1}} } +\newcommand{\B}[1]{ +\textbf{#1} +} + diff --git a/milena/doc/examples/Makefile.am b/milena/doc/examples/Makefile.am index c343312..57209da 100644 --- a/milena/doc/examples/Makefile.am +++ b/milena/doc/examples/Makefile.am @@ -17,6 +17,7 @@ noinst_PROGRAMS = \ fill-subdomain \ fill-subdomain-shorter \ fill-subimage-cfun \ + first_routine \ forall-piter \ fun-p2v-1 \ graph-data \ @@ -50,6 +51,13 @@ tuto2_first_image \ tuto3_rw_image \ tuto4_genericity_and_algorithms +# Tuto3 +noinst_PROGRAMS += \ +colorize \ +println \ +trace + + accu_right_instanciation_SOURCES = accu-right-instanciation.cc borderthickness_SOURCES = borderthickness.cc box2d_bbox_SOURCES = box2d-bbox.cc @@ -64,6 +72,7 @@ fill_part_image_SOURCES = fill-part-image.cc fill_subdomain_SOURCES = fill-subdomain.cc fill_subdomain_shorter_SOURCES = fill-subdomain-shorter.cc fill_subimage_cfun_SOURCES = fill-subimage-cfun.cc +first_routine_SOURCES = tuto3/first_routine.cc forall_piter_SOURCES = forall-piter.cc fun_p2v_1_SOURCES = fun-p2v-1.cc graph_data_SOURCES = graph-data.cc @@ -95,6 +104,11 @@ tuto2_first_image_SOURCES = tuto2_first_image.cc tuto3_rw_image_SOURCES = tuto3_rw_image.cc tuto4_genericity_and_algorithms_SOURCES = tuto4_genericity_and_algorithms.cc +# Tuto 3 +colorize_SOURCES = tuto3/colorize.cc +println_SOURCES = tuto3/println.cc +trace_SOURCES = tuto3/trace.cc + all: clean-figures mkdir -p $(OUTPUTS_BUILDDIR) mkdir -p $(FIGURES_BUILDDIR) @@ -171,7 +185,7 @@ fix-refdata: split-samples: mkdir -p $(EXAMPLES_BUILDDIR) @failcom='exit 1'; \ - list='$(EXAMPLES_SRCDIR)/*.cc'; for file in $$list; do \ + list=`find $(EXAMPLES_SRCDIR) -type f -name '*.cc'`; for file in $$list; do \ $(DOC_SRCDIR)/tools/split_sample.sh $$file cc $(EXAMPLES_BUILDDIR)\ || eval $$failcom; \ done diff --git a/milena/doc/examples/examples.mk b/milena/doc/examples/examples.mk index 65b0a3f..4449d52 100644 --- a/milena/doc/examples/examples.mk +++ b/milena/doc/examples/examples.mk @@ -48,13 +48,21 @@ examples/point-1.cc \ examples/box2d-bbox.cc \ examples/forall-piter.cc \ examples/ima-size.cc \ +examples/tuto2 \ examples/examples.mk \ +examples/tuto4 \ examples/borderthickness.cc \ examples/Makefile.in \ examples/ima-load.cc \ examples/ima-has.cc \ examples/win-create-1.cc \ examples/samples.mk \ +examples/tuto3 \ +examples/tuto3/fill_non_generic.cc.raw \ +examples/tuto3/colorize.cc \ +examples/tuto3/println.cc \ +examples/tuto3/trace.cc \ +examples/tuto3/first_routine.cc \ examples/accu-wrong-instanciation.cc.raw \ examples/accu-right-instanciation.cc \ examples/ima2d-5.cc \ diff --git a/milena/doc/examples/fill.cc b/milena/doc/examples/fill.cc index 0e98634..c4184b4 100644 --- a/milena/doc/examples/fill.cc +++ b/milena/doc/examples/fill.cc @@ -1,4 +1,6 @@ #include <mln/essential/2d.hh> +#include <tests/data.hh> +#include <doc/tools/sample_utils.hh> // \{ template <typename I> @@ -12,4 +14,19 @@ void fill(I& ima, mln_value(I) v) int main() { + using namespace mln; + + image2d<value::rgb8> ima; + io::ppm::load(ima, MLN_IMG_DIR "/small.ppm"); + + // \{ + box2d b(20,20); + fill((ima | b).rw(), literal::green); + // \} + doc::ppmsave(ima, "fill"); + + // \{ + fill(ima, literal::green); + // \} + doc::ppmsave(ima, "fill"); } diff --git a/milena/doc/examples/tuto3/colorize.cc b/milena/doc/examples/tuto3/colorize.cc new file mode 100644 index 0000000..59dba6f --- /dev/null +++ b/milena/doc/examples/tuto3/colorize.cc @@ -0,0 +1,25 @@ +#include <mln/core/image/image2d.hh> +#include <mln/make/image2d.hh> +#include <mln/value/int_u8.hh> +#include <mln/debug/colorize.hh> +#include <doc/tools/sample_utils.hh> + +int main() +{ + using namespace mln; + using namespace mln::value; + + // \{ + int_u8 vals[25] = { 100, 100, 200, 200, 230, + 100, 100, 200, 230, 230, + 140, 140, 140, 0, 0, + 65, 186, 65, 127, 127, + 65, 65, 65, 127, 127 }; + + image2d<int_u8> ima = make::image2d(vals); + image2d<rgb8> ima_color = debug::colorize(rgb8(), ima, 230); + // \} + + doc::pgmsave(ima, "colorize"); + doc::ppmsave(ima_color, "colorize"); +} diff --git a/milena/doc/examples/tuto3/fill_non_generic.cc.raw b/milena/doc/examples/tuto3/fill_non_generic.cc.raw new file mode 100644 index 0000000..d2cd39b --- /dev/null +++ b/milena/doc/examples/tuto3/fill_non_generic.cc.raw @@ -0,0 +1,8 @@ +// Java or C -like code + +void fill(image ima, unsigned char v) +{ + for (int i = 0; i < ima->nrows; ++i) + for (int j = 0; j < ima->ncols; ++j) + ima->data[i][j] = v; +} diff --git a/milena/doc/examples/tuto3/first_routine.cc b/milena/doc/examples/tuto3/first_routine.cc new file mode 100644 index 0000000..a0eb870 --- /dev/null +++ b/milena/doc/examples/tuto3/first_routine.cc @@ -0,0 +1,98 @@ +#include <mln/essential/2d.hh> +#include <tests/data.hh> +#include <doc/tools/sample_utils.hh> + +// \{ +namespace mln +{ + + template <typename I, typename N> + mln_concrete(I) + my_algorithm(const Image<I>& ima_, + const Neighborhood<N>& nbh_) + { + trace::entering("my_algorithm"); + + const I& ima = exact(ima_); + const N& nbh = exact(nbh_); + mln_precondition(ima.is_valid()); + mln_precondition(nbh.is_valid()); + + typedef value::label_8 V; + V nlabels; + mln_ch_value(I,V) lbl = labeling::blobs(ima, nbh, nlabels); + util::array<unsigned> + count = labeling::compute(accu::meta::count(), lbl, nlabels); + + mln_concrete(I) output; + initialize(output, ima); + data::fill(output, literal::one); + + for (unsigned i = 1; i <= nlabels; ++i) + if (count[i] < 10u) + data::fill((output | pw::value(lbl) == pw::cst(i)).rw(), literal::zero); + + trace::exiting("my_algorithm"); + return output; + } + +} // end of namespace mln +// \} + +namespace sandbox +{ + + using namespace mln; + + // \{ + template <typename I, typename N> + mln_concrete(I) + my_algorithm(const Image<I>& ima_, + const Neighborhood<N>& nbh_) + // \} + { + // \{ + trace::entering("my_algorithm"); + // \} + + // \{ + const I& ima = exact(ima_); + const N& nbh = exact(nbh_); + mln_precondition(ima.is_valid()); + mln_precondition(nbh.is_valid()); + // \} + + // \{ + typedef value::label_8 V; + V nlabels; + mln_ch_value(I,V) lbl = labeling::blobs(ima, nbh, nlabels); + util::array<unsigned> + count = labeling::compute(accu::meta::count(), lbl, nlabels); + // \} + + // \{ + mln_concrete(I) output; + initialize(output, ima); + data::fill(output, literal::one); + // \} + + // \{ + for (unsigned i = 1; i <= nlabels; ++i) + if (count[i] < 10u) + data::fill((output | pw::value(lbl) == pw::cst(i)).rw(), literal::zero); + // \} + + // \{ + trace::exiting("my_algorithm"); + return output; + // \} + } + +} // end of namespace mln + +int main() +{ + mln::image2d<bool> test(2,2); + mln_assertion(sandbox::my_algorithm(test, mln::c4()) + == mln::my_algorithm(test, mln::c4())); +} diff --git a/milena/doc/examples/tuto3/println.cc b/milena/doc/examples/tuto3/println.cc new file mode 100644 index 0000000..8ee60be --- /dev/null +++ b/milena/doc/examples/tuto3/println.cc @@ -0,0 +1,33 @@ +#include <mln/core/image/image2d.hh> +#include <mln/data/fill.hh> +#include <mln/border/fill.hh> +#include <mln/value/int_u8.hh> +#include <mln/debug/println.hh> +#include <mln/debug/println_with_border.hh> + +int main() +{ + using namespace mln; + using namespace mln::value; + + { + std::cout << "// \\{" << std::endl; + // \{ + image2d<int_u8> ima(5,5); + data::fill(ima, 2); + debug::println(ima); + // \} + std::cout << "// \\}" << std::endl; + } + + { + std::cout << "// \\{" << std::endl; + // \{ + image2d<int_u8> ima(5,5); + data::fill(ima, 2); + border::fill(ima, 7); + debug::println_with_border(ima); + // \} + std::cout << "// \\}" << std::endl; + } +} diff --git a/milena/doc/examples/tuto3/trace.cc b/milena/doc/examples/tuto3/trace.cc new file mode 100644 index 0000000..3e0cd41 --- /dev/null +++ b/milena/doc/examples/tuto3/trace.cc @@ -0,0 +1,25 @@ +#include <mln/core/image/image2d.hh> +#include <mln/value/label_8.hh> +#include <mln/labeling/blobs.hh> +#include <mln/core/alias/neighb2d.hh> +#include <mln/geom/bbox.hh> + +int main() +{ + using namespace mln; + using namespace mln::value; + + image2d<bool> ima(200,300); + label_8 nlabels; + // \{ + // ... + trace::quiet = false; + + labeling::blobs(ima, c4(), nlabels); + + trace::quiet = true; + + geom::bbox(ima); + // ... + // \} +} diff --git a/milena/doc/figures/colorize-1.pgm b/milena/doc/figures/colorize-1.pgm new file mode 100644 index 0000000000000000000000000000000000000000..d7222c74ff5c14fbc536a26736f4f4a3d9427ee7 GIT binary patch literal 141 zcmWGA<x*B~Pt8j$N-RlDQAny(@XgFg%}Z1;)H6^}$S5f(u+rDh2Z`wA6s4r<r50qC zB<iIV0d=_sc!oGC1f>?ICKe@UC?w{kD7d7SrRL-p<fi78DEK5M<pT}PFRE0~@CkBp m)#Nf&Fy%5bHRVc4IdS3{ka+g2r>BR3!Eu*keZ8Y2kN^O=qA;8Q literal 0 HcmV?d00001 diff --git a/milena/doc/figures/colorize-2.ppm b/milena/doc/figures/colorize-2.ppm new file mode 100644 index 0000000000000000000000000000000000000000..c7b0c0151897e22f7a089ef8d7f16af669a11061 GIT binary patch literal 191 zcmWGA<5E^|Pt8j$N-RlDQAny(@XgFg%}Z1;)H6^}$S5f(u+rDh2Z`wA6s4r<r50qC zB<iIV0d=_sc!oGC1f>?ICKe@UC?w{kD7d7SrRL-p<fi78DEK5M<pT}PFRE0~@CkBp z)#Nf&Fy%5bHRTeKkOCq<#jQZ3ILQpo1+szYV$L!MVgQ3p2d@_fhyuy?T3dh!$bcXS F7XaWkM92UD literal 0 HcmV?d00001 diff --git a/milena/doc/figures/figures.mk b/milena/doc/figures/figures.mk index 41dba2b..42d8724 100644 --- a/milena/doc/figures/figures.mk +++ b/milena/doc/figures/figures.mk @@ -27,6 +27,7 @@ figures/logical-not-3.pbm \ figures/tuto4_genericity_and_algorithms-3.pbm \ figures/tuto4_genericity_and_algorithms-1.ppm \ figures/extend-4.ppm \ +figures/fill-2.ppm \ figures/tuto4_genericity_and_algorithms-8.ppm \ figures/labeling-compute-1.pbm \ figures/tuto3_rw_image-3.ppm \ @@ -35,4 +36,5 @@ figures/tuto4_genericity_and_algorithms-8.pgm \ figures/extend-2.ppm \ figures/tuto4_genericity_and_algorithms-2.ppm \ figures/fill-subdomain-1.pbm \ +figures/fill-1.ppm \ figures/tuto3_rw_image-2.ppm diff --git a/milena/doc/figures/fill-1.ppm b/milena/doc/figures/fill-1.ppm new file mode 100644 index 0000000000000000000000000000000000000000..ce4039f142f1e01315853e4bfbac4a24efa81e6f GIT binary patch literal 12406 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 G@c#vb$#MJu literal 0 HcmV?d00001 diff --git a/milena/doc/figures/fill-2.ppm b/milena/doc/figures/fill-2.ppm new file mode 100644 index 0000000000000000000000000000000000000000..4d4213108284b26441c0e14fdac067d72373e8c0 GIT binary patch literal 12406 zcmeIu!3u&v6oui|^As1_)Ml(u7wrNi0t1m=V9Xl|rZNqIPha*HEq*ww1LrKhGBs;C z>!98RZKR&%+Vwg(+1s5+8^UyqqVd<*-ZyG>>VmTmzpV1|ayv<-FLnOjiW?fq^sW6k zJ#`3DxO!YpM?cG^sIq)((pb{i9FoMWJ}ZI%0tg_000IagfB*srAb<b@2q1s}0tg_0 n00IagfB*srAb<b@2q1s}0tg_000IagfB*srAb<b@e=hI^FboyG literal 0 HcmV?d00001 diff --git a/milena/doc/outputs/colorize.txt b/milena/doc/outputs/colorize.txt new file mode 100644 index 0000000..e69de29 diff --git a/milena/doc/outputs/first_routine.txt b/milena/doc/outputs/first_routine.txt new file mode 100644 index 0000000..e69de29 diff --git a/milena/doc/outputs/outputs.mk b/milena/doc/outputs/outputs.mk index 1e4c9cf..bb57832 100644 --- a/milena/doc/outputs/outputs.mk +++ b/milena/doc/outputs/outputs.mk @@ -7,6 +7,7 @@ outputs/accu-right-instanciation.txt \ outputs/extend.txt \ outputs/ima2d-1.txt \ outputs/borderthickness.txt \ +outputs/first_routine.txt \ outputs/ima-save.txt \ outputs/fill-subimage-cfun.txt \ outputs/labeling-compute.txt \ diff --git a/milena/doc/outputs/println.txt b/milena/doc/outputs/println.txt new file mode 100644 index 0000000..307681c --- /dev/null +++ b/milena/doc/outputs/println.txt @@ -0,0 +1,22 @@ +// \{ +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + +// \} +// \{ +7 7 7 7 7 7 7 7 7 7 7 +7 7 7 7 7 7 7 7 7 7 7 +7 7 7 7 7 7 7 7 7 7 7 +7 7 7 2 2 2 2 2 7 7 7 +7 7 7 2 2 2 2 2 7 7 7 +7 7 7 2 2 2 2 2 7 7 7 +7 7 7 2 2 2 2 2 7 7 7 +7 7 7 2 2 2 2 2 7 7 7 +7 7 7 7 7 7 7 7 7 7 7 +7 7 7 7 7 7 7 7 7 7 7 +7 7 7 7 7 7 7 7 7 7 7 + +// \} diff --git a/milena/doc/outputs/trace.txt b/milena/doc/outputs/trace.txt new file mode 100644 index 0000000..f1506c7 --- /dev/null +++ b/milena/doc/outputs/trace.txt @@ -0,0 +1,12 @@ +labeling::blobs { + core::initialize {} + data::fill { + data::fill_with_value { + data::impl::fill_with_value_one_block { + data::memset_ { + data::impl::memset_ {} + } data::memset_ + } data::impl::fill_with_value_one_block + } data::fill_with_value + } data::fill +} labeling::blobs - 0.08s diff --git a/milena/doc/ref_guide/ref_guide.tex b/milena/doc/ref_guide/ref_guide.tex index 59b6199..1464207 100644 --- a/milena/doc/ref_guide/ref_guide.tex +++ b/milena/doc/ref_guide/ref_guide.tex @@ -140,8 +140,8 @@ A copy of the license is provided in the file COPYING.DOC. The latest version of Olena is available at the following addresses: \begin{itemize} - \item http://www.lrde.epita.fr/dload/olena/olena.tar.gz - \item http://www.lrde.epita.fr/dload/olena/olena.tar.bz2 + \item \href{http://www.lrde.epita.fr/dload/olena/olena.tar.gz}{http://www.lrde.epita.fr/dload/olena/olena.tar.gz} + \item \href{http://www.lrde.epita.fr/dload/olena/olena.tar.bz2}{http://www.lrde.epita.fr/dload/olena/olena.tar.bz2} \end{itemize} @@ -151,19 +151,19 @@ The latest version of Olena is available at the following addresses: First uncompress the archive. According to the downloaded archive, the options are different. \begin{verbatim} -$tar zxvf olena.tar.gz +$ tar zxvf olena.tar.gz \end{verbatim} Or \begin{verbatim} -$tar jxvf olena.tar.bz2 +$ tar jxvf olena.tar.bz2 \end{verbatim} Then follow these steps: \begin{verbatim} -$mkdir olena-build -$cd olena-build -$../olena-1.0/configure && make -$sudo make install +$ mkdir olena-build +$ cd olena-build +$ ../olena-1.0/configure && make +$ sudo make install \end{verbatim} @@ -241,7 +241,7 @@ Before writing your first program, please be ware of these hints: slow down a program though and these tests can be disabled by compiling using \code{-DNDEBUG}. \begin{verbatim} -g++ -DNDEBUG -Ipath/to/mln my_program.cc +$ g++ -DNDEBUG -Ipath/to/mln my_program.cc \end{verbatim} \item If you decide to use optimization flags to compile for debugging, @@ -1681,7 +1681,7 @@ You can extend the range of supported files by installing third-parties librarie \end{itemize} \doxysection{ioim}{ImageMagick} - \href{http://www.imagemagick.org/}{http://www.imagemagick.org/} + \href{http://www.imagemagick.org}{http://www.imagemagick.org} You have to install ImageMagick with Magick++ support. You will be able to load every file recognized as an image by ImageMagick. @@ -1701,7 +1701,7 @@ You can extend the range of supported files by installing third-parties librarie installation. \doxysection{iodcm}{GDCM} - \href{http://apps.sourceforge.net/mediawiki/gdcm/}{http://apps.sourceforge.net/mediawiki/gdcm/} + \href{http://apps.sourceforge.net/mediawiki/gdcm}{http://apps.sourceforge.net/mediawiki/gdcm} GDCM is a library for manipulating DICOM files. DICOM files are used in medical imaging. diff --git a/milena/doc/tutorial/tutorial.tex b/milena/doc/tutorial/tutorial.tex index 3326b24..a69e28f 100644 --- a/milena/doc/tutorial/tutorial.tex +++ b/milena/doc/tutorial/tutorial.tex @@ -466,18 +466,18 @@ There are other ways to get to know what is the status of the project. \begin{itemize} \item Olena's trac\\ - \href{https://trac.lrde.org/olena} \\ + \href{https://trac.lrde.org/olena}{https://trac.lrde.org/olena} \\ Here is the roadmap, the current open tickets/bugs/improvements which are taken in consideration. A source browser is also available. \item Olena's Buildfarm \\ - \href{https://buildfarm.lrde.org/buildfarm/oln/} \\ + \href{https://buildfarm.lrde.org/buildfarm/oln/}{https://buildfarm.lrde.org/buildfarm/oln/} \\ The official buildfarm. Every night and after each commit, tests are compiled and run. The buildfarm can show you whether it is safe to update your svn copy of Milena or not\ldots \item Test failures - \href{http://www.lrde.epita.fr/dload/olena/test-failures-daily.html} + \href{http://www.lrde.epita.fr/dload/olena/test-failures-daily.html}{http://www.lrde.epita.fr/dload/olena/test-failures-daily.html} \\ Through this page, you can see exactly which tests do not compile or pass. This page is updated every night. @@ -703,13 +703,18 @@ Text and image outputs will be respectively stored in Few tools are provided with Milena. They can be considered as full program examples. -Currently two tools are available: +Currently two tools are available: \\ + \begin{tabular}{l l} area\_flooding.cc & FIXME:description \\ \hline seed2tiling.cc & FIXME:description \\ \end{tabular} +% +\bigskip +% + To build these tools, run: \begin{verbatim} $ cd /my/path/to/olena-1.0/build/milena/tools @@ -749,7 +754,319 @@ In the installed path prefix, Milena's files are located in: %==================================== \doxychapter{tuto3}{Getting started with Milena} -** intent +\doxysection{getfamiliargen}{Getting familiar with genericity} + +One of Milena's main features is its genericity. In order to understand how to +take benefit of it, let's see what genericity really means for us and how it is +illustrated in the library. + +A \B{Generic algorithm} is written once, without duplicates, and works on +different kind of input. + +Let's have a look to a small example. In any image processing library, we may be +interested in a small routine to fill an image with data. A common +implementation would look like this one: + +\doxyrawcode{tuto3/fill_non_generic} + +In this example, there are a lot of \B{implicit} assumptions about the input: +\begin{itemize} + \item The input image has to be 2D; + \item Its definition domain has to be a rectangle starting at (0,0); + \item Data cannot be of a different type than \type{unsigned char}; + \item Image data need to be stored as a 2D array in RAM. +\end{itemize} +So, what would happen if we would like to use it for 3D images, use rgb8 as +value or even work on a region of interest? + +This implementation would require to be reimplemented and the user would have to +deal with the various version of the fill routine. For the developer, it is error +prone, redundant and hard to maintain. For the user, it is confusing and forces +to always think about what he is manipulating. +According to our definition, this algorithm is clearly \B{not} generic. + +This is not acceptable and that's why Milena is developped considering +genericity and user/developer friendlyness. + +With Milena, the previous example would be written as follow: + +\doxycode{fill} + +In this version, the routine can take any kind of image types as arguments. So +it is for the values: The expected type depends on the value used in the +given image. +The \code{for\_all} loop is also significantly generic to support any kind of +images since the iterator guarantees it will pass through every sites. + +This code is more generic and remains really close to the common description of +the generic algorithm. + +As a result, with this algorithm we can fill an image,... +\doxycode[2]{fill} +\doxyfigure[1]{fill}{3cm} + +... Or fill only a region of interest (a set of points). +\doxycode[3]{fill} +\doxyfigure[2]{fill}{3cm} + + + +\doxysection{firstgenalgo}{First generic algorithm} +In this section, we will introduce several routines/tools which are useful while +writing generic algorithms. It is more important to focus on these +routines/tools than what this program actually does. + + +Here is the full example: + +\doxycode[1]{first_routine} +Let's see the different parts of the algorithm. + + +\doxycode[2]{first_routine} +The prototype is restrictive enough, readable and still generic. +We use concepts to statically check that the generic type passed as +parameter is what the routine expects. The ``exact'' image type is \type{I}. For +instance an image of type \type{image2d} inherits from \type{Image<image2d>}. So +an \type{image2d} is an \type{Image<I>}. +Note that the return type of this function is defined by a macro. +\code{mln\_concrete} is a macro hidding tricky mechanisms (traits) used in Milena. +The important point to remember is that a generic function should not return +\type{I} directly but \code{mln\_concrete(I)} instead. + + +\doxycode[3]{first_routine} +Like any Milena's routine, note that we use \code{trace}. This debugging tool +will be detailled in section \ref{debughints}. + + +\doxycode[4]{first_routine} +Since the function take some arguments thanks their concept, these object cannot +be used as such. Indeed, concepts are empty shells only used for dispatching and +concept checking, that's the reason why they are parameterized with their exact +type. The exact type let us know what is the real type of the object. To get an +objet with the exact type, simply call \code{exact()}. +Of course, it is always a good idea to add few preconditions to help during +debug. + + +\doxycode[5]{first_routine} +In this portion of code, the image is labeled and the number of site per label +is computed. This code does not depend on the image type at all. Again, a macro +\code{mln\_ch\_value} (``mln change value'') helps us. \code{labeling::blobs} is a routine returning an +image of the same kind as the input image but with a different value. +\code{mln\_ch\_value} enables the possibility of doing that, whatever the image type +\type{I} and whatever its value type, it returns the same image type with a +different value type. + + +\doxycode[6]{first_routine} +The output image is declared here. Like any variable, it must be initialized at +some point. To do so, \code{initialize()} is provided. It is a generic routine +which can initialize the geometry any kind of image with another image of the +same kind. +After this call, \var{output} has a valid domain and is valid. It can be used in +an algorithm, here \code{data::fill}, to have its values modified. +Note that the value passed to \code{data::fill} is also generic. The library +includes few generic common values from which any value type can convert to. + + +\doxycode[7]{first_routine} +In this part, every region from the labeled image, of which cardinality is lower +than 10 sites, is set to \val{literal::zero} in \var{output}. +Once again, a generic value is used in order to avoid a constraints on the image +value type. + + +\doxycode[8]{first_routine} +Don't forget to close the trace before exiting the function. Then return the +result. + + + +%FIXME: add an example to show how a routine behavior depends on its arguments. +% => cf. des images etendues ou non et un parcours de voisinage. + + +\doxysection{compilhints}{Compilation} + +\doxysubsection{howtocompile}{Include path} + +If Milena has been installed in a custom directory, e.g. not /usr/include or +/usr/local/include, the path to the library headers must be passed to the +compiler. + +With g++ and MinGW, the option is \B{-I<path>}. +\begin{verbatim} +$ g++ -Ipath/to/mln my_program.cc +\end{verbatim} + +For other compilers, please look at the documentation and search for ``include +path''. + + +\doxysubsection{liblink}{Library linking} +As it is usually expected when using a library, no library linking is needed for +the library itself. +Milena is a ``header only'' library and is compiled ``on demand'' with your +program. + +If you use specific input/output you may need to link your program with the +right graphic library. For more information, please refer to section +\doxyref{inputoutput} in the Quick Reference Guide. + + +\doxysubsection{compildndebug}{Disable Debug} +By default, Olena enables a lot of internal pre and post conditions. Usually, +this is a useful feature and it should be enabled. It can heavily slow down a +program though and these tests can be disabled by compiling using -DNDEBUG: + +\begin{verbatim} +$ g++ -DNDEBUG -Ipath/to/mln my_program.cc +\end{verbatim} + +\doxysubsection{compoptimflags}{Compiler optimization flags} + +In this section you will find remarks about the compiler optimization flags and +their impact on the compilation and execution time. + + +\doxysubsubsection{compoptimgcc}{GCC} + +\begin{itemize} + \item \B{-O0}, combined with -DNDEBUG, it leads to the fastest compilation + time. The execution is somewhat slow though since dispatch functions and one + line members are not inlined by the compiler. + \item \B{-O1}, best compromise between compilation time and execution time. + \item \B{-O2}, \B{-O3}, combined with -DNDEBUG, it leads to the best execution + time. However these optimizations dramatically slow down the compilation and + requires much more memory at compile time. +\end{itemize} + +\doxysubsubsection{compoptimother}{Other compilers} + +Currently, have not tested different optimization flags with other compilers. If +you did, please report us your results. + + + +\doxysection{debughints}{Debug hints} + +\doxysubsection{gdbhints}{Using assertions and GDB} +As said above, Milena already includes a lot of post and pre conditions. +Thus, if you made a mistake in your code there is a high probability that it +will be detected at run time. If an assertion fail, we advice you to compile +with the following options: + +\begin{verbatim} +$ g++ -ggdb -Ipath/to/mln my_program.cc +\end{verbatim} + +Note that you \B{MUST NOT} compile \var{-DNDEBUG} other the assertions will be +deactivated. +Once compiled, restart the program with GDB. + +\begin{verbatim} +$ gdb ./my_program +\end{verbatim} + +In the GDB console, run it again. +\begin{verbatim} +(gdb) run <any parameter you may want to pass to the program> +\end{verbatim} + +When an assertion fails, in the GDB console simply type: +\begin{verbatim} +(gdb) bt +\end{verbatim} + +The full backtrace will be printed out and you will be able to find from where +the error come from. The filenames, the line numbers and the parameters values +are printed out in the backtrace as you can see in the following example: + +\begin{verbatim} +#0 0xffffe410 in __kernel_vsyscall () +#1 0xb7d00640 in raise () from /lib/i686/cmov/libc.so.6 +#2 0xb7d02018 in abort () from /lib/i686/cmov/libc.so.6 +#3 0xb7cf95be in __assert_fail () from /lib/i686/cmov/libc.so.6 +#4 0x0804e094 in mln::image2d<bool>::has (this=0xbff32f34, p=@0xbff32f3c) + at /lrde/stockholm/lazzara/svn/olena/git/oln/milena/mln/core/image/image2d.hh:442 +#5 0x0804e6d7 in mln::image2d<bool>::operator() (this=0xbff32f34, p=@0xbff32f3c) + at /lrde/stockholm/lazzara/svn/olena/git/oln/milena/mln/core/image/image2d.hh:460 +#6 0x080490b0 in main () at test.cc:18 +\end{verbatim} + + + +\doxysubsection{traces}{Traces} +Sometimes, compiling for GDB without optimization flags and with debug +assertions enabled could lead to execution time dramaticaly high. +If the function parameter values are not necessary for debbuging, +a good alternative is the trace system provided in Milena. +Each time a routine is called, a trace log is written. + +This trace allows to follow the stack trace at runtime. It also provides the +time passed in each function call if the call last at least 10ms. + +In order to enable traces in a program, set the related global variable to +true: +\begin{verbatim} +... +trace::quiet = true; +... +\end{verbatim} + +Since it's a global variable, at anytime in the source code, the trace can be +disabled. + +\doxycode[1]{trace} + +The previous code will produce the following trace: + +\begin{verbatim} +labeling::blobs { + core::initialize {} + data::fill { + data::fill_with_value { + data::impl::fill_with_value_one_block { + data::memset_ { + data::impl::memset_ {} + } data::memset_ + } data::impl::fill_with_value_one_block + } data::fill_with_value + } data::fill +} labeling::blobs - 0.08s +\end{verbatim} + +As you can see, \code{labeling::blobs} is located just after having set +\var{trace::quiet} to \val{true} so its trace is part of the output. +\code{geom::bbox}'s trace is not part of the output though since traces have +been disabled just before it is called. + + +\doxysubsection{debugroutines}{Debug routines} +Milena also provides a lot of debug tools. Here is a small list of the tools: +\begin{itemize} + \item mln::debug::println, print an image in the console. + \doxycode[1]{println} + \doxymoutput[1]{println} + + \item mln::debug::println\_with\_border, print an image in the console withs + its border. + \doxycode[2]{println} + \doxymoutput[2]{println} + + \item mln::debug::colorize, colorize a label image with random colors. + \doxycode[1]{colorize} + + \begin{center} + \begin{tabular}{c c c} + \doxyfigure[1]{colorize}{3cm} & ~\huge{$\rightarrow$}~ & + \doxyfigure[2]{colorize}{3cm} \\ + \end{tabular} + \end{center} +\end{itemize} + A very simple processing chain; the target is the end-user! @@ -763,6 +1080,7 @@ compilation time w.r.t compilation options (O1, DNDEBUG). + %==================================== \doxychapter{tuto4}{Step 4: Load and save images} -- 1.5.6.5