
--- milena/apps/bench/Makefile.am | 15 +- milena/{mln/accu/pair.hh => apps/bench/and_not.hh} | 74 +++-- milena/apps/bench/gradient-spe-lena.cc | 353 ++++++++++++++++++++ milena/{mln/accu/pair.hh => apps/bench/minus.hh} | 73 +++-- 4 files changed, 450 insertions(+), 65 deletions(-) copy milena/{mln/accu/pair.hh => apps/bench/and_not.hh} (74%) create mode 100644 milena/apps/bench/gradient-spe-lena.cc copy milena/{mln/accu/pair.hh => apps/bench/minus.hh} (74%) diff --git a/milena/apps/bench/Makefile.am b/milena/apps/bench/Makefile.am index 707f457..27a368e 100644 --- a/milena/apps/bench/Makefile.am +++ b/milena/apps/bench/Makefile.am @@ -21,9 +21,20 @@ APPS_CXXFLAGS = @APPS_CXXFLAGS@ AM_CXXFLAGS = $(APPS_CXXFLAGS) noinst_PROGRAMS = \ - gradient-lena + gradient-lena \ + gradient-spe-lena + +EXTRA_DIST = \ + and_not.hh \ + minus.hh gradient_lena_SOURCES = gradient-lena.cc +gradient_spe_lena_SOURCES = gradient-spe-lena.cc MOSTLYCLEANFILES = \ - gradient-lena-out.pgm + gradient-lena-out.pgm \ + gradient-spe-lena-out-0.pgm \ + gradient-spe-lena-out-1.pgm \ + gradient-spe-lena-out-2.pgm \ + gradient-spe-lena-out-3.pgm \ + gradient-spe-lena-out-4.pgm diff --git a/milena/mln/accu/pair.hh b/milena/apps/bench/and_not.hh similarity index 74% copy from milena/mln/accu/pair.hh copy to milena/apps/bench/and_not.hh index 11f4dc6..c3ddf36 100644 --- a/milena/mln/accu/pair.hh +++ b/milena/apps/bench/and_not.hh @@ -1,4 +1,4 @@ -// Copyright (C) 2007, 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) // // This file is part of Olena. // @@ -23,17 +23,17 @@ // exception does not however invalidate any other reasons why the // executable file might be covered by the GNU General Public License. -#ifndef MLN_ACCU_PAIR_HH -# define MLN_ACCU_PAIR_HH +#ifndef MLN_ACCU_AND_NOT_HH +# define MLN_ACCU_AND_NOT_HH /// \file /// -/// Define a pair of accumulators. - -# include <utility> +/// Define a logical "and not" of accumulators. # include <mln/core/concept/meta_accumulator.hh> +# include <mln/logical/and_not.hh> + # include <mln/accu/internal/base.hh> # include <mln/metal/is_a.hh> # include <mln/metal/unqualif.hh> @@ -46,7 +46,7 @@ namespace mln { - /// \brief Generic pair of accumulators. + /// \brief Logical "and not" of accumulators. /// /// The parameter \c T is the type of values. /// @@ -55,29 +55,30 @@ namespace mln /// \ingroup modaccumulti // template <typename A1, typename A2, typename T = mln_argument(A1)> - struct pair : public mln::accu::internal::base< std::pair<mln_result(A1), mln_result(A2)>, - pair<A1,A2,T> > + struct and_not + : public mln::accu::internal::base< bool, and_not<A1,A2,T> > { typedef T argument; typedef mln_result(A1) result_1; typedef mln_result(A2) result_2; - pair(); + and_not(); // FIXME: not implemented. Do we want it? -// pair(const A1& a1, const A2& a2); +// and_not(const A1& a1, const A2& a2); /// Manipulators. /// \{ void init(); void take_as_init_(const argument& t); void take(const argument& t); - void take(const pair<A1,A2,T>& other); + void take(const and_not<A1,A2,T>& other); + void untake(const argument& t); /// \} /// Get the value of the accumulator. /// \{ - std::pair<mln_result(A1), mln_result(A2)> to_result() const; + bool to_result() const; void get_result(result_1& r1, result_2& r2) const; /// \} @@ -105,16 +106,16 @@ namespace mln namespace meta { - /// Meta accumulator for pair. + /// Meta accumulator for and_not. template <typename A1, typename A2> - struct pair : public Meta_Accumulator< pair<A1,A2> > + struct and_not : public Meta_Accumulator< and_not<A1,A2> > { template <typename T> struct with { typedef mln_accu_with(A1, T) A1_T; typedef mln_accu_with(A2, T) A2_T; - typedef accu::pair<A1_T, A2_T, T> ret; + typedef accu::and_not<A1_T, A2_T, T> ret; }; }; @@ -125,7 +126,7 @@ namespace mln template <typename A1, typename A2, typename T> inline - pair<A1,A2,T>::pair() + and_not<A1,A2,T>::and_not() { init(); } @@ -133,7 +134,7 @@ namespace mln template <typename A1, typename A2, typename T> inline void - pair<A1,A2,T>::init() + and_not<A1,A2,T>::init() { a1_.init(); a2_.init(); @@ -142,7 +143,7 @@ namespace mln template <typename A1, typename A2, typename T> inline void - pair<A1,A2,T>::take_as_init_(const argument& t) + and_not<A1,A2,T>::take_as_init_(const argument& t) { a1_.take_as_init_(t); a2_.take_as_init_(t); @@ -151,7 +152,7 @@ namespace mln template <typename A1, typename A2, typename T> inline void - pair<A1,A2,T>::take(const argument& t) + and_not<A1,A2,T>::take(const argument& t) { a1_.take(t); a2_.take(t); @@ -160,7 +161,7 @@ namespace mln template <typename A1, typename A2, typename T> inline void - pair<A1,A2,T>::take(const pair<A1,A2,T>& other) + and_not<A1,A2,T>::take(const and_not<A1,A2,T>& other) { a1_.take(other.a1_); a2_.take(other.a2_); @@ -168,18 +169,27 @@ namespace mln template <typename A1, typename A2, typename T> inline - std::pair<mln_result(A1), mln_result(A2)> - pair<A1,A2,T>::to_result() const + void + and_not<A1,A2,T>::untake(const argument& t) + { + a1_.untake(t); + a2_.untake(t); + } + + template <typename A1, typename A2, typename T> + inline + bool + and_not<A1,A2,T>::to_result() const { - std::pair<mln_result(A1), mln_result(A2)> tmp(a1_.to_result(), a2_.to_result()); + bool tmp = a1_.to_result() && ! a2_.to_result(); return tmp; } template <typename A1, typename A2, typename T> inline void - pair<A1,A2,T>::get_result(result_1& r1, - result_2& r2) const + and_not<A1,A2,T>::get_result(result_1& r1, + result_2& r2) const { r1 = a1_.to_result(); r2 = a2_.to_result(); @@ -188,7 +198,7 @@ namespace mln template <typename A1, typename A2, typename T> inline mln_result(A1) - pair<A1,A2,T>::first() const + and_not<A1,A2,T>::first() const { return a1_.to_result(); } @@ -196,7 +206,7 @@ namespace mln template <typename A1, typename A2, typename T> inline mln_result(A2) - pair<A1,A2,T>::second() const + and_not<A1,A2,T>::second() const { return a2_.to_result(); } @@ -206,7 +216,7 @@ namespace mln template <typename A1, typename A2, typename T> inline A1 - pair<A1,A2,T>::first_accu() const + and_not<A1,A2,T>::first_accu() const { return a1_; } @@ -214,7 +224,7 @@ namespace mln template <typename A1, typename A2, typename T> inline A2 - pair<A1,A2,T>::second_accu() const + and_not<A1,A2,T>::second_accu() const { return a2_; } @@ -223,7 +233,7 @@ namespace mln template <typename A1, typename A2, typename T> inline bool - pair<A1,A2,T>::is_valid() const + and_not<A1,A2,T>::is_valid() const { return a1_.is_valid() && a2_.is_valid(); } @@ -235,4 +245,4 @@ namespace mln } // end of namespace mln -#endif // ! MLN_ACCU_PAIR_HH +#endif // ! MLN_ACCU_AND_NOT_HH diff --git a/milena/apps/bench/gradient-spe-lena.cc b/milena/apps/bench/gradient-spe-lena.cc new file mode 100644 index 0000000..70dd58b --- /dev/null +++ b/milena/apps/bench/gradient-spe-lena.cc @@ -0,0 +1,353 @@ +// Copyright (C) 2007, 2008, 2009, 2010 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. + +#include <iostream> + +#include <mln/core/image/image2d.hh> +#include <mln/core/alias/window2d.hh> + +#include <mln/io/pgm/load.hh> +#include <mln/io/pgm/save.hh> + +#include <mln/value/int_u8.hh> + +#include <mln/morpho/includes.hh> +#include <mln/morpho/general.hh> + +#include <mln/accu/logic/lor.hh> +#include <mln/accu/logic/land.hh> +#include <mln/accu/logic/land_basic.hh> +#include <mln/accu/logic/lor_basic.hh> +#include <mln/accu/stat/max.hh> +#include <mln/accu/stat/min.hh> +#include <mln/accu/stat/max_h.hh> +#include <mln/accu/stat/min_h.hh> + +#include "apps/bench/minus.hh" +#include "apps/bench/and_not.hh" + +#include <mln/util/timer.hh> + +#include "apps/data.hh" + +// With hard-coded/inlined 4-c structuring element. +template <typename I> +mln_concrete(I) +gradient_spe_0(const mln::Image<I>& ima_) +{ + using namespace mln; + typedef mln_value(I) V; + typedef mln_psite(I) P; + + const I& ima = exact(ima_); + + mln_concrete(I) result; + initialize(result, ima); + + mln_piter(I) p(result.domain()); + for_all(p) + { + // FIXME: Use one or two accu(s) instead? + V sup = ima(p); + V inf = ima(p); + { + P q(p.row() - 1, p.col()); + if (ima.has(q)) + { + if (ima(q) > sup) sup = ima(q); + if (ima(q) < inf) inf = ima(q); + } + } + { + P q(p.row(), p.col() - 1); + if (ima.has(q)) + { + if (ima(q) > sup) sup = ima(q); + if (ima(q) < inf) inf = ima(q); + } + } + { + P q(p.row(), p.col() + 1); + if (ima.has(q)) + { + if (ima(q) > sup) sup = ima(q); + if (ima(q) < inf) inf = ima(q); + } + } + { + P q(p.row() + 1, p.col()); + if (ima.has(q)) + { + if (ima(q) > sup) sup = ima(q); + if (ima(q) < inf) inf = ima(q); + } + } + result(p) = sup - inf; + } + return result; +} + +template <typename I, typename W> +mln_concrete(I) +gradient_spe_1(const mln::Image<I>& ima_, const mln::Window<W>& win_) +{ + using namespace mln; + typedef mln_value(I) V; + + const I& ima = exact(ima_); + const W& win = exact(win_); + + mln_concrete(I) result; + initialize(result, ima); + + mln_piter(I) p(result.domain()); + mln_qiter(W) q(win, p); + for_all(p) + { + // FIXME: Use one or two accu(s) instead? + V sup = mln_min(V); + V inf = mln_max(V); + for_all(q) + if (ima.has(q)) + { + if (ima(q) > sup) + sup = ima(q); + if (ima(q) < inf) + inf = ima(q); + } + result(p) = sup - inf; + } + return result; +} + +template <typename I, typename W> +mln_concrete(I) +gradient_spe_2(const mln::Image<I>& ima_, const mln::Window<W>& win_) +{ + using namespace mln; + typedef mln_value(I) V; + + const I& ima = exact(ima_); + const W& win = exact(win_); + + typedef mln_concrete(I) O; + O result; + initialize(result, ima); + + mln_pixter(const I) pi(ima); + mln_pixter(O) po(result); + // FIXME: The arguments of a qixter (p, win) are swapped compared to + // a qiter (win, p). Make this uniform? + mln_qixter(const I, W) q(pi, win); + for_all_2(pi, po) + { + // FIXME: Use one or two accu(s) instead? + V sup = mln_min(V); + V inf = mln_max(V); + for_all(q) + { + if (q.val() > sup) + sup = q.val(); + if (q.val() < inf) + inf = q.val(); + } + po.val() = sup - inf; + } + return result; +} + +template <typename I, typename W> +mln_concrete(I) +gradient_spe_3(const mln::Image<I>& ima_, const mln::Window<W>& win_) +{ + using namespace mln; + typedef mln_value(I) V; + + const I& ima = exact(ima_); + const W& win = exact(win_); + + typedef mln_concrete(I) O; + O result; + initialize(result, ima); + + mln_pixter(const I) pi(ima); + mln_pixter(O) po(result); + // FIXME: The arguments of a qixter (p, win) are swapped compared to + // a qiter (win, p). Make this uniform? + mln_qixter(const I, W) q(pi, win); + for_all_2(pi, po) + { + // FIXME: Use one or two accu(s) instead? + V sup = mln_min(V); + V inf = mln_max(V); + bool global_sup_reached_p = false; + bool global_inf_reached_p = false; + for_all(q) + { + if (!global_sup_reached_p && q.val() > sup) + { + sup = q.val(); + if (sup == mln_max(V)) + { + // Global sup reached. + if (global_inf_reached_p) + break; + global_sup_reached_p = true; + } + } + if (!global_inf_reached_p && q.val() < inf) + { + inf = q.val(); + if (inf == mln_min(V)) + { + // Global inf reached. + if (global_sup_reached_p) + break; + global_inf_reached_p = true; + } + } + } + po.val() = sup - inf; + } + return result; +} + + +// FIXME: Unify accumulators and_not and minus? + +namespace mln +{ + namespace accu + { + namespace meta + { + /// Accumulator for morphological gradient on sets. + typedef and_not<meta::logic::lor_basic, meta::logic::land_basic> lor_basic_minus_land_basic; + /// Accumulator for morphological gradient on functions. + typedef minus<meta::stat::max, meta::stat::min> max_minus_min; + + /// Incremental accumulator for morphological gradient on sets. + typedef meta::and_not<meta::logic::lor, meta::logic::land> lor_minus_land; + /// Incremental accumulator for morphological gradient on functions. + typedef meta::minus<meta::stat::max_h, meta::stat::min_h> max_h_minus_min_h; + } // End of namespace mln::accu::meta. + + } // End of namespace mln::accu. + + +namespace morpho +{ + + struct gradient_op + { + template <typename I> + mln_morpho_select_accu(I, lor_basic_minus_land_basic, max_minus_min) + accu(const Image<I>&) const + { + mln_morpho_select_accu(I, lor_basic_minus_land_basic, max_minus_min) tmp; + return tmp; + } + + template <typename I> + mln_morpho_select_accu(I, lor_minus_land, max_h_minus_min_h) + accu_incr(const Image<I>&) const + { + mln_morpho_select_accu(I, lor_minus_land, max_h_minus_min_h) tmp; + return tmp; + } + + // FIXME: Which neutral should we choose? + template <typename I> + mln_value(I) neutral(const Image<I>&) const + { + return internal::neutral<I>::infimum(); + } + }; + + template <typename I, typename W> + inline + mln_concrete(I) + gradient_spe_4(const Image<I>& input, const Window<W>& win) + { + trace::entering("morpho::dilation"); + mln_precondition(exact(input).is_valid()); + mln_precondition(! exact(win).is_empty()); + + mln_concrete(I) output = general(gradient_op(), input, win); + + mln_postcondition(test::positive(output)); + trace::exiting("morpho::dilation"); + return output; + } + +} // End of namespace mln::morpho. + +} // End of namespace mln. + + + +int main() +{ + using namespace mln; + using value::int_u8; + + border::thickness = 1; + image2d<int_u8> lena; + io::pgm::load(lena, MLN_IMG_DIR "/lena.pgm"); + + image2d<int_u8> g; + util::timer t; + + t.start(); + g = gradient_spe_0(lena); + t.stop(); + std::cout << t.read() << std::endl; + io::pgm::save(g, "gradient-spe-lena-out-0.pgm"); + + t.restart(); + g = gradient_spe_1(lena, win_c4p()); + t.stop(); + std::cout << t.read() << std::endl; + io::pgm::save(g, "gradient-spe-lena-out-1.pgm"); + + t.restart(); + g = gradient_spe_2(lena, win_c4p()); + t.stop(); + std::cout << t.read() << std::endl; + io::pgm::save(g, "gradient-spe-lena-out-2.pgm"); + + t.restart(); + g = gradient_spe_3(lena, win_c4p()); + t.stop(); + std::cout << t.read() << std::endl; + io::pgm::save(g, "gradient-spe-lena-out-3.pgm"); + + t.restart(); + g = mln::morpho::gradient_spe_4(lena, win_c4p()); + t.stop(); + std::cout << t.read() << std::endl; + io::pgm::save(g, "gradient-spe-lena-out-4.pgm"); +} diff --git a/milena/mln/accu/pair.hh b/milena/apps/bench/minus.hh similarity index 74% copy from milena/mln/accu/pair.hh copy to milena/apps/bench/minus.hh index 11f4dc6..16b7b9d 100644 --- a/milena/mln/accu/pair.hh +++ b/milena/apps/bench/minus.hh @@ -1,4 +1,4 @@ -// Copyright (C) 2007, 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) // // This file is part of Olena. // @@ -23,17 +23,17 @@ // exception does not however invalidate any other reasons why the // executable file might be covered by the GNU General Public License. -#ifndef MLN_ACCU_PAIR_HH -# define MLN_ACCU_PAIR_HH +#ifndef MLN_ACCU_MINUS_HH +# define MLN_ACCU_MINUS_HH /// \file /// -/// Define a pair of accumulators. - -# include <utility> +/// Define a difference of accumulators. # include <mln/core/concept/meta_accumulator.hh> +# include <mln/arith/minus.hh> + # include <mln/accu/internal/base.hh> # include <mln/metal/is_a.hh> # include <mln/metal/unqualif.hh> @@ -46,38 +46,40 @@ namespace mln { - /// \brief Generic pair of accumulators. + /// \brief Difference of accumulators. /// /// The parameter \c T is the type of values. /// /// \todo Check that, when T is not provided, A1 and A2 have the same value. + /// \todo Compute the result type from both A1 and A2. /// /// \ingroup modaccumulti // template <typename A1, typename A2, typename T = mln_argument(A1)> - struct pair : public mln::accu::internal::base< std::pair<mln_result(A1), mln_result(A2)>, - pair<A1,A2,T> > + struct minus + : public mln::accu::internal::base< mln_result(A1), minus<A1,A2,T> > { typedef T argument; typedef mln_result(A1) result_1; typedef mln_result(A2) result_2; - pair(); + minus(); // FIXME: not implemented. Do we want it? -// pair(const A1& a1, const A2& a2); +// minus(const A1& a1, const A2& a2); /// Manipulators. /// \{ void init(); void take_as_init_(const argument& t); void take(const argument& t); - void take(const pair<A1,A2,T>& other); + void take(const minus<A1,A2,T>& other); + void untake(const argument& t); /// \} /// Get the value of the accumulator. /// \{ - std::pair<mln_result(A1), mln_result(A2)> to_result() const; + mln_result(A1) to_result() const; void get_result(result_1& r1, result_2& r2) const; /// \} @@ -105,16 +107,16 @@ namespace mln namespace meta { - /// Meta accumulator for pair. + /// Meta accumulator for minus. template <typename A1, typename A2> - struct pair : public Meta_Accumulator< pair<A1,A2> > + struct minus : public Meta_Accumulator< minus<A1,A2> > { template <typename T> struct with { typedef mln_accu_with(A1, T) A1_T; typedef mln_accu_with(A2, T) A2_T; - typedef accu::pair<A1_T, A2_T, T> ret; + typedef accu::minus<A1_T, A2_T, T> ret; }; }; @@ -125,7 +127,7 @@ namespace mln template <typename A1, typename A2, typename T> inline - pair<A1,A2,T>::pair() + minus<A1,A2,T>::minus() { init(); } @@ -133,7 +135,7 @@ namespace mln template <typename A1, typename A2, typename T> inline void - pair<A1,A2,T>::init() + minus<A1,A2,T>::init() { a1_.init(); a2_.init(); @@ -142,7 +144,7 @@ namespace mln template <typename A1, typename A2, typename T> inline void - pair<A1,A2,T>::take_as_init_(const argument& t) + minus<A1,A2,T>::take_as_init_(const argument& t) { a1_.take_as_init_(t); a2_.take_as_init_(t); @@ -151,7 +153,7 @@ namespace mln template <typename A1, typename A2, typename T> inline void - pair<A1,A2,T>::take(const argument& t) + minus<A1,A2,T>::take(const argument& t) { a1_.take(t); a2_.take(t); @@ -160,7 +162,7 @@ namespace mln template <typename A1, typename A2, typename T> inline void - pair<A1,A2,T>::take(const pair<A1,A2,T>& other) + minus<A1,A2,T>::take(const minus<A1,A2,T>& other) { a1_.take(other.a1_); a2_.take(other.a2_); @@ -168,17 +170,26 @@ namespace mln template <typename A1, typename A2, typename T> inline - std::pair<mln_result(A1), mln_result(A2)> - pair<A1,A2,T>::to_result() const + void + minus<A1,A2,T>::untake(const argument& t) + { + a1_.untake(t); + a2_.untake(t); + } + + template <typename A1, typename A2, typename T> + inline + mln_result(A1) + minus<A1,A2,T>::to_result() const { - std::pair<mln_result(A1), mln_result(A2)> tmp(a1_.to_result(), a2_.to_result()); + mln_result(A1) tmp = a1_.to_result() - a2_.to_result(); return tmp; } template <typename A1, typename A2, typename T> inline void - pair<A1,A2,T>::get_result(result_1& r1, + minus<A1,A2,T>::get_result(result_1& r1, result_2& r2) const { r1 = a1_.to_result(); @@ -188,7 +199,7 @@ namespace mln template <typename A1, typename A2, typename T> inline mln_result(A1) - pair<A1,A2,T>::first() const + minus<A1,A2,T>::first() const { return a1_.to_result(); } @@ -196,7 +207,7 @@ namespace mln template <typename A1, typename A2, typename T> inline mln_result(A2) - pair<A1,A2,T>::second() const + minus<A1,A2,T>::second() const { return a2_.to_result(); } @@ -206,7 +217,7 @@ namespace mln template <typename A1, typename A2, typename T> inline A1 - pair<A1,A2,T>::first_accu() const + minus<A1,A2,T>::first_accu() const { return a1_; } @@ -214,7 +225,7 @@ namespace mln template <typename A1, typename A2, typename T> inline A2 - pair<A1,A2,T>::second_accu() const + minus<A1,A2,T>::second_accu() const { return a2_; } @@ -223,7 +234,7 @@ namespace mln template <typename A1, typename A2, typename T> inline bool - pair<A1,A2,T>::is_valid() const + minus<A1,A2,T>::is_valid() const { return a1_.is_valid() && a2_.is_valid(); } @@ -235,4 +246,4 @@ namespace mln } // end of namespace mln -#endif // ! MLN_ACCU_PAIR_HH +#endif // ! MLN_ACCU_MINUS_HH -- 1.7.2.5