
* mln/world/kn/holes.hh, * mln/world/kn/internal/get_background_label.hh, * mln/world/kn/saturate.hh, * tests/world/kn/holes.cc, * tests/world/kn/saturate.cc: New. * tests/world/kn/Makefile.am: New targets. --- milena/ChangeLog | 12 ++ ...{fill_0_1_faces_internal_border.hh => holes.hh} | 68 ++++++----- .../mln/world/kn/internal/get_background_label.hh | 122 ++++++++++++++++++++ ...ll_0_1_faces_internal_border.hh => saturate.hh} | 70 ++++++----- milena/tests/world/kn/Makefile.am | 4 + .../{k1/fill_1_from_2_faces.cc => kn/holes.cc} | 88 +++++++-------- .../{k1/fill_1_from_2_faces.cc => kn/saturate.cc} | 89 +++++++-------- 7 files changed, 295 insertions(+), 158 deletions(-) copy milena/mln/world/kn/{fill_0_1_faces_internal_border.hh => holes.hh} (58%) create mode 100644 milena/mln/world/kn/internal/get_background_label.hh copy milena/mln/world/kn/{fill_0_1_faces_internal_border.hh => saturate.hh} (57%) copy milena/tests/world/{k1/fill_1_from_2_faces.cc => kn/holes.cc} (59%) copy milena/tests/world/{k1/fill_1_from_2_faces.cc => kn/saturate.cc} (58%) diff --git a/milena/ChangeLog b/milena/ChangeLog index cc55293..45480d5 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,3 +1,15 @@ +2012-10-26 Guillaume Lazzara <z@lrde.epita.fr> + + Add kn::holes() and kn::saturate(). + + * mln/world/kn/holes.hh, + * mln/world/kn/internal/get_background_label.hh, + * mln/world/kn/saturate.hh, + * tests/world/kn/holes.cc, + * tests/world/kn/saturate.cc: New. + + * tests/world/kn/Makefile.am: New targets. + 2012-10-25 Guillaume Lazzara <z@lrde.epita.fr> Fix preconditions. diff --git a/milena/mln/world/kn/fill_0_1_faces_internal_border.hh b/milena/mln/world/kn/holes.hh similarity index 58% copy from milena/mln/world/kn/fill_0_1_faces_internal_border.hh copy to milena/mln/world/kn/holes.hh index 915a69a..dad04cd 100644 --- a/milena/mln/world/kn/fill_0_1_faces_internal_border.hh +++ b/milena/mln/world/kn/holes.hh @@ -25,12 +25,17 @@ /// \file /// -/// \brief Fill 0 and 1 faces border with a value in a KN 2D image. +/// \brief -#ifndef MLN_WORLD_KN_FILL_0_1_FACES_INTERNAL_BORDER_HH -# define MLN_WORLD_KN_FILL_0_1_FACES_INTERNAL_BORDER_HH +#ifndef MLN_WORLD_KN_SATURATE_HH +# define MLN_WORLD_KN_SATURATE_HH -# include <mln/inner_border/fill.hh> +# include <mln/core/image/image2d.hh> +# include <mln/core/alias/neighb2d.hh> +# include <mln/labeling/background.hh> +# include <mln/data/fill.hh> +# include <mln/pw/all.hh> +# include <mln/world/kn/internal/get_background_label.hh> namespace mln @@ -42,44 +47,45 @@ namespace mln namespace kn { - /*! \brief Fill 0 and 1 faces border with a value in a KN 2D image. - \param[in,out] inout A 2D image immersed in KN. - \param[in] v The border value. - - Example with \p v=1: - - . - . - . 1 1 1 1 1 - | o | o | 1 o | o 1 - . - . - . -> 1 - . - 1 - | o | o | 1 o | o 1 - . - . - . 1 1 1 1 1 - - */ template <typename I> - void fill_0_1_faces_internal_border(Image<I>& inout, - const mln_value(I)& v); - + mln_concrete(I) + holes(const Image<I>& input); # ifndef MLN_INCLUDE_ONLY + template <typename I> + mln_concrete(I) + holes(const Image<I>& input_) + { + trace::entering("mln::world::kn::holes"); + mlc_equal(mln_trait_image_kind(I), + mln::trait::image::kind::binary)::check(); + mln_precondition(exact(input_).is_valid()); - // Facade + const I& input = exact(input_); + unsigned n_labels; + mln_ch_value(I,unsigned) + lab = labeling::background(input, c4(), n_labels); - template <typename I> - void fill_0_1_faces_internal_border(Image<I>& inout_, - const mln_value(I)& v) - { - trace::entering("mln::world::kn::fill_0_1_faces_internal_border"); + bool has_bg_label; + unsigned bg = internal::get_background_label(lab, has_bg_label); + + mln_concrete(I) output(input.domain()); - mln_precondition(exact(inout_).is_valid()); - I& inout = exact(inout_); + if (! has_bg_label) + { + data::fill(output, false); + return output; + } - inner_border::fill(inout, v); + data::fill(output, pw::value(lab) != pw::cst(bg) + && pw::value(lab) != pw::cst(literal::zero)); - trace::exiting("mln::world::kn::fill_0_1_faces_internal_border"); + trace::exiting("mln::world::kn::holes"); + return output; } # endif // ! MLN_INCLUDE_ONLY @@ -90,4 +96,4 @@ namespace mln } // end of namespace mln -#endif // ! MLN_WORLD_KN_FILL_0_1_FACES_INTERNAL_BORDER_HH +#endif // ! MLN_WORLD_KN_SATURATE_HH diff --git a/milena/mln/world/kn/internal/get_background_label.hh b/milena/mln/world/kn/internal/get_background_label.hh new file mode 100644 index 0000000..a993b5a --- /dev/null +++ b/milena/mln/world/kn/internal/get_background_label.hh @@ -0,0 +1,122 @@ +// Copyright (C) 2012 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 Look for background label in the borders of a labeled +/// image. + +#ifndef MLN_WORLD_KN_INTERNAL_GET_BACKGROUND_LABEL_HH +# define MLN_WORLD_KN_INTERNAL_GET_BACKGROUND_LABEL_HH + +# include <mln/core/concept/image.hh> + +namespace mln +{ + + namespace world + { + + namespace kn + { + + namespace internal + { + + /// \brief Look for background label in the borders of a + /// labeled image. + template <typename I> + mln_value(I) + get_background_label(const Image<I>& lab, bool& has_bg_label); + + +# ifndef MLN_INCLUDE_ONLY + + template <typename I> + mln_value(I) + get_background_label(const Image<I>& lab_, bool& has_bg_label) + { + trace::entering("mln::world::kn::internal::get_background_label"); + mln_precondition(exact(lab_).is_valid()); + + const I& lab = exact(lab_); + + mln_box(I) dom = lab.domain(); + def::coord + min_row = dom.pmin().row(), + max_row = dom.pmax().row(), + min_col = dom.pmin().col(), + max_col = dom.pmax().col(); + + has_bg_label = false; + for (def::coord col = min_col; col <= max_col; ++col) + { + // first row + if (lab.at_(min_row, col) != 0) + { + has_bg_label = true; + return lab.at_(min_row, col); + } + // last row + if (lab.at_(max_row, col) != 0) + { + has_bg_label = true; + return lab.at_(max_row, col); + } + } + if (! has_bg_label) + { + for (def::coord row = min_row; row <= max_row; ++row) + { + // first col + if (lab.at_(row, min_col) != 0) + { + has_bg_label = true; + return lab.at_(row, min_col); + } + // last col + if (lab.at_(row, max_col) != 0) + { + has_bg_label = true; + return lab.at_(row, max_col); + } + } + } + + trace::exiting("mln::world::kn::internal::get_background_label"); + return 0; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::world::kn::internal + + } // end of namespace mln::world::kn + + } // end of namespace mln::world + +} // end of namespace mln + +#endif // ! MLN_WORLD_KN_INTERNAL_GET_BACKGROUND_LABEL_HH diff --git a/milena/mln/world/kn/fill_0_1_faces_internal_border.hh b/milena/mln/world/kn/saturate.hh similarity index 57% copy from milena/mln/world/kn/fill_0_1_faces_internal_border.hh copy to milena/mln/world/kn/saturate.hh index 915a69a..3677333 100644 --- a/milena/mln/world/kn/fill_0_1_faces_internal_border.hh +++ b/milena/mln/world/kn/saturate.hh @@ -25,12 +25,17 @@ /// \file /// -/// \brief Fill 0 and 1 faces border with a value in a KN 2D image. +/// \brief Saturate a cut of an image. -#ifndef MLN_WORLD_KN_FILL_0_1_FACES_INTERNAL_BORDER_HH -# define MLN_WORLD_KN_FILL_0_1_FACES_INTERNAL_BORDER_HH +#ifndef MLN_WORLD_KN_SATURATE_HH +# define MLN_WORLD_KN_SATURATE_HH -# include <mln/inner_border/fill.hh> +# include <mln/core/image/image2d.hh> +# include <mln/core/alias/neighb2d.hh> +# include <mln/labeling/background.hh> +# include <mln/data/fill.hh> +# include <mln/pw/all.hh> +# include <mln/world/kn/internal/get_background_label.hh> namespace mln @@ -42,44 +47,45 @@ namespace mln namespace kn { - /*! \brief Fill 0 and 1 faces border with a value in a KN 2D image. - - \param[in,out] inout A 2D image immersed in KN. - \param[in] v The border value. - - Example with \p v=1: - - . - . - . 1 1 1 1 1 - | o | o | 1 o | o 1 - . - . - . -> 1 - . - 1 - | o | o | 1 o | o 1 - . - . - . 1 1 1 1 1 - - */ + /// \brief Saturate a cut of an image. template <typename I> - void fill_0_1_faces_internal_border(Image<I>& inout, - const mln_value(I)& v); - + mln_concrete(I) + saturate(const Image<I>& input); # ifndef MLN_INCLUDE_ONLY + template <typename I> + mln_concrete(I) + saturate(const Image<I>& input_) + { + trace::entering("mln::world::kn::saturate"); + mlc_equal(mln_trait_image_kind(I), + mln::trait::image::kind::binary)::check(); + mln_precondition(exact(input_).is_valid()); - // Facade + const I& input = exact(input_); + unsigned n_labels; + mln_ch_value(I,unsigned) + lab = labeling::background(input, c4(), n_labels); - template <typename I> - void fill_0_1_faces_internal_border(Image<I>& inout_, - const mln_value(I)& v) - { - trace::entering("mln::world::kn::fill_0_1_faces_internal_border"); + bool has_bg_label; + unsigned bg = internal::get_background_label(lab, has_bg_label); + + mln_concrete(I) output; + initialize(output, input); - mln_precondition(exact(inout_).is_valid()); - I& inout = exact(inout_); + if (! has_bg_label) + { + data::fill(output, true); + return output; + } - inner_border::fill(inout, v); + data::fill(output, pw::value(lab) != pw::cst(bg)); - trace::exiting("mln::world::kn::fill_0_1_faces_internal_border"); + trace::exiting("mln::world::kn::saturate"); + return output; } # endif // ! MLN_INCLUDE_ONLY @@ -90,4 +96,4 @@ namespace mln } // end of namespace mln -#endif // ! MLN_WORLD_KN_FILL_0_1_FACES_INTERNAL_BORDER_HH +#endif // ! MLN_WORLD_KN_SATURATE_HH diff --git a/milena/tests/world/kn/Makefile.am b/milena/tests/world/kn/Makefile.am index 866ae00..2a89e48a 100644 --- a/milena/tests/world/kn/Makefile.am +++ b/milena/tests/world/kn/Makefile.am @@ -23,6 +23,7 @@ check_PROGRAMS = \ fill_1_from_2_faces \ fill_1_from_aux_2_faces \ fill_2_from_1_faces \ + holes \ immerse \ immerse_with_inner_border \ is_0_face \ @@ -32,6 +33,7 @@ check_PROGRAMS = \ is_1_face_horizontal \ is_2_face \ level \ + saturate \ un_immerse fill_0_1_faces_internal_border_SOURCES = fill_0_1_faces_internal_border.cc @@ -40,6 +42,7 @@ fill_0_from_2_faces_SOURCES = fill_0_from_2_faces.cc fill_1_from_2_faces_SOURCES = fill_1_from_2_faces.cc fill_1_from_aux_2_faces_SOURCES = fill_1_from_aux_2_faces.cc fill_2_from_1_faces_SOURCES = fill_2_from_1_faces.cc +holes_SOURCES = holes.cc immerse_SOURCES = immerse.cc immerse_with_inner_border_SOURCES = immerse_with_inner_border.cc is_0_face_SOURCES = is_0_face.cc @@ -49,6 +52,7 @@ is_1_face_vertical_SOURCES = is_1_face_vertical.cc is_1_face_horizontal_SOURCES = is_1_face_horizontal.cc is_2_face_SOURCES = is_2_face.cc level_SOURCES = level.cc +saturate_SOURCES = saturate.cc un_immerse_SOURCES = un_immerse.cc diff --git a/milena/tests/world/k1/fill_1_from_2_faces.cc b/milena/tests/world/kn/holes.cc similarity index 59% copy from milena/tests/world/k1/fill_1_from_2_faces.cc copy to milena/tests/world/kn/holes.cc index 4045674..9bba24f 100644 --- a/milena/tests/world/k1/fill_1_from_2_faces.cc +++ b/milena/tests/world/kn/holes.cc @@ -26,61 +26,55 @@ /// \file #include <mln/core/image/image2d.hh> -#include <mln/make/box2d.hh> +#include <mln/world/kn/holes.hh> #include <mln/data/compare.hh> -#include <mln/accu/math/sum.hh> -#include <mln/world/k1/fill_1_from_2_faces.hh> -#include <mln/border/fill.hh> - - -namespace mln -{ - - struct sum_t : Function_vv2v<sum_t> - { - typedef int result; - - int operator()(const int& v1, const int& v2) const - { - return v1 + v2; - } - - }; - -} - - int main() { using namespace mln; - int refvals[5][5] = { - {1, 3, 1, 3, 1}, - {3, 3, 6, 3, 3}, - {1, 6, 1, 6, 1}, - {3, 3, 6, 3, 3}, - {1, 3, 1, 3, 1} - }; - image2d<int> ref = make::image(refvals, point2d(-1, -1)); - - int vals[5][5] = { - {1, 0, 1, 0, 1 }, - {0, 3, 0, 3, 0 }, - {1, 0, 1, 0, 1 }, - {0, 3, 0, 3, 0 }, - {1, 0, 1, 0, 1 } - }; - image2d<int> imakn = make::image(vals, point2d(-1, -1)); + { + bool vals[][5] = { + {0, 0, 1, 1, 1}, + {1, 0, 1, 0, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1} + }; + image2d<bool> ima = make::image(vals); + bool refvals[][5] = { + {0, 0, 0, 0, 0}, + {0, 0, 0, 1, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0} + }; + image2d<bool> ref = make::image(refvals); + + image2d<bool> out = world::kn::holes(ima); + mln_assertion(out == ref); + } - /// Make sure the border is set to 0 to get deterministic results. - border::fill(imakn, 0); - // Overload with function { - sum_t f; - world::k1::fill_1_from_2_faces(imakn, f); - mln_assertion(ref == imakn); + bool vals[][5] = { + {1, 1, 1, 1, 1}, + {1, 0, 1, 0, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1} + }; + image2d<bool> ima = make::image(vals); + bool refvals[][5] = { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0} + }; + image2d<bool> ref = make::image(refvals); + + image2d<bool> out = world::kn::holes(ima); + mln_assertion(out == ref); } - } diff --git a/milena/tests/world/k1/fill_1_from_2_faces.cc b/milena/tests/world/kn/saturate.cc similarity index 58% copy from milena/tests/world/k1/fill_1_from_2_faces.cc copy to milena/tests/world/kn/saturate.cc index 4045674..33b0f79 100644 --- a/milena/tests/world/k1/fill_1_from_2_faces.cc +++ b/milena/tests/world/kn/saturate.cc @@ -26,61 +26,54 @@ /// \file #include <mln/core/image/image2d.hh> -#include <mln/make/box2d.hh> +#include <mln/world/kn/saturate.hh> #include <mln/data/compare.hh> -#include <mln/accu/math/sum.hh> -#include <mln/world/k1/fill_1_from_2_faces.hh> -#include <mln/border/fill.hh> - - -namespace mln -{ - - struct sum_t : Function_vv2v<sum_t> - { - typedef int result; - - int operator()(const int& v1, const int& v2) const - { - return v1 + v2; - } - - }; - -} - - int main() { using namespace mln; - int refvals[5][5] = { - {1, 3, 1, 3, 1}, - {3, 3, 6, 3, 3}, - {1, 6, 1, 6, 1}, - {3, 3, 6, 3, 3}, - {1, 3, 1, 3, 1} - }; - image2d<int> ref = make::image(refvals, point2d(-1, -1)); - - int vals[5][5] = { - {1, 0, 1, 0, 1 }, - {0, 3, 0, 3, 0 }, - {1, 0, 1, 0, 1 }, - {0, 3, 0, 3, 0 }, - {1, 0, 1, 0, 1 } - }; - image2d<int> imakn = make::image(vals, point2d(-1, -1)); - - /// Make sure the border is set to 0 to get deterministic results. - border::fill(imakn, 0); - - // Overload with function { - sum_t f; - world::k1::fill_1_from_2_faces(imakn, f); - mln_assertion(ref == imakn); + bool vals[][5] = { + {0, 0, 1, 1, 1}, + {1, 0, 1, 0, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1} + }; + image2d<bool> ima = make::image(vals); + bool refvals[][5] = { + {0, 0, 1, 1, 1}, + {1, 0, 1, 1, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1} + }; + image2d<bool> ref = make::image(refvals); + + image2d<bool> out = world::kn::saturate(ima); + mln_assertion(out == ref); } + { + bool vals[][5] = { + {1, 1, 1, 1, 1}, + {1, 0, 1, 0, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1} + }; + image2d<bool> ima = make::image(vals); + bool refvals[][5] = { + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1} + }; + image2d<bool> ref = make::image(refvals); + + image2d<bool> out = world::kn::saturate(ima); + mln_assertion(out == ref); + } } -- 1.7.2.5