
* mln/world/k1/fill_1_from_2_faces.hh: Fix initialization of the accumulator. * mln/world/k1/immerse_with.hh, * mln/world/kn/fill_1_from_2_faces.hh: Add an overload with functions. * mln/world/k2/fill_non_primary_from_primary_2_faces.hh: Cast to a specific type. * mln/world/kn/fill_1_from_aux_2_faces.hh: Initialize the accumulator. * mln/world/kn/internal/get_background_label.hh: Use mln::geom routines. * tests/world/k1/immerse_with.cc: Improve test. * tests/world/k2/fill_non_primary_from_primary_2_faces.cc: Make use of new functions. * tests/world/kn/accu/max_interval.cc, * tests/world/kn/accu/min_interval.cc: Fix test. --- milena/ChangeLog | 26 +++++++++++++ milena/mln/world/k1/fill_1_from_2_faces.hh | 13 ++++-- milena/mln/world/k1/immerse_with.hh | 40 ++++++++++++++++++++ .../k2/fill_non_primary_from_primary_2_faces.hh | 10 +++-- milena/mln/world/kn/fill_1_from_2_faces.hh | 33 ++++++++++++++-- milena/mln/world/kn/fill_1_from_aux_2_faces.hh | 15 ++++--- .../mln/world/kn/internal/get_background_label.hh | 13 ++++-- milena/tests/world/k1/immerse_with.cc | 25 +++++++----- .../k2/fill_non_primary_from_primary_2_faces.cc | 37 ++---------------- milena/tests/world/kn/accu/max_interval.cc | 13 +++--- milena/tests/world/kn/accu/min_interval.cc | 13 +++--- 11 files changed, 158 insertions(+), 80 deletions(-) diff --git a/milena/ChangeLog b/milena/ChangeLog index 6c1f276..f93a95b 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,5 +1,31 @@ 2012-10-26 Guillaume Lazzara <z@lrde.epita.fr> + Various fixes. + + * mln/world/k1/fill_1_from_2_faces.hh: Fix initialization of the + accumulator. + + * mln/world/k1/immerse_with.hh, + * mln/world/kn/fill_1_from_2_faces.hh: Add an overload with functions. + + * mln/world/k2/fill_non_primary_from_primary_2_faces.hh: Cast to a + specific type. + + * mln/world/kn/fill_1_from_aux_2_faces.hh: Initialize the accumulator. + + * mln/world/kn/internal/get_background_label.hh: Use mln::geom + routines. + + * tests/world/k1/immerse_with.cc: Improve test. + + * tests/world/k2/fill_non_primary_from_primary_2_faces.cc: Make + use of new functions. + + * tests/world/kn/accu/max_interval.cc, + * tests/world/kn/accu/min_interval.cc: Fix test. + +2012-10-26 Guillaume Lazzara <z@lrde.epita.fr> + Handle border effects while computing 1-faces values. * mln/world/kn/internal/fill_primary_2_faces_from_input.hh: diff --git a/milena/mln/world/k1/fill_1_from_2_faces.hh b/milena/mln/world/k1/fill_1_from_2_faces.hh index b8bf9cd..3db133f 100644 --- a/milena/mln/world/k1/fill_1_from_2_faces.hh +++ b/milena/mln/world/k1/fill_1_from_2_faces.hh @@ -34,7 +34,6 @@ # include <mln/world/kn/is_1_face_vertical.hh> # include <mln/world/kn/is_1_face_horizontal.hh> - namespace mln { @@ -70,6 +69,8 @@ namespace mln void fill_1_from_2_faces(Image<I>& inout, const Function_vv2v<F>& f); /// \overload + /// This implementation do not read values outside of the image + /// domain. template <typename I, typename A> void fill_1_from_2_faces(Image<I>& inout, const Accumulator<A>& accu); @@ -89,7 +90,8 @@ namespace mln I& inout = exact(inout_); const F& f = exact(f_); - mln_piter(I) p(inout.domain()); + mln_box(I) b = inout.domain(); + mln_piter(I) p(b); for_all(p) if (kn::is_1_face_vertical(p)) inout(p) = f(inout(p + left), inout(p + right)); @@ -106,13 +108,13 @@ namespace mln mln_precondition(exact(inout_).is_valid()); I& inout = exact(inout_); - A accu(accu_); + A accu(exact(accu_)); - mln_box(I) b = inout.domain(); - mln_piter(I) p(b); + mln_piter(I) p(inout.domain()); for_all(p) if (kn::is_1_face_vertical(p)) { + accu.init(); if (inout.domain().has(p + left)) accu.take(inout(p + left)); if (inout.domain().has(p + right)) @@ -121,6 +123,7 @@ namespace mln } else if (kn::is_1_face_horizontal(p)) { + accu.init(); if (inout.domain().has(p + up)) accu.take(inout(p + up)); if (inout.domain().has(p + down)) diff --git a/milena/mln/world/k1/immerse_with.hh b/milena/mln/world/k1/immerse_with.hh index d52bbe7..aa9658b 100644 --- a/milena/mln/world/k1/immerse_with.hh +++ b/milena/mln/world/k1/immerse_with.hh @@ -67,10 +67,21 @@ namespace mln 0-faces are valued with function \p f4, considering a 4-connexity with its 1-face neighbors. + Inner-border 0 and 1 faces are initialized with \p + default_value. */ template <typename I, typename V, typename F2, typename F4> mln_ch_value(I, V) immerse_with(const Image<I>& ima, const V& new_value_type, + const V& default_value, + const Function_vv2v<F2>& f_1faces, + const Function_vvvv2v<F4>& f_0faces); + + /// \overload + /// 0 and 1 faces in the inner border are not initialized. + template <typename I, typename V, typename F2, typename F4> + mln_ch_value(I, V) + immerse_with(const Image<I>& ima, const V& new_value_type, const Function_vv2v<F2>& f_1faces, const Function_vvvv2v<F4>& f_0faces); @@ -106,6 +117,35 @@ namespace mln return output; } + template <typename I, typename V, typename F2, typename F4> + mln_ch_value(I, V) + immerse_with(const Image<I>& ima_, const V& new_value_type, + const V& default_value, + const Function_vv2v<F2>& f_1faces_, + const Function_vvvv2v<F4>& f_0faces_) + { + trace::entering("mln::world::k1::immerse_with"); + mln_precondition(exact(ima_).is_valid()); + + // FIXME: we cannot write that test because we rely on + // safe_convert. So, even though some types may not + // have conversions available by default, conversion + // may work... + //mlc_converts_to(mln_result(F2), V)::check(); + //mlc_converts_to(mln_result(F4), V)::check(); + + const I& ima = exact(ima_); + const F2& f_1faces = exact(f_1faces_); + const F4& f_0faces = exact(f_0faces_); + + mln_ch_value(I,V) output = k1::immerse(ima, new_value_type, default_value); + k1::fill_1_from_2_faces(output, f_1faces); + k1::fill_0_from_1_faces(output, f_0faces); + + trace::exiting("mln::world::k1::immerse_with"); + return output; + } + # endif // ! MLN_INCLUDE_ONLY } // end of namespace mln::world::k1 diff --git a/milena/mln/world/k2/fill_non_primary_from_primary_2_faces.hh b/milena/mln/world/k2/fill_non_primary_from_primary_2_faces.hh index 8bf7f84..0f8d71c 100644 --- a/milena/mln/world/k2/fill_non_primary_from_primary_2_faces.hh +++ b/milena/mln/world/k2/fill_non_primary_from_primary_2_faces.hh @@ -116,25 +116,27 @@ namespace mln const F2& f_intermediate = exact(f_intermediate_); const F4& f_center = exact(f_center_); + typedef mln_value(I) VI; typedef mln_argument(F2) V2; typedef mln_argument(F4) V4; - mln_piter(I) p(ima.domain()); + mln_box(I) b = ima.domain(); + mln_piter(I) p(b); for_all(p) if (is_non_primary_2_face_vertical(p)) { - ima(p) = kn::safe_cast( + ima(p) = kn::safe_cast_to<VI>( f_intermediate(kn::safe_cast_to<V2>(ima(p + 2 * left)), kn::safe_cast_to<V2>(ima(p + 2 * right)))); } else if (is_non_primary_2_face_horizontal(p)) { - ima(p) = kn::safe_cast( + ima(p) = kn::safe_cast_to<VI>( f_intermediate(kn::safe_cast_to<V2>(ima(p + 2 * up)), kn::safe_cast_to<V2>(ima(p + 2 * down)))); } else if (is_non_primary_2_face_center(p)) { - ima(p) = kn::safe_cast( + ima(p) = kn::safe_cast_to<VI>( f_center(kn::safe_cast_to<V4>(ima(p + 2 * up_left)), kn::safe_cast_to<V4>(ima(p + 2 * up_right)), kn::safe_cast_to<V4>(ima(p + 2 * down_left)), diff --git a/milena/mln/world/kn/fill_1_from_2_faces.hh b/milena/mln/world/kn/fill_1_from_2_faces.hh index 3a8b93c..0c024b3 100644 --- a/milena/mln/world/kn/fill_1_from_2_faces.hh +++ b/milena/mln/world/kn/fill_1_from_2_faces.hh @@ -34,7 +34,6 @@ # include <mln/world/kn/is_1_face_vertical.hh> # include <mln/world/kn/is_1_face_horizontal.hh> - namespace mln { @@ -69,6 +68,12 @@ namespace mln template <typename I, typename A> void fill_1_from_2_faces(Image<I>& inout, const Accumulator<A>& accu); + /// \overload + /// This implementation duplicate 2-faces in border in order to + /// be able to read values outside of the image domain. + template <typename I, typename F> + void fill_1_from_2_faces(Image<I>& inout, const Function_vv2v<F>& f); + # ifndef MLN_INCLUDE_ONLY @@ -83,11 +88,9 @@ namespace mln mln_precondition(exact(inout_).is_valid()); I& inout = exact(inout_); - (void) accu_; - A accu = A(); - mln_box(I) b = inout.domain(); - mln_piter(I) p(b); + A accu(exact(accu_)); + mln_piter(I) p(inout.domain()); for_all(p) if (kn::is_1_face_vertical(p)) { @@ -112,6 +115,26 @@ namespace mln } + template <typename I, typename F> + void fill_1_from_2_faces(Image<I>& inout_, const Function_vv2v<F>& f_) + { + trace::entering("mln::world::kn::fill_1_from_2_faces"); + + mln_precondition(exact(inout_).is_valid()); + I& inout = exact(inout_); + const F& f = exact(f_); + + mln_piter(I) p(inout.domain()); + for_all(p) + if (kn::is_1_face_vertical(p)) + inout(p) = f(inout(p + left), inout(p + right)); + else if (is_1_face_horizontal(p)) + inout(p) = f(inout(p + up), inout(p + down)); + + trace::exiting("mln::world::kn::fill_1_from_2_faces"); + } + + # endif // ! MLN_INCLUDE_ONLY } // end of namespace mln::world::kn diff --git a/milena/mln/world/kn/fill_1_from_aux_2_faces.hh b/milena/mln/world/kn/fill_1_from_aux_2_faces.hh index b9cbffe..987e3b7 100644 --- a/milena/mln/world/kn/fill_1_from_aux_2_faces.hh +++ b/milena/mln/world/kn/fill_1_from_aux_2_faces.hh @@ -35,7 +35,6 @@ # include <mln/world/kn/is_1_face_vertical.hh> # include <mln/world/kn/is_1_face_horizontal.hh> - namespace mln { @@ -52,6 +51,11 @@ namespace mln \param[in] aux A 2D image with the same domain as \p inout. \param[in,out] f A functor computing a result from two values. + Warning: \p aux borders must have been initialized with + kn::border::duplicate_2_faces or have been immersed in Kn in + order to get valid values for 1-faces located in the + inner-border. + This function use the following neighborhoods: * In case of vertical 1 faces: @@ -71,7 +75,7 @@ namespace mln */ template <typename I, typename J, typename F> void fill_1_from_aux_2_faces(Image<I>& inout, const Image<J>& aux, - Function_vv2v<F>& f); + Function_vv2v<F>& f); /// \overload template <typename I, typename J, typename A> @@ -87,7 +91,7 @@ namespace mln template <typename I, typename J, typename F> void fill_1_from_aux_2_faces(Image<I>& inout_, const Image<J>& aux_, - Function_vv2v<F>& f_) + Function_vv2v<F>& f_) { trace::entering("mln::world::kn::fill_1_from_aux_2_faces"); @@ -111,7 +115,7 @@ namespace mln template <typename I, typename J, typename A> void fill_1_from_aux_2_faces(Image<I>& inout_, const Image<J>& aux_, - const Accumulator<A>& accu_) + const Accumulator<A>& accu_) { trace::entering("mln::world::kn::fill_1_from_aux_2_faces"); @@ -120,9 +124,8 @@ namespace mln mln_precondition(exact(inout_).domain() == exact(aux_).domain()); I& inout = exact(inout_); const J& aux = exact(aux_); - (void) accu_; - A accu = A(); + A accu(exact(accu_)); mln_box(I) b = inout.domain(); mln_piter(I) p(b); for_all(p) diff --git a/milena/mln/world/kn/internal/get_background_label.hh b/milena/mln/world/kn/internal/get_background_label.hh index a993b5a..bdd2bf0 100644 --- a/milena/mln/world/kn/internal/get_background_label.hh +++ b/milena/mln/world/kn/internal/get_background_label.hh @@ -32,6 +32,10 @@ # define MLN_WORLD_KN_INTERNAL_GET_BACKGROUND_LABEL_HH # include <mln/core/concept/image.hh> +# include <mln/geom/min_row.hh> +# include <mln/geom/min_col.hh> +# include <mln/geom/max_row.hh> +# include <mln/geom/max_col.hh> namespace mln { @@ -63,12 +67,11 @@ namespace mln 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(); + min_row = geom::min_row(lab), + max_row = geom::max_row(lab), + min_col = geom::min_col(lab), + max_col = geom::max_col(lab); has_bg_label = false; for (def::coord col = min_col; col <= max_col; ++col) diff --git a/milena/tests/world/k1/immerse_with.cc b/milena/tests/world/k1/immerse_with.cc index 3b7e8fc..c6d4af7 100644 --- a/milena/tests/world/k1/immerse_with.cc +++ b/milena/tests/world/k1/immerse_with.cc @@ -29,8 +29,8 @@ #include <mln/world/k1/immerse_with.hh> #include <mln/data/compare.hh> #include <mln/border/fill.hh> -#include <mln/fun/vv2v/max.hh> -#include <mln/fun/vvvv2v/max.hh> +#include <mln/fun/vv2v/sum.hh> +#include <mln/fun/vvvv2v/sum.hh> int main() { @@ -41,22 +41,25 @@ int main() {3, 4} }; image2d<int> ima = make::image(ivals); - border::fill(ima, 0); // Make sure there is not border effect. + border::fill(ima, 0); // FIXME: to be removed when 0-face + // computation will handle borders. int fvals[][5] = { - {1, 1, 2, 2, 2}, - {1, 1, 2, 2, 2}, - {3, 3, 4, 4, 4}, - {3, 3, 4, 4, 4}, - {3, 3, 4, 4, 4} + {0, 2, 0, 4, 0}, + {2, 1, 3, 2, 4}, + {0, 4, 20, 6, 0}, + {6, 3, 7, 4, 8}, + {0, 6, 0, 8, 0} }; image2d<int> ref = make::image(fvals, point2d(-1,-1)); + { image2d<long> - immersed = world::k1::immerse_with(ima, long(), - fun::vv2v::max<long>(), - fun::vvvv2v::max<long>()); + immersed = world::k1::immerse_with(ima, long(), 0l, + fun::vv2v::sum<long>(), + fun::vvvv2v::sum<long>()); + mln_assertion(immersed == ref); } diff --git a/milena/tests/world/k2/fill_non_primary_from_primary_2_faces.cc b/milena/tests/world/k2/fill_non_primary_from_primary_2_faces.cc index c83a613..7a17f80 100644 --- a/milena/tests/world/k2/fill_non_primary_from_primary_2_faces.cc +++ b/milena/tests/world/k2/fill_non_primary_from_primary_2_faces.cc @@ -26,41 +26,12 @@ /// \file #include <mln/core/image/image2d.hh> -#include <mln/make/box2d.hh> #include <mln/data/compare.hh> #include <mln/accu/math/sum.hh> +#include <mln/fun/vv2v/sum.hh> +#include <mln/fun/vvvv2v/sum.hh> #include <mln/world/k2/fill_non_primary_from_primary_2_faces.hh> -namespace mln -{ - - struct sum4_t : Function_vvvv2v<sum4_t> - { - typedef int argument; - typedef int result; - - int operator()(const int& v1, const int& v2, const int& v3, const int& v4) const - { - return v1 + v2 + v3 + v4; - } - - }; - - struct sum2_t : Function_vv2v<sum2_t> - { - typedef int argument; - typedef int result; - - int operator()(const int& v1, const int& v2) const - { - return v1 + v2; - } - - }; - -} - - int main() { @@ -98,7 +69,9 @@ int main() // Overload with function { image2d<int> ima = make::image(vals, point2d(-1,-1)); - world::k2::fill_non_primary_from_primary_2_faces(ima, sum2_t(), sum4_t()); + fun::vv2v::sum<int> f2; + fun::vvvv2v::sum<int> f4; + world::k2::fill_non_primary_from_primary_2_faces(ima, f2, f4); mln_assertion(ref == ima); } diff --git a/milena/tests/world/kn/accu/max_interval.cc b/milena/tests/world/kn/accu/max_interval.cc index 9686ad7..304266a 100644 --- a/milena/tests/world/kn/accu/max_interval.cc +++ b/milena/tests/world/kn/accu/max_interval.cc @@ -40,12 +40,6 @@ void doit(const mln::value::interval<T>& inter) } { - M m; - m.init(); - mln_assertion(m.to_result() == mln_min(T)); - } - - { M m(inter); m.init(); m.take(6); @@ -105,4 +99,11 @@ int main() doit(inter); } + // Checking default return value. + { + mln::world::kn::accu::max_interval<int> m; + m.init(); + mln_assertion(m.to_result() == mln_min(int)); + } + } diff --git a/milena/tests/world/kn/accu/min_interval.cc b/milena/tests/world/kn/accu/min_interval.cc index 7b5a0e2..84c5bd5 100644 --- a/milena/tests/world/kn/accu/min_interval.cc +++ b/milena/tests/world/kn/accu/min_interval.cc @@ -40,12 +40,6 @@ void doit(const mln::value::interval<T>& inter) } { - M m; - m.init(); - mln_assertion(m.to_result() == mln_max(T)); - } - - { M m(inter); m.init(); m.take(6); @@ -105,4 +99,11 @@ int main() doit(inter); } + // Checking default return value. + { + mln::world::kn::accu::min_interval<int> m; + m.init(); + mln_assertion(m.to_result() == mln_max(int)); + } + } -- 1.7.2.5