Commit d9fc1df7 authored by Roland Levillain's avatar Roland Levillain
Browse files

apps/bench: More (specialized) test/bench gradient on lena.pgm.

	* apps/bench/gradient-spe-lena.cc,
	* apps/bench/and_not.hh,
	* apps/bench/minus.hh:
	New.
	* apps/bench/Makefile.am (noinst_PROGRAMS): Add gradient-spe-lena.
	(noinst_HEADERS): Add and_not.hh and minus.h.
	(MOSTLYCLEANFILES): Update.
parent c8848046
2010-12-06 Roland Levillain <roland@lrde.epita.fr>
apps/bench: More (specialized) test/bench gradient on lena.pgm.
* apps/bench/gradient-spe-lena.cc,
* apps/bench/and_not.hh,
* apps/bench/minus.hh:
New.
* apps/bench/Makefile.am (noinst_PROGRAMS): Add gradient-spe-lena.
(noinst_HEADERS): Add and_not.hh and minus.h.
(MOSTLYCLEANFILES): Update.
2011-01-10 Roland Levillain <roland@lrde.epita.fr>
 
* apps/Makefile.am (SUBDIRS): Add bench.
......@@ -17,7 +17,17 @@
include $(top_srcdir)/milena/apps/apps.mk
noinst_PROGRAMS = \
gradient-lena
gradient-lena \
gradient-spe-lena
noinst_HEADERS = \
and_not.hh \
minus.hh
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
// Copyright (C) 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.
#ifndef MLN_ACCU_AND_NOT_HH
# define MLN_ACCU_AND_NOT_HH
/// \file
///
/// 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>
namespace mln
{
namespace accu
{
/// \brief Logical "and not" 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.
///
/// \ingroup modaccumulti
//
template <typename A1, typename A2, typename T = mln_argument(A1)>
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;
and_not();
// FIXME: not implemented. Do we want it?
// 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 and_not<A1,A2,T>& other);
void untake(const argument& t);
/// \}
/// Get the value of the accumulator.
/// \{
bool to_result() const;
void get_result(result_1& r1, result_2& r2) const;
/// \}
/// Return the result of the first accumulator.
mln_result(A1) first() const;
/// Return the result of the second accumulator.
mln_result(A2) second() const;
/// Return the first accumulator.
A1 first_accu() const;
/// Return the second accumulator.
A2 second_accu() const;
/// Check whether this accu is able to return a result.
/// Always true here.
bool is_valid() const;
protected:
A1 a1_;
A2 a2_;
};
namespace meta
{
/// Meta accumulator for and_not.
template <typename A1, typename 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::and_not<A1_T, A2_T, T> ret;
};
};
} // end of namespace mln::accu::meta
# ifndef MLN_INCLUDE_ONLY
template <typename A1, typename A2, typename T>
inline
and_not<A1,A2,T>::and_not()
{
init();
}
template <typename A1, typename A2, typename T>
inline
void
and_not<A1,A2,T>::init()
{
a1_.init();
a2_.init();
}
template <typename A1, typename A2, typename T>
inline
void
and_not<A1,A2,T>::take_as_init_(const argument& t)
{
a1_.take_as_init_(t);
a2_.take_as_init_(t);
}
template <typename A1, typename A2, typename T>
inline
void
and_not<A1,A2,T>::take(const argument& t)
{
a1_.take(t);
a2_.take(t);
}
template <typename A1, typename A2, typename T>
inline
void
and_not<A1,A2,T>::take(const and_not<A1,A2,T>& other)
{
a1_.take(other.a1_);
a2_.take(other.a2_);
}
template <typename A1, typename A2, typename T>
inline
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
{
bool tmp = a1_.to_result() && ! a2_.to_result();
return tmp;
}
template <typename A1, typename A2, typename T>
inline
void
and_not<A1,A2,T>::get_result(result_1& r1,
result_2& r2) const
{
r1 = a1_.to_result();
r2 = a2_.to_result();
}
template <typename A1, typename A2, typename T>
inline
mln_result(A1)
and_not<A1,A2,T>::first() const
{
return a1_.to_result();
}
template <typename A1, typename A2, typename T>
inline
mln_result(A2)
and_not<A1,A2,T>::second() const
{
return a2_.to_result();
}
template <typename A1, typename A2, typename T>
inline
A1
and_not<A1,A2,T>::first_accu() const
{
return a1_;
}
template <typename A1, typename A2, typename T>
inline
A2
and_not<A1,A2,T>::second_accu() const
{
return a2_;
}
template <typename A1, typename A2, typename T>
inline
bool
and_not<A1,A2,T>::is_valid() const
{
return a1_.is_valid() && a2_.is_valid();
}
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::accu
} // end of namespace mln
#endif // ! MLN_ACCU_AND_NOT_HH
// 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)
{
mln_trace("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));
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();