
* mln/core/image/imorph/labeled_image.hh: new image type. * mln/trait/ch_value.hh: Specialize ch_value trait for this type. * tests/core/image/imorph/labeled_image.cc: new associated test. --- milena/ChangeLog | 10 + milena/mln/core/image/imorph/labeled_image.hh | 398 +++++++++++++++++++++++ milena/mln/trait/ch_value.hh | 9 + milena/tests/core/image/imorph/labeled_image.cc | 110 +++++++ 4 files changed, 527 insertions(+), 0 deletions(-) create mode 100644 milena/mln/core/image/imorph/labeled_image.hh create mode 100644 milena/tests/core/image/imorph/labeled_image.cc diff --git a/milena/ChangeLog b/milena/ChangeLog index e006366..36ff601 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,5 +1,15 @@ 2009-05-28 Guillaume Lazzara <lazzara@lrde.epita.fr> + Add labeled_image type. + + * mln/core/image/imorph/labeled_image.hh: new image type. + + * mln/trait/ch_value.hh: Specialize ch_value trait for this type. + + * tests/core/image/imorph/labeled_image.cc: new associated test. + +2009-05-28 Guillaume Lazzara <lazzara@lrde.epita.fr> + Move morphers in core/image subdirectories. diff --git a/milena/mln/core/image/imorph/labeled_image.hh b/milena/mln/core/image/imorph/labeled_image.hh new file mode 100644 index 0000000..c81f331 --- /dev/null +++ b/milena/mln/core/image/imorph/labeled_image.hh @@ -0,0 +1,398 @@ +// Copyright (C) 2009 EPITA Research and Development Laboratory +// (LRDE) +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library 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 this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library 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. + +#ifndef MLN_CORE_IMAGE_IMORPH_LABELED_IMAGE_HH +# define MLN_CORE_IMAGE_IMORPH_LABELED_IMAGE_HH + +/// \file mln/core/image/imorph/labeled_image.hh +/// +/// Definition of a morpher on a labeled image. + +# include <mln/core/image/dmorph/image_if.hh> + +# include <mln/core/concept/function.hh> + +# include <mln/core/internal/image_identity.hh> + +# include <mln/core/site_set/box.hh> + +# include <mln/accu/pair.hh> +# include <mln/accu/nil.hh> +# include <mln/accu/center.hh> + +# include <mln/labeling/compute.hh> +# include <mln/labeling/pack.hh> +# include <mln/labeling/relabel.hh> + +# include <mln/util/array.hh> + +# ifndef NDEBUG +# include <mln/accu/max.hh> +# include <mln/level/compute.hh> +# endif // ! NDEBUG + + +namespace mln +{ + + // Forward declarations. + template <typename I> struct labeled_image; + namespace accu + { + template <typename T> struct nil; + template <typename T> struct bbox; + } + + + namespace internal + { + + /// Data structure for \c mln::labeled_image<I>. + template <typename I> + struct data< labeled_image<I> > + { + data(const I& ima, const mln_value(I)& nlabels); + + I ima_; + mln_value(I) nlabels_; + mutable util::array< box<mln_psite(I)> > bboxes_; + }; + + } // end of namespace mln::internal + + + namespace trait + { + + template <typename I> + struct image_< labeled_image<I> > : image_< I > // Same as I except... + { + // ...these changes. + typedef trait::image::category::identity_morpher category; + typedef mln_internal_trait_image_speed_from(I) speed; // Un-fastest. + typedef trait::image::value_access::indirect value_access; + + typedef trait::image::value_io::read_only value_io; + typedef trait::image::pw_io::read pw_io; + + // extended domain + typedef trait::image::ext_value::multiple ext_value; + typedef trait::image::ext_io::read_only ext_io; + }; + + } // end of namespace mln::trait + + + + /// Morpher providing an improved interface for labeled image. + /// + /// \tparam I The label image type. + /// \tparam A An accumulator type. + /// + /// This image type allows to pre-compute components attributes. These + /// attributes can be set through the template parameter \p A. This + /// accumulator type can be a simple accumulator, a pair of accumulators or + /// a tuple. + /// + /// This image type guaranties that the labeling is always contiguous. + /// + /// \sa accu::pair, accu::tuple, mln::accu + /// + /// + /// \ingroup modimageidmorpher + // + template <typename I> + class labeled_image + : public internal::image_identity< const I, mln_domain(I), labeled_image<I> > + { + typedef internal::image_identity< const I, mln_domain(I), labeled_image<I> > + super_; + + public: + + /// Skeleton. + typedef labeled_image< tag::image_<I> > skeleton; + + /// Type of the bounding component bounding boxes. + typedef mln_result(accu::bbox<mln_psite(I)>) bbox_t; + + /// Constructors + /// @{ + /// Constructor without argument. + labeled_image(); + + /// Constructor from an image \p ima and the number of labels \p nlabels. + labeled_image(const I& ima, const mln_value(I)& nlabels); + /// @} + + /// Deferred initialization from a labeled image \p ima and the number + /// of labels \p nlabels. + void init_(const I& ima, const mln_value(I)& nlabels); + + /// Duplicate the underlying image and create a new labeled_image. + void init_from_(const labeled_image<I>& model); + + /// Relabel according to a function. + /// @{ + // + /// Labels may be removed and the labeling may not be contiguous + /// afterwards. + /// FIXME: currently the labels are packed after relabeling for + /// performance reasons. Do we want to be less restrictive? + /// \sa pack_(). + template <typename F> + void relabel(const Function_v2v<F>& f); + // + /// Labels may be removed. This overload make sure the labeling is still + /// contiguous. + template <typename F> + void relabel(const Function_v2b<F>& f); + /// @} + + /// Pack labeling. Relabel if the labeling is not contiguous. + void pack_(); + + /// Return the number of labels; + mln_value(I) nlabels() const; + + /// Update bounding boxes information. + void update_(); + + /// Return the bounding box of the component \p label. + const bbox_t& bbox(const mln_value(I)& label) const; + + const util::array<bbox_t>& bboxes() const + { + return this->data_->bboxes_; + } + + /// Return the domain of the component with label \p label. + /// This is an optimized version. +// p_if<mln_psite(I)> domain(const mln_value(I)& label) const; + }; + + + // init_ + + //FIXME: not enough generic? We would like 'J' instead of + // 'labeled_image<I>'. + template <typename I, typename J> + void init_(tag::image_t, labeled_image<I>& target, + const labeled_image<J>& model); + + + + namespace make + { + + template <typename I> + mln::labeled_image<I> + labeled_image(const Image<I>& ima, const mln_value(I)& nlabels); + + } // end of namespace mln::make + + + + +# ifndef MLN_INCLUDE_ONLY + + + // internal::data< labeled_image<I> > + + namespace internal + { + + + // data< labeled_image<I> > + + template <typename I> + inline + data< labeled_image<I> >::data(const I& ima, const mln_value(I)& nlabels) + : ima_(ima), nlabels_(nlabels) + { + } + + } // end of namespace mln::internal + + + template <typename I> + inline + labeled_image<I>::labeled_image() + { + } + + template <typename I> + inline + labeled_image<I>::labeled_image(const I& ima, const mln_value(I)& nlabels) + { + init_(ima, nlabels); + } + + template <typename I> + inline + void + labeled_image<I>::init_(const I& ima, const mln_value(I)& nlabels) + { + mln_precondition(level::compute(accu::meta::max(), ima) == nlabels); + this->data_ = new internal::data< labeled_image<I> >(ima, nlabels); + this->update_(); + } + + template <typename I> + inline + void + labeled_image<I>::init_from_(const labeled_image<I>& model) + { + this->data_ + = new internal::data< labeled_image<I> >(duplicate(model.hook_data_()->ima_), + model.nlabels()); + this->data_->bboxes_ = model.hook_data_()->bboxes_; + } + + template <typename I> + template <typename F> + inline + void + labeled_image<I>::relabel(const Function_v2v<F>& f_) + { + const F& f = exact(f_); + labeling::relabel_inplace(this->data_->ima_, this->data_->nlabels_, f); + + /// We MUST be sure that the labeling is contiguous in order to compute + /// attributes. + ///FIXME: do we want to be less restrictive? + pack_(); + + /// FIXME: could be highly improved: reorder the attributes according to + /// the function f. + this->update_(); + } + + template <typename I> + template <typename F> + inline + void + labeled_image<I>::relabel(const Function_v2b<F>& f_) + { + const F& f = exact(f_); + labeling::relabel_inplace(this->data_->ima_, this->data_->nlabels_, f); + + /// FIXME: could be highly improved: reorder the attributes according to + /// the function f. + this->update_(); + } + + template <typename I> + inline + void + labeled_image<I>::pack_() + { + labeling::pack_inplace(this->data_->ima_, this->data_->nlabels_); + + /// FIXME: could be highly improved: reorder the attributes according to + /// the way the labels are packed. + this->update_(); + } + + + template <typename I> + inline + mln_value(I) + labeled_image<I>::nlabels() const + { + return this->data_->nlabels_; + } + + + // init_ + + template <typename I, typename J> + void init_(tag::image_t, labeled_image<I>& target, + const labeled_image<J>& model) + { + I ima; + init_(tag::image, ima, model); + target.init_(ima, model.nlabels()); + } + + + template <typename I> + void + labeled_image<I>::update_() + { + this->data_->bboxes_ + = labeling::compute(accu::meta::bbox(), this->data_->ima_, + this->data_->nlabels_); + } + + + template <typename I> + const typename labeled_image<I>::bbox_t& + labeled_image<I>::bbox(const mln_value(I)& label) const + { + return this->data_->bboxes_[label]; + } + + +// template <typename I, typename V, typename E> +//// p_if<mln_psite(I)> +// unsigned +// extended_impl_selector<I, +// accu::pair<accu::bbox<mln_psite(I)>, +// accu::center<mln_psite(I),V> >, +// E>::domain(const mln_value(I)& label) const +// { +// const E& ima = internal::force_exact<E>(*this); +// return ((ima.hook_data_() | bbox(label)) +// | (pw::value(ima.hook_data_()) == pw::cst(label))).domain(); +// } + + + // Make routines. + + namespace make + { + + template <typename I> + mln::labeled_image<I> + labeled_image(const Image<I>& ima, const mln_value(I)& nlabels) + { + mln_precondition(exact(ima).is_valid()); + mln::labeled_image<I> tmp(exact(ima), nlabels); + return tmp; + } + + } // end of namespace mln::make + + +# endif // ! MLN_INCLUDE_ONLY + +} // end of namespace mln + + +#endif // ! MLN_CORE_IMAGE_IMORPH_LABELED_IMAGE_HH diff --git a/milena/mln/trait/ch_value.hh b/milena/mln/trait/ch_value.hh index 388520a..6e5caf1 100644 --- a/milena/mln/trait/ch_value.hh +++ b/milena/mln/trait/ch_value.hh @@ -52,6 +52,7 @@ namespace mln template <typename G, typename F> class p_vertices; template <typename P, typename V, typename G> class vertex_image; template <typename P, typename V, typename G> class edge_image; + template <typename I> class labeled_image; namespace pw { template <typename F, typename S> class image; } @@ -207,6 +208,14 @@ namespace mln typedef edge_image< P, V2, G > ret; }; + // Labeled image + template < typename I, typename V> + struct ch_value_< labeled_image< tag::image_<I> >, + V > + { + typedef mln_ch_value(I,V) ret; + }; + template < template <class, class> class M, typename T, typename S, typename V > diff --git a/milena/tests/core/image/imorph/labeled_image.cc b/milena/tests/core/image/imorph/labeled_image.cc new file mode 100644 index 0000000..e34692d --- /dev/null +++ b/milena/tests/core/image/imorph/labeled_image.cc @@ -0,0 +1,110 @@ +// Copyright (C) 2009 EPITA Research and Development Laboratory +// (LRDE) +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library 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 this library; see the file COPYING. If not, write to +// the Free Software Foundation, 51 Franklin Street, Fifth Floor, +// Boston, MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library 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 tests/core/image/imorph/labeled_image.cc +/// +/// Tests on mln::labeled_image. + + +#include <mln/core/image/image2d.hh> +#include <mln/core/image/imorph/labeled_image.hh> +#include <mln/core/routine/duplicate.hh> + +#include <mln/make/image.hh> + +#include <mln/make/box2d.hh> + +#include <mln/value/label_8.hh> + +#include <mln/accu/pair.hh> +#include <mln/accu/center.hh> +#include <mln/accu/bbox.hh> + + +static const unsigned bboxes_1[][4] = { { 1,1, 1,1 }, + { 2,0, 2,1 }, + { 0,0, 0,1 }, + { 2,2, 2,2 } }; + + +static const unsigned bboxes_2[][4] = { { 1,1, 1,1 }, + { 2,2, 2,2 }, + { 2,0, 2,1 }, + { 0,0, 0,1 } }; + + + + +namespace mln +{ + + template <typename I> + void test_image(const labeled_image<I>& lbl_i, + const unsigned bboxes[][4]) + { + unsigned j = 0; + for (unsigned i = 1; i < 5; ++i, ++j) + mln_assertion(lbl_i.bbox(i) == make::box2d(bboxes[j][0], bboxes[j][1], + bboxes[j][2], bboxes[j][3])); + } + +} // end of namespace mln + + + + +int main() +{ + using namespace mln; + using value::label_8; + + + label_8 lbl_values[][3] = { { 3, 3, 0 }, + { 0, 1, 0 }, + { 2, 2, 4 } }; + + typedef image2d<label_8> lbl_t; + lbl_t lbl = make::image(lbl_values); + + labeled_image<lbl_t> lbl_i(lbl, 4); + + + test_image(lbl_i, bboxes_1); + + fun::i2v::array<label_8> f(5); + f(0) = 0; + f(1) = 1; + f(2) = 5; + f(3) = 9; + f(4) = 2; + + lbl_i.relabel(f); + + test_image(lbl_i, bboxes_2); + +} -- 1.5.6.5