
* apps/morphers/mask+channel.cc, * apps/morphers/recorder.cc, * apps/morphers/mask+recorder.cc: New. * apps/morphers/Makefile.am: New. * apps/Makefile.am (SUBDIRS): Add morphers. --- milena/ChangeLog | 11 ++ milena/apps/Makefile.am | 5 +- .../Makefile.am | 24 +++- .../morphers/mask+channel.cc} | 76 +++++------ milena/apps/morphers/mask+recorder.cc | 140 ++++++++++++++++++++ milena/apps/morphers/recorder.cc | 135 +++++++++++++++++++ 6 files changed, 338 insertions(+), 53 deletions(-) copy milena/apps/{constrained-connectivity => morphers}/Makefile.am (62%) copy milena/{doc/examples/tuto3_rw_image.cc => apps/morphers/mask+channel.cc} (58%) create mode 100644 milena/apps/morphers/mask+recorder.cc create mode 100644 milena/apps/morphers/recorder.cc diff --git a/milena/ChangeLog b/milena/ChangeLog index 544cc30..c10deb8 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,3 +1,14 @@ +2011-11-14 Roland Levillain <roland@lrde.epita.fr> + + Add examples of morphers. + + * apps/morphers/mask+channel.cc, + * apps/morphers/recorder.cc, + * apps/morphers/mask+recorder.cc: + New. + * apps/morphers/Makefile.am: New. + * apps/Makefile.am (SUBDIRS): Add morphers. + 2011-10-04 Roland Levillain <roland@lrde.epita.fr> Handle the case of filling an empty border. diff --git a/milena/apps/Makefile.am b/milena/apps/Makefile.am index c42ffd7..465f1db 100644 --- a/milena/apps/Makefile.am +++ b/milena/apps/Makefile.am @@ -1,4 +1,5 @@ -# Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE). +# Copyright (C) 2008, 2009, 2011 EPITA Research and Development +# Laboratory (LRDE). # # This file is part of Olena. # @@ -16,7 +17,7 @@ # # Applied examples of Milena. -SUBDIRS = mesh-segm-skel graph-morpho constrained-connectivity +SUBDIRS = mesh-segm-skel graph-morpho constrained-connectivity morphers # Examples from papers. SUBDIRS += papers diff --git a/milena/apps/constrained-connectivity/Makefile.am b/milena/apps/morphers/Makefile.am similarity index 62% copy from milena/apps/constrained-connectivity/Makefile.am copy to milena/apps/morphers/Makefile.am index c0dfb0d..d7af433 100644 --- a/milena/apps/constrained-connectivity/Makefile.am +++ b/milena/apps/morphers/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE). +# Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE). # # This file is part of Olena. # @@ -14,17 +14,27 @@ # You should have received a copy of the GNU General Public License # along with Olena. If not, see <http://www.gnu.org/licenses/>. +# Illustrations of morphers. + # Find Milena headers. AM_CPPFLAGS = -I$(top_srcdir)/milena -I$(top_builddir)/milena # Produce fast code. APPS_CXXFLAGS = @APPS_CXXFLAGS@ AM_CXXFLAGS = $(APPS_CXXFLAGS) -noinst_PROGRAMS = constrained-connectivity -constrained_connectivity_SOURCES = constrained-connectivity.cc -constrained_connectivity_CXXFLAGS = $(AM_CXXFLAGS) $(STRICT_ALIASING_CXXFLAGS) +noinst_PROGRAMS = \ + mask+channel \ + recorder \ + mask+recorder + +mask_channel_SOURCES = mask+channel.cc +recorder_SOURCES = recorder.cc +mask_recorder_SOURCES = mask+recorder.cc -TESTS = test-constrained-connectivity +MOSTLYCLEANFILES = \ + lena-mask-channel.ppm \ + lena-fill??????.ppm \ + lena-roi-fill??????.ppm -# The sample image form Pierre Soille's PAMI 2008 article. -EXTRA_DIST = soille.pgm +# FIXME: Also produce movies (see comments in recorder.cc and +# mask+recorder.cc.) diff --git a/milena/doc/examples/tuto3_rw_image.cc b/milena/apps/morphers/mask+channel.cc similarity index 58% copy from milena/doc/examples/tuto3_rw_image.cc copy to milena/apps/morphers/mask+channel.cc index 14ba056..ffbe023 100644 --- a/milena/doc/examples/tuto3_rw_image.cc +++ b/milena/apps/morphers/mask+channel.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE) // // This file is part of Olena. // @@ -24,58 +24,46 @@ // executable file might be covered by the GNU General Public License. /// \file +/// \brief Example projecting a RGB image to the green channel and +/// then applying a domain restricting with a mask. -#include <mln/core/image/image2d.hh> -#include <mln/value/rgb8.hh> -#include <mln/data/fill.hh> -#include <mln/data/paste.hh> -#include <mln/core/routine/duplicate.hh> -#include <mln/literal/colors.hh> -#include <mln/opt/at.hh> +#include <sstream> +#include <iomanip> -#include <tests/data.hh> -#include <doc/tools/sample_utils.hh> +#include <string> -int main() -{ - using namespace mln; +#include <mln/core/image/image2d.hh> +#include <mln/core/image/dmorph/image_if.hh> +#include <mln/fun/component/green.hh> - // \{ - image2d<value::rgb8> ima(40, 40); - // \} +#include <mln/value/rgb8.hh> + +/* FIXME: We wanted to use `fun_image' and `operator<<' from + <mln/core/image/vmorph/fun_image.hh, but they only create read-only + images. Use `thru_image' instead. */ +#include <mln/core/image/vmorph/thru_image.hh> - // \{ - data::fill(ima, literal::red); - // \} +#include <mln/core/routine/duplicate.hh> - // \{ - for (def::coord row = 20; row < 30; ++row) - for (def::coord col = 20; col < 30; ++col) - ima(point2d(row, col)) = literal::blue; - // \} +#include <mln/literal/colors.hh> +#include <mln/data/fill.hh> - // \{ - for (def::coord row = 20; row < 30; ++row) - for (def::coord col = 20; col < 30; ++col) - opt::at(ima, row, col) = literal::blue; - // \} - doc::ppmsave(ima, "tuto3_rw_image"); +#include <mln/io/ppm/all.hh> - image2d<value::rgb8> ima2 = duplicate(ima); +#include "apps/data.hh" - // \{ - image2d<value::rgb8> lena; - io::ppm::load(lena, MLN_IMG_DIR "/small.ppm"); - // \} - // \{ - data::fill(ima, lena); - // \} - doc::ppmsave(ima, "tuto3_rw_image"); +int main() +{ + using namespace mln; + using mln::value::rgb8; - ima = ima2; - // \{ - data::paste(ima, lena); - // \} - doc::ppmsave(lena, "tuto3_rw_image"); + image2d<rgb8> lena = io::ppm::load<rgb8>(MLN_IMG_DIR "/tiny.ppm"); + fun::green green; + /* FIXME: Cheat: use generic fill as mln::decorated_image does not + define properly its properties. */ + data::impl::generic::fill_with_value((thru(green, lena).rw() | + box2d(point2d(5,5), point2d(10,10))).rw(), + 255); + io::ppm::save(lena, "lena-mask-channel.ppm"); } diff --git a/milena/apps/morphers/mask+recorder.cc b/milena/apps/morphers/mask+recorder.cc new file mode 100644 index 0000000..d697451 --- /dev/null +++ b/milena/apps/morphers/mask+recorder.cc @@ -0,0 +1,140 @@ +// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +/// \file +/// \brief Morpher recording every change in the morphed image +/// followed by the application of a domain restriction with a mask. +/// +/// To produce an AVI movie from the `lena-roi-fill*.ppm' files, use: +/// +/// for f in lena-roi-fill*ppm; convert $f -scale 2500% $(basename $f .ppm).png +/// mencoder "mf://lena-roi-fill*.png" -o lena-roi-fill.avi -ovc lavc -lavcopts vcodec=mjpeg +/// +/// The output `lena-roi-fill.avi' can be embedded in a PDF file. */ + +// FIXME: Factor with recorder.cc. + +#include <sstream> +#include <iomanip> + +#include <string> + +#include <mln/core/image/image2d.hh> +#include <mln/core/image/dmorph/image_if.hh> +#include <mln/core/image/imorph/decorated_image.hh> + +#include <mln/value/rgb8.hh> + +#include <mln/core/routine/duplicate.hh> + +#include <mln/literal/colors.hh> +#include <mln/data/fill.hh> + +#include <mln/io/ppm/all.hh> + +#include "apps/data.hh" + + +// FIXME: mln::decorated_image lacks a proper definition of +// properties! (see mln/core/image/imorph/decorated_image.hh +namespace mln +{ + + namespace trait + { + + template <typename I, typename D> + struct image_< decorated_image<I,D> > + : default_image_morpher< I, + mln_value(I), + decorated_image<I,D> > + { + typedef trait::image::category::identity_morpher category; + }; + + } // end of namespace mln::trait + +} // end of namespace mln + + +// Recorder. +template <typename I> +struct recorder +{ + void reading(const I&, const mln_psite(I)&) const + { + // N/A. + } + + void writing(I& ima, const mln_psite(I)&, const mln_value(I)&) + { + sequence.push_back(mln::duplicate(ima)); + } + + std::vector<I> sequence; +}; + +template <typename I> +mln::decorated_image< I, recorder<I> > +record(mln::Image<I>& ima) +{ + return mln::decorate(ima, recorder<I>()); +} + + +// I/O. +namespace ppm +{ + template <typename I> + void + save(const mln::decorated_image< I, recorder<I> >& rec, + const std::string& prefix) + { + for (size_t i = 0; i < rec.decoration().sequence.size(); ++i) + { + std::stringstream s; + s << std::setfill ('0') << std::setw (6) << i; + mln::io::ppm::save(rec.decoration().sequence[i], + prefix + s.str() + ".ppm"); + } + } +} + + +int main() +{ + using namespace mln; + using mln::value::rgb8; + + typedef image2d<rgb8> I; + I lena = io::ppm::load<rgb8>(MLN_IMG_DIR "/tiny.ppm"); + decorated_image< I, recorder<I> > lena_rec = record(lena); + /* FIXME: Cheat: use generic fill as mln::decorated_image does not + define properly its properties. */ + data::impl::generic::fill_with_value((lena_rec | box2d(point2d(5,5), + point2d(10,10))).rw(), + literal::green); + ppm::save(lena_rec, "lena-roi-fill"); +} diff --git a/milena/apps/morphers/recorder.cc b/milena/apps/morphers/recorder.cc new file mode 100644 index 0000000..195f24c --- /dev/null +++ b/milena/apps/morphers/recorder.cc @@ -0,0 +1,135 @@ +// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see <http://www.gnu.org/licenses/>. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +/// \file +/// \brief Morpher recording every change in the morphed image. +/// +/// To produce an AVI movie from the `lena-fill*.ppm' files, use: +/// +/// for f in lena-fill*ppm; convert $f -scale 2500% $(basename $f .ppm).png +/// mencoder "mf://lena-fill*.png" -o lena-fill.avi -ovc lavc -lavcopts vcodec=mjpeg +/// +/// The output `lena-fill.avi' can be embedded in a PDF file. */ + +#include <sstream> +#include <iomanip> + +#include <string> + +#include <mln/core/image/image2d.hh> +#include <mln/core/image/imorph/decorated_image.hh> + +#include <mln/value/rgb8.hh> + +#include <mln/core/routine/duplicate.hh> + +#include <mln/literal/colors.hh> +#include <mln/data/fill.hh> + +#include <mln/io/ppm/all.hh> + +#include "apps/data.hh" + + +// FIXME: mln::decorated_image lacks a proper definition of +// properties! (see mln/core/image/imorph/decorated_image.hh +namespace mln +{ + + namespace trait + { + + template <typename I, typename D> + struct image_< decorated_image<I,D> > + : default_image_morpher< I, + mln_value(I), + decorated_image<I,D> > + { + typedef trait::image::category::identity_morpher category; + }; + + } // end of namespace mln::trait + +} // end of namespace mln + + +// Recorder. +template <typename I> +struct recorder +{ + void reading(const I&, const mln_psite(I)&) const + { + // N/A. + } + + void writing(I& ima, const mln_psite(I)&, const mln_value(I)&) + { + sequence.push_back(mln::duplicate(ima)); + } + + std::vector<I> sequence; +}; + +template <typename I> +mln::decorated_image< I, recorder<I> > +record(mln::Image<I>& ima) +{ + return mln::decorate(ima, recorder<I>()); +} + + +// I/O. +namespace ppm +{ + template <typename I> + void + save(const mln::decorated_image< I, recorder<I> >& rec, + const std::string& prefix) + { + for (size_t i = 0; i < rec.decoration().sequence.size(); ++i) + { + std::stringstream s; + s << std::setfill ('0') << std::setw (6) << i; + mln::io::ppm::save(rec.decoration().sequence[i], + prefix + s.str() + ".ppm"); + } + } +} + + +int main() +{ + using namespace mln; + using mln::value::rgb8; + + typedef image2d<rgb8> I; + I lena = io::ppm::load<rgb8>(MLN_IMG_DIR "/tiny.ppm"); + decorated_image< I, recorder<I> > lena_rec = record(lena); + /* FIXME: Cheat: use generic fill as mln::decorated_image does not + define properly its properties. */ + data::impl::generic::fill_with_value(lena_rec, + literal::green); + ppm::save(lena_rec, "lena-fill"); +} -- 1.7.2.5