https://svn/svn/oln/prototypes/proto-1.0/olena
Index: ChangeLog
from Damien Thivolle <damien(a)lrde.epita.fr>
Rewrite reconstruction classes.
* tests/morpho/tests/reconstruction: Now use builtin types.
* oln/funobj/invert.hh: Add bool and unsigned char inversion.
* oln/core/abstract/image_typeness.hh: Add rules (unsigned char, char
and ntg::real_value) for greylevel_image.
* oln/morpho/reconstruction.hh: Now support grey level images.
* oln/morpho/local.hh: Add new functions for handling neighborhood.
* oln/morpho/reconstruction_by_dilation.hh: Add grey level
specialization and use new functions from local.hh.
* oln/morpho/reconstruction_selfdual.hh: Likewise.
* oln/morpho/reconstruction_by_erosion.hh: Likewise.
* oln/canvas/reconstruction.hh: Now use mlc::is_a to check if the input
images have a neighborhood. A bit of cleaning.
oln/canvas/reconstruction.hh | 53 +++--
oln/core/abstract/image_typeness.hh | 6
oln/funobj/invert.hh | 10 +
oln/morpho/local.hh | 178 ++++++++++++++++++
oln/morpho/reconstruction.hh | 41 +++-
oln/morpho/reconstruction_by_dilation.hh | 271 +++++++++++++++++++++-------
oln/morpho/reconstruction_by_erosion.hh | 296 +++++++++++++++++++++++--------
oln/morpho/reconstruction_selfdual.hh | 94 +--------
tests/morpho/tests/reconstruction | 22 +-
9 files changed, 733 insertions(+), 238 deletions(-)
Index: tests/morpho/tests/reconstruction
--- tests/morpho/tests/reconstruction (revision 275)
+++ tests/morpho/tests/reconstruction (working copy)
@@ -20,16 +20,16 @@
bool check()
{
using namespace oln;
- image2d<ntg::bin> marker;
- image2d<ntg::bin> mask;
- image_with_nbh<image2d<ntg::bin>, neighborhood2d> res_dil_hyb;
- image_with_nbh<image2d<ntg::bin>, neighborhood2d> res_dil_seq;
- image_with_nbh<image2d<ntg::bin>, neighborhood2d> res_dil_par;
- image_with_nbh<image2d<ntg::bin>, neighborhood2d> res_ero_hyb;
- image_with_nbh<image2d<ntg::bin>, neighborhood2d> res_ero_seq;
- image_with_nbh<image2d<ntg::bin>, neighborhood2d> res_ero_par;
- image_with_nbh<image2d<ntg::bin>, neighborhood2d> res_selfdual;
- image_with_nbh<image2d<ntg::bin>, neighborhood2d> res_selfdual_invert;
+ image2d<bool> marker;
+ image2d<bool> mask;
+ image_with_nbh<image2d<bool>, neighborhood2d> res_dil_hyb;
+ image_with_nbh<image2d<bool>, neighborhood2d> res_dil_seq;
+ image_with_nbh<image2d<bool>, neighborhood2d> res_dil_par;
+ image_with_nbh<image2d<bool>, neighborhood2d> res_ero_hyb;
+ image_with_nbh<image2d<bool>, neighborhood2d> res_ero_seq;
+ image_with_nbh<image2d<bool>, neighborhood2d> res_ero_par;
+ image_with_nbh<image2d<bool>, neighborhood2d> res_selfdual;
+ image_with_nbh<image2d<bool>, neighborhood2d> res_selfdual_invert;
utils::key::value_type data_key[16] =
{ 0xd1, 0x5c, 0x13, 0xd8, 0xe0, 0xa8, 0x58, 0x7d,
@@ -56,7 +56,7 @@
morpho::tag::parallel(),
morpho::tag::by_dilation());
- image2d<ntg::bin> marker_c(level::invert(marker));
+ image2d<bool> marker_c(level::invert(marker));
res_ero_hyb =
morpho::reconstruction(join(marker_c, neighb_c4()),
Index: oln/funobj/invert.hh
--- oln/funobj/invert.hh (revision 275)
+++ oln/funobj/invert.hh (working copy)
@@ -44,6 +44,16 @@
// (not: either -x or 1/x or min<->max or?)
struct invert
{
+ unsigned char operator()(const unsigned char& v) const
+ {
+ return 255 - v;
+ }
+
+ bool operator()(const bool& v) const
+ {
+ return !v;
+ }
+
template <typename V>
V operator()(const ntg::vect_value<V>& v) const
{
Index: oln/core/abstract/image_typeness.hh
--- oln/core/abstract/image_typeness.hh (revision 275)
+++ oln/core/abstract/image_typeness.hh (working copy)
@@ -112,6 +112,12 @@
template <typename E>
static tag_is<_label_tag> selector(ntg::enum_value<E>*);
+ template <typename E>
+ static tag_is<_greylevel_tag> selector(ntg::real_value<E>*);
+
+ static tag_is<_greylevel_tag> selector(char*);
+ static tag_is<_greylevel_tag> selector(unsigned char*);
+
static tag_is<_binary_tag> selector(bool*);
static tag_is<_binary_tag> selector(ntg::bin*);
template <class b>
Index: oln/morpho/reconstruction.hh
--- oln/morpho/reconstruction.hh (revision 275)
+++ oln/morpho/reconstruction.hh (working copy)
@@ -42,12 +42,47 @@
// Generic implementation of reconstruction (routine).
+// template<typename I1, typename I2, typename A, typename Op>
+// oln_type_of(I1, concrete)
+// reconstruction_(const abstract::image<I1>& marker,
+// const abstract::image<I2>& mask)
+// {
+// mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+
+// reconstruction<I1, I2, A, Op> tmp(marker, mask);
+// // tmp.entering(); FIXME: something like that ?
+
+// tmp.run();
+
+// // tmp.exiting(); FIXME: something like that ?
+// return tmp.get_output();
+// }
+
template<typename I1, typename I2, typename A, typename Op>
oln_type_of(I1, concrete)
- reconstruction_(const abstract::image_with_nbh<I1>& marker,
- const abstract::image<I2>& mask)
+ reconstruction_(const abstract::binary_image<I1>& marker,
+ const abstract::binary_image<I2>& mask)
+ {
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+
+ binary_reconstruction<I1, I2, A, Op> tmp(marker, mask);
+ // tmp.entering(); FIXME: something like that ?
+
+ tmp.run();
+
+ // tmp.exiting(); FIXME: something like that ?
+ return tmp.get_output();
+ }
+
+
+ template <typename I1, typename I2, typename A, typename Op>
+ oln_type_of(I1, concrete)
+ reconstruction_(const abstract::greylevel_image<I1>& marker,
+ const abstract::greylevel_image<I2>& mask)
{
- reconstruction<I1, I2, A, Op> tmp(marker, mask);
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+
+ greylevel_reconstruction<I1, I2, A, Op> tmp(marker, mask);
// tmp.entering(); FIXME: something like that ?
tmp.run();
Index: oln/morpho/local.hh
--- oln/morpho/local.hh (revision 275)
+++ oln/morpho/local.hh (working copy)
@@ -62,6 +62,54 @@
}
+ /// Local image "inf-value" for erosion on sets - based on the
+ /// neighborhood points that have already been processed when
+ /// performing a forward scan.
+
+ template <typename I>
+ oln_type_of(I, value) local_inf_value_fwd(const abstract::image<I>&
input,
+ const oln_type_of(I, point)& p)
+ {
+ mlc_is_a(I, abstract::image_with_nbh)::ensure();
+ mlc_is_a(I, abstract::not_binary_image)::ensure();
+
+ typedef oln_type_of(I, value) value_type;
+ typedef f_::accum_with_init<f_::inf_<value_type>, value_type>
accum_type;
+ accum_type val(ntg_sup_val(value_type));
+
+ oln_type_of(I, niter) n(input);
+ for_all_n_of_p(n, p)
+ if (input.hold(n) and p.fwd_less(n))
+ val(input[n]);
+
+ return val;
+ }
+
+
+ /// Local image "inf-value" for erosion on sets - based on the
+ /// neighborhood points that have already been processed when
+ /// performing a forward scan.
+
+ template <typename I>
+ oln_type_of(I, value) local_inf_value_bkd(const abstract::image<I>&
input,
+ const oln_type_of(I, point)& p)
+ {
+ mlc_is_a(I, abstract::image_with_nbh)::ensure();
+ mlc_is_a(I, abstract::not_binary_image)::ensure();
+
+ typedef oln_type_of(I, value) value_type;
+ typedef f_::accum_with_init<f_::inf_<value_type>, value_type>
accum_type;
+ accum_type val(ntg_sup_val(value_type));
+
+ oln_type_of(I, niter) n(input);
+ for_all_n_of_p(n, p)
+ if (input.hold(n) and p.bkd_less(n))
+ val(input[n]);
+
+ return val;
+ }
+
+
/// Local image "sup-value" for dilation on functions (based on the
neighborhood).
template <typename I>
@@ -84,6 +132,54 @@
}
+ /// Local image "sup-value" for erosion on sets - based on the
+ /// neighborhood points that have already been processed when
+ /// performing a forward scan.
+
+ template <typename I>
+ oln_type_of(I, value) local_sup_value_fwd(const abstract::image<I>&
input,
+ const oln_type_of(I, point)& p)
+ {
+ mlc_is_a(I, abstract::image_with_nbh)::ensure();
+ mlc_is_a(I, abstract::not_binary_image)::ensure();
+
+ typedef oln_type_of(I, value) value_type;
+ typedef f_::accum_with_init<f_::sup_<value_type>, value_type>
accum_type;
+ accum_type val(ntg_inf_val(value_type));
+
+ oln_type_of(I, niter) n(input);
+ for_all_n_of_p(n, p)
+ if (input.hold(n) and p.fwd_less(n))
+ val(input[n]);
+
+ return val;
+ }
+
+
+ /// Local image "sup-value" for erosion on sets - based on the
+ /// neighborhood points that have already been processed when
+ /// performing a forward scan.
+
+ template <typename I>
+ oln_type_of(I, value) local_sup_value_bkd(const abstract::image<I>&
input,
+ const oln_type_of(I, point)& p)
+ {
+ mlc_is_a(I, abstract::image_with_nbh)::ensure();
+ mlc_is_a(I, abstract::not_binary_image)::ensure();
+
+ typedef oln_type_of(I, value) value_type;
+ typedef f_::accum_with_init<f_::sup_<value_type>, value_type>
accum_type;
+ accum_type val(ntg_inf_val(value_type));
+
+ oln_type_of(I, niter) n(input);
+ for_all_n_of_p(n, p)
+ if (input.hold(n) and p.bkd_less(n))
+ val(input[n]);
+
+ return val;
+ }
+
+
/// Local image "and-value" for erosion on sets (based on the
neighborhood).
template <typename I>
@@ -102,6 +198,47 @@
}
+ /// Local image "and-value" for erosion on sets - based on the
+ /// neighborhood points that have already been processed when
+ /// performing a forward scan.
+
+ template <typename I>
+ oln_type_of(I, value) local_and_value_fwd(const abstract::image<I>& input,
+ const oln_type_of(I, point)& p)
+ {
+ mlc_is_a(I, abstract::image_with_nbh)::ensure();
+ mlc_is_a(I, abstract::binary_image)::ensure();
+
+ oln_type_of(I, niter) n(input);
+ for_all_n_of_p(n, p)
+ if (input.hold(n) and p.fwd_less(n) and not input[n])
+ return false;
+
+ return true;
+ }
+
+
+ /// Local image "and-value" for erosion on sets - based on the
+ /// neighborhood points that have already been processed when
+ /// performing a backward scan.
+
+ template <typename I>
+ oln_type_of(I, value) local_and_value_bkd(const abstract::image<I>& input,
+ const oln_type_of(I, point)& p)
+ {
+ mlc_is_a(I, abstract::image_with_nbh)::ensure();
+ mlc_is_a(I, abstract::binary_image)::ensure();
+
+ oln_type_of(I, niter) n(input);
+ for_all_n_of_p(n, p)
+ if (input.hold(n) and p.bkd_less(n) and not input[n])
+ return false;
+
+ return true;
+ }
+
+
+
/// Local image "or-value" for dilation on sets (based on the
neighborhood).
template <typename I>
@@ -120,6 +257,46 @@
}
+ /// Local image "or-value" for erosion on sets - based on the
+ /// neighborhood points that have already been processed when
+ /// performing a forward scan.
+
+ template <typename I>
+ oln_type_of(I, value) local_or_value_fwd(const abstract::image<I>& input,
+ const oln_type_of(I, point)& p)
+ {
+ mlc_is_a(I, abstract::image_with_nbh)::ensure();
+ mlc_is_a(I, abstract::binary_image)::ensure();
+
+ oln_type_of(I, niter) n(input);
+ for_all_n_of_p(n, p)
+ if (input.hold(n) and p.fwd_less(n) and input[n])
+ return true;
+
+ return false;
+ }
+
+
+ /// Local image "or-value" for erosion on sets - based on the
+ /// neighborhood points that have already been processed when
+ /// performing a backward scan.
+
+ template <typename I>
+ oln_type_of(I, value) local_or_value_bkd(const abstract::image<I>& input,
+ const oln_type_of(I, point)& p)
+ {
+ mlc_is_a(I, abstract::image_with_nbh)::ensure();
+ mlc_is_a(I, abstract::binary_image)::ensure();
+
+ oln_type_of(I, niter) n(input);
+ for_all_n_of_p(n, p)
+ if (input.hold(n) and p.bkd_less(n) and input[n])
+ return true;
+
+ return false;
+ }
+
+
/// Image "inf-value" in a window for erosion on functions.
@@ -207,5 +384,4 @@
} // end of namespace oln
-
#endif // ! OLENA_MORPHO_LOCAL_HH
Index: oln/morpho/reconstruction_by_dilation.hh
--- oln/morpho/reconstruction_by_dilation.hh (revision 275)
+++ oln/morpho/reconstruction_by_dilation.hh (working copy)
@@ -40,8 +40,10 @@
namespace impl {
+ // BINARY
+
template <typename I1, typename I2, typename A, typename E>
- struct reconstruction_by_dilation
+ struct binary_reconstruction_by_dilation
: public canvas::reconstruction<I1, I2, A, E>
{
typedef canvas::reconstruction<I1, I2, A, E> super_type;
@@ -55,55 +57,196 @@
using super_type::p;
- /// Local image "or-value" for dilation on sets
- /// (based on the point and its backward neighborhood).
+ void impl_bkd_loop_body()
+ {
+ output[bkd_p] = mask[bkd_p] and
+ (output[bkd_p] or local_or_value_bkd(join(output, marker.nbh_get()), bkd_p));
+ }
- oln_type_of(I1, value) bkd_or()
+ void impl_fwd_loop_body()
{
- if (output[bkd_p])
- return true;
- p = bkd_p;
- for_all_n_of_p(n, p)
- if (p.bkd_less(n) and output.hold(n) and output[n])
- return true;
+ output[fwd_p] = mask[fwd_p] and
+ (output[fwd_p] or local_or_value_fwd(join(output, marker.nbh_get()), fwd_p));
+ }
- return false;
+ binary_reconstruction_by_dilation(const abstract::binary_image<I1>& marker,
+ const abstract::binary_image<I2>& mask) :
+ super_type(marker, mask)
+ {
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
+ };
+
+ // Hybrid version
+
+ template<typename I1, typename I2>
+ struct binary_reconstruction <I1, I2, tag::hybrid_type,
tag::by_dilation_type>
+ : public binary_reconstruction_by_dilation<I1, I2, tag::hybrid_type,
+ binary_reconstruction<I1, I2, tag::hybrid_type, tag::by_dilation_type> >
+ {
+ typedef binary_reconstruction<I1, I2, tag::hybrid_type,
+ tag::by_dilation_type> self_type;
+ typedef binary_reconstruction_by_dilation<I1, I2, tag::hybrid_type,
+ self_type> super_type;
+
+ using super_type::mask;
+ using super_type::marker;
+ using super_type::output;
+ using super_type::bkd_p;
+ using super_type::n;
+ using super_type::p;
+ using super_type::fifo;
- /// Local image "or-value" for dilation on sets
- /// (based on the point and its forward neighborhood).
- oln_type_of(I1, value) fwd_or()
+ void impl_preconditions() const
{
- if (output[fwd_p])
- return true;
- p = fwd_p;
- for_all_n_of_p(n, p)
- if (p.fwd_less(n) and output.hold(n) and output[n])
- return true;
+ precondition(level::is_greater_or_equal(mask, marker));
+ }
- return false;
+ void impl_fifo_loop_body()
+ {
+ // output[n] < output[p] doesn't make sense with binary types.
+ if ((output[n] == false and output[p] == true) and (mask[n] != output[n]))
+ {
+ output[n] = output[p] and mask[n];
+ fifo.push(n);
+ }
}
+ bool impl_test_fifo_push()
+ {
+ return (output[n] == false and output[bkd_p] == true) and
+ (output[n] == false and mask[n] == true);
+ }
+
+
+ binary_reconstruction(const abstract::binary_image<I1>& marker,
+ const abstract::binary_image<I2>& mask) :
+ super_type(marker, mask)
+ {
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+ }
+
+ };
+
+
+ // Sequential version
+
+ template<typename I1, typename I2>
+ struct binary_reconstruction <I1, I2, tag::sequential_type,
tag::by_dilation_type>
+ : public binary_reconstruction_by_dilation<I1, I2, tag::sequential_type,
+ binary_reconstruction<I1, I2, tag::sequential_type,
+ tag::by_dilation_type> >
+ {
+ typedef binary_reconstruction<I1, I2, tag::sequential_type,
+ tag::by_dilation_type> self_type;
+ typedef binary_reconstruction_by_dilation<I1, I2, tag::sequential_type,
+ self_type> super_type;
+
+ using super_type::mask;
+ using super_type::marker;
+
+ void impl_preconditions() const
+ {
+ precondition(level::is_greater_or_equal(mask, marker));
+ }
+
+
+ binary_reconstruction(const abstract::binary_image<I1>& marker,
+ const abstract::binary_image<I2>& mask) :
+ super_type(marker, mask)
+ {
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+ }
+
+ };
+
+
+ // Parallel version
+
+ template <typename I1, typename I2>
+ struct binary_reconstruction<I1, I2, tag::parallel_type,
tag::by_dilation_type>
+ : public canvas::reconstruction<I1, I2, tag::parallel_type,
+ binary_reconstruction<I1, I2, tag::parallel_type, tag::by_dilation_type> >
+ {
+ typedef binary_reconstruction<I1, I2, tag::parallel_type,
+ tag::by_dilation_type> self_type;
+ typedef canvas::reconstruction<I1, I2, tag::parallel_type,
+ self_type> super_type;
+
+ using super_type::mask;
+ using super_type::marker;
+ using super_type::save;
+ using super_type::output;
+ using super_type::fwd_p;
+
+ void impl_first_step()
+ {
+ output[fwd_p] = save[fwd_p] or
+ local_or_value(join(save, marker.nbh_get()), fwd_p);
+ }
+
+ void impl_second_step()
+ {
+ output[fwd_p] = mask[fwd_p] and output[fwd_p];
+ }
+
+ void impl_preconditions() const
+ {
+ precondition(level::is_greater_or_equal(mask, marker));
+ }
+
+ binary_reconstruction(const abstract::binary_image<I1>& marker,
+ const abstract::binary_image<I2>& mask) :
+ super_type(marker, mask)
+ {
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+ }
+
+ };
+
+
+
+ // GREYLEVEL
+
+ template <typename I1, typename I2, typename A, typename E>
+ struct greylevel_reconstruction_by_dilation
+ : public canvas::reconstruction<I1, I2, A, E>
+ {
+ typedef canvas::reconstruction<I1, I2, A, E> super_type;
+ typedef oln_type_of(I1, value) value_type;
+ typedef f_::accum_with_init<f_::sup_<value_type>, value_type> accum_type;
+
+ using super_type::mask;
+ using super_type::marker;
+ using super_type::output;
+ using super_type::bkd_p;
+ using super_type::fwd_p;
+ using super_type::n;
+ using super_type::p;
+
void impl_bkd_loop_body()
{
- // FIXME: The call to value_box<>::value is needed to have
- // f_max_alt compile. Try to get rid of it.
- output[bkd_p] = f_min_alt(mask[bkd_p].value(), bkd_or());
+ value_type nbh_max =
+ f_max_alt(output[bkd_p].value(),
+ local_sup_value_bkd(join(output, marker.nbh_get()), bkd_p));
+ output[bkd_p] = f_min_alt(mask[bkd_p].value(), nbh_max);
}
void impl_fwd_loop_body()
{
- // FIXME: The call to value_box<>::value is needed to have
- // f_max_alt compile. Try to get rid of it.
- output[fwd_p] = f_min_alt(mask[fwd_p].value(), fwd_or());
+ value_type nbh_max =
+ f_max_alt(output[fwd_p].value(),
+ local_sup_value_fwd(join(output, marker.nbh_get()), fwd_p));
+ output[fwd_p] = f_min_alt(mask[fwd_p].value(), nbh_max);
}
- reconstruction_by_dilation(const abstract::image_with_nbh<I1>& marker,
- const abstract::image<I2>& mask) :
+ greylevel_reconstruction_by_dilation(const abstract::greylevel_image<I1>&
marker,
+ const abstract::greylevel_image<I2>& mask) :
super_type(marker, mask)
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
};
@@ -111,13 +254,13 @@
// Hybrid version
template<typename I1, typename I2>
- struct reconstruction <I1, I2, tag::hybrid_type, tag::by_dilation_type>
- : public reconstruction_by_dilation<I1, I2, tag::hybrid_type,
- reconstruction<I1, I2, tag::hybrid_type, tag::by_dilation_type> >
+ struct greylevel_reconstruction <I1, I2, tag::hybrid_type,
tag::by_dilation_type>
+ : public greylevel_reconstruction_by_dilation<I1, I2, tag::hybrid_type,
+ greylevel_reconstruction<I1, I2, tag::hybrid_type, tag::by_dilation_type> >
{
- typedef reconstruction<I1, I2, tag::hybrid_type,
+ typedef greylevel_reconstruction<I1, I2, tag::hybrid_type,
tag::by_dilation_type> self_type;
- typedef reconstruction_by_dilation<I1, I2, tag::hybrid_type,
+ typedef greylevel_reconstruction_by_dilation<I1, I2, tag::hybrid_type,
self_type> super_type;
using super_type::mask;
@@ -138,23 +281,22 @@
{
if ((output[n] < output[p]) and (mask[n] != output[n]))
{
- // FIXME: The calls to value_box<>::value are needed to
- // have f_min_alt compile. Try to get rid of it.
- output[n] = f_max_alt(output[p].value(), mask[n].value());
+ output[n] = f_min_alt(output[p].value(), mask[n].value());
fifo.push(n);
}
}
bool impl_test_fifo_push()
{
- return output[n] < output[bkd_p] and output[n] < mask[n];
+ return (output[n] < output[bkd_p]) and (output[n] < mask[n]);
}
- reconstruction(const abstract::image_with_nbh<I1>& marker,
- const abstract::image<I2>& mask) :
+ greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
+ const abstract::greylevel_image<I2>& mask) :
super_type(marker, mask)
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
};
@@ -163,14 +305,14 @@
// Sequential version
template<typename I1, typename I2>
- struct reconstruction <I1, I2, tag::sequential_type, tag::by_dilation_type>
- : public reconstruction_by_dilation<I1, I2, tag::sequential_type,
- reconstruction<I1, I2, tag::sequential_type,
+ struct greylevel_reconstruction <I1, I2, tag::sequential_type,
tag::by_dilation_type>
+ : public greylevel_reconstruction_by_dilation<I1, I2, tag::sequential_type,
+ greylevel_reconstruction<I1, I2, tag::sequential_type,
tag::by_dilation_type> >
{
- typedef reconstruction<I1, I2, tag::sequential_type,
+ typedef greylevel_reconstruction<I1, I2, tag::sequential_type,
tag::by_dilation_type> self_type;
- typedef reconstruction_by_dilation<I1, I2, tag::sequential_type,
+ typedef greylevel_reconstruction_by_dilation<I1, I2, tag::sequential_type,
self_type> super_type;
using super_type::mask;
@@ -182,10 +324,11 @@
}
- reconstruction(const abstract::image_with_nbh<I1>& marker,
- const abstract::image<I2>& mask) :
+ greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
+ const abstract::greylevel_image<I2>& mask) :
super_type(marker, mask)
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
};
@@ -194,14 +337,17 @@
// Parallel version
template <typename I1, typename I2>
- struct reconstruction<I1, I2, tag::parallel_type, tag::by_dilation_type>
+ struct greylevel_reconstruction<I1, I2, tag::parallel_type,
tag::by_dilation_type>
: public canvas::reconstruction<I1, I2, tag::parallel_type,
- reconstruction<I1, I2, tag::parallel_type, tag::by_dilation_type> >
+ greylevel_reconstruction<I1, I2, tag::parallel_type, tag::by_dilation_type> >
{
- typedef reconstruction<I1, I2, tag::parallel_type,
+ typedef greylevel_reconstruction<I1, I2, tag::parallel_type,
tag::by_dilation_type> self_type;
typedef canvas::reconstruction<I1, I2, tag::parallel_type,
self_type> super_type;
+ typedef oln_type_of(I1, value) value_type;
+ typedef f_::accum_with_init<f_::sup_<value_type>, value_type> accum_type;
+
using super_type::mask;
using super_type::marker;
@@ -210,31 +356,32 @@
using super_type::fwd_p;
- void impl_preconditions() const
+ void impl_first_step()
{
- precondition(level::is_greater_or_equal(mask, marker));
+ output[fwd_p] =
+ f_max_alt(output[fwd_p].value(),
+ local_sup_value(join(output, marker.nbh_get()), fwd_p));
}
- void impl_fwd_loop_body()
+ void impl_second_step()
{
- // dilation step
- if (not output[fwd_p])
- output[fwd_p] = local_or_value(join(save, marker.nbh_get()),
- fwd_p);
+ output[fwd_p] = f_min_alt(mask[fwd_p].value(), output[fwd_p].value());
+ }
- // minimum between mask and output
- output[fwd_p] = f_min_alt(output[fwd_p].value(), mask[fwd_p].value());
+ void impl_preconditions() const
+ {
+ precondition(level::is_greater_or_equal(mask, marker));
}
- reconstruction(const abstract::image_with_nbh<I1>& marker,
- const abstract::image<I2>& mask) :
+ greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
+ const abstract::greylevel_image<I2>& mask) :
super_type(marker, mask)
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
};
-
}
}
Index: oln/morpho/reconstruction_selfdual.hh
--- oln/morpho/reconstruction_selfdual.hh (revision 275)
+++ oln/morpho/reconstruction_selfdual.hh (working copy)
@@ -34,7 +34,6 @@
# include <oln/funobj/arith.hh>
-//FIXME: Adapt ...
namespace oln {
@@ -44,20 +43,23 @@
namespace impl {
+ // BINARY
+
template<typename I1, typename I2>
- struct reconstruction <I1, I2, tag::selfdual_type, tag::none_type>
+ struct binary_reconstruction <I1, I2, tag::selfdual_type, tag::none_type>
: public canvas::reconstruction<I1, I2, tag::hybrid_type,
- reconstruction<I1, I2, tag::selfdual_type, tag::none_type> >
+ binary_reconstruction<I1, I2, tag::selfdual_type, tag::none_type> >
{
- typedef reconstruction<I1, I2, tag::selfdual_type,
+ typedef binary_reconstruction<I1, I2, tag::selfdual_type,
tag::none_type> self_type;
typedef canvas::reconstruction<I1, I2, tag::hybrid_type,
self_type> super_type;
- reconstruction(const abstract::image_with_nbh<I1>& marker,
- const abstract::image<I2>& mask) :
+ binary_reconstruction(const abstract::binary_image<I1>& marker,
+ const abstract::binary_image<I2>& mask) :
super_type(marker, mask)
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
using super_type::mask;
@@ -70,87 +72,25 @@
using super_type::fifo;
- /// Local image "or-value" for dilation on sets
- /// (based on the point and its backward neighborhood).
-
- oln_type_of(I1, value) bkd_or()
- {
- if (output[bkd_p])
- return true;
- p = bkd_p;
- for_all_n_of_p(n, p)
- if (p.bkd_less(n) and output.hold(n) and output[n])
- return true;
-
- return false;
- }
-
-
- /// Local image "or-value" for dilation on sets
- /// (based on the point and its forward neighborhood).
-
- oln_type_of(I1, value) fwd_or()
- {
- if (output[fwd_p])
- return true;
- p = fwd_p;
- for_all_n_of_p(n, p)
- if (p.fwd_less(n) and output.hold(n) and output[n])
- return true;
-
- return false;
- }
-
-
-
- /// Local image "and-value" for erosion on sets
- /// (based on the point and its backward neighborhood).
-
- oln_type_of(I1, value) bkd_and()
- {
- if (not output[bkd_p])
- return false;
- p = bkd_p;
- for_all_n_of_p(n, p)
- if (p.bkd_less(n) and output.hold(n) and not output[n])
- return false;
-
- return true;
- }
-
-
- /// Local image "and-value" for erosion on sets
- /// (based on the point and its forward neighborhood).
-
- oln_type_of(I1, value) fwd_and()
- {
- if (not output[fwd_p])
- return false;
- p = fwd_p;
- for_all_n_of_p(n, p)
- if (p.fwd_less(n) and output.hold(n) and not output[n])
- return false;
-
- return true;
- }
-
-
void impl_bkd_loop_body()
{
- // FIXME: Shouldn't be .value() !
if (output[bkd_p] < mask[bkd_p])
- output[bkd_p] = f_min_alt(bkd_or(), mask[bkd_p].value());
+ output[bkd_p] = mask[bkd_p] and
+ (output[bkd_p] or local_or_value_bkd(join(output, marker.nbh_get()), bkd_p));
else
- output[bkd_p] = f_max_alt(bkd_and(), mask[bkd_p].value());
+ output[bkd_p] = mask[bkd_p] or
+ (output[bkd_p] and local_and_value_bkd(join(output, marker.nbh_get()), bkd_p));
}
void impl_fwd_loop_body()
{
- // FIXME: Shouldn't be .value() !
if (output[fwd_p] < mask[fwd_p])
- output[fwd_p] = f_min_alt(fwd_or(), mask[fwd_p].value());
+ output[fwd_p] = mask[fwd_p] and
+ (output[fwd_p] or local_or_value_fwd(join(output, marker.nbh_get()), fwd_p));
else
- output[fwd_p] = f_max_alt(fwd_and(), mask[fwd_p].value());
+ output[fwd_p] = mask[fwd_p] or
+ (output[fwd_p] and local_and_value_fwd(join(output, marker.nbh_get()), fwd_p));
+
}
void impl_fifo_loop_body()
Index: oln/morpho/reconstruction_by_erosion.hh
--- oln/morpho/reconstruction_by_erosion.hh (revision 275)
+++ oln/morpho/reconstruction_by_erosion.hh (working copy)
@@ -40,8 +40,10 @@
namespace impl {
+ // BINARY
+
template <typename I1, typename I2, typename A, typename E>
- struct reconstruction_by_erosion
+ struct binary_reconstruction_by_erosion
: public canvas::reconstruction<I1, I2, A, E>
{
typedef canvas::reconstruction<I1, I2, A, E> super_type;
@@ -54,71 +56,217 @@
using super_type::n;
using super_type::p;
+ void impl_bkd_loop_body()
+ {
+ output[bkd_p] = mask[bkd_p] or
+ (output[bkd_p] and local_and_value_bkd(join(output, marker.nbh_get()), bkd_p));
+ }
+
+ void impl_fwd_loop_body()
+ {
+ output[fwd_p] = mask[fwd_p] or
+ (output[fwd_p] and local_and_value_fwd(join(output, marker.nbh_get()), fwd_p));
+ }
+
+ binary_reconstruction_by_erosion(const abstract::binary_image<I1>& marker,
+ const abstract::binary_image<I2>& mask) :
+ super_type(marker, mask)
+ {
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+ }
- /// Local image "and-value" for erosion on sets
- /// (based on the point and its backward neighborhood).
+ };
- oln_type_of(I1, value) bkd_and()
+ // Hybrid version
+
+ template<typename I1, typename I2>
+ struct binary_reconstruction <I1, I2, tag::hybrid_type,
tag::by_erosion_type>
+ : public binary_reconstruction_by_erosion<I1, I2, tag::hybrid_type,
+ binary_reconstruction<I1, I2, tag::hybrid_type, tag::by_erosion_type> >
{
- if (not output[bkd_p])
- return false;
- p = bkd_p;
- for_all_n_of_p(n, p)
- if (p.bkd_less(n) and output.hold(n) and not output[n])
- return false;
+ typedef binary_reconstruction<I1, I2, tag::hybrid_type,
+ tag::by_erosion_type> self_type;
+ typedef binary_reconstruction_by_erosion<I1, I2, tag::hybrid_type,
+ self_type> super_type;
- return true;
+ using super_type::mask;
+ using super_type::marker;
+ using super_type::output;
+ using super_type::bkd_p;
+ using super_type::n;
+ using super_type::p;
+ using super_type::fifo;
+
+
+ void impl_preconditions() const
+ {
+ precondition(level::is_lower_or_equal(mask, marker));
}
+ void impl_fifo_loop_body()
+ {
+ // output[n] > output[p] doesn't make sense with binary types...
+ if ((output[n] == true and output[p] == false) and (mask[n] != output[n]))
+ {
+ output[n] = output[p] and mask[n];
+ fifo.push(n);
+ }
+ }
- /// Local image "and-value" for erosion on sets
- /// (based on the point and its forward neighborhood).
+ bool impl_test_fifo_push()
+ {
+ return (output[n] == true and output[bkd_p] == false)and
+ (output[n] == true and mask[n] == false);
+ }
+
+
+ binary_reconstruction(const abstract::binary_image<I1>& marker,
+ const abstract::binary_image<I2>& mask) :
+ super_type(marker, mask)
+ {
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+ }
+
+ };
- oln_type_of(I1, value) fwd_and()
+
+ // Sequential version
+
+ template<typename I1, typename I2>
+ struct binary_reconstruction <I1, I2, tag::sequential_type,
tag::by_erosion_type>
+ : public binary_reconstruction_by_erosion<I1, I2, tag::sequential_type,
+ binary_reconstruction<I1, I2, tag::sequential_type,
+ tag::by_erosion_type> >
{
- if (not output[fwd_p])
- return false;
- p = fwd_p;
- for_all_n_of_p(n, p)
- if (p.fwd_less(n) and output.hold(n) and not output[n])
- return false;
+ typedef binary_reconstruction<I1, I2, tag::sequential_type,
+ tag::by_erosion_type> self_type;
+ typedef binary_reconstruction_by_erosion<I1, I2, tag::sequential_type,
+ self_type> super_type;
- return true;
+ using super_type::mask;
+ using super_type::marker;
+
+ void impl_preconditions() const
+ {
+ precondition(level::is_lower_or_equal(mask, marker));
}
+
+ binary_reconstruction(const abstract::binary_image<I1>& marker,
+ const abstract::binary_image<I2>& mask) :
+ super_type(marker, mask)
+ {
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+ }
+
+ };
+
+
+ // Parallel version
+
+ template <typename I1, typename I2>
+ struct binary_reconstruction<I1, I2, tag::parallel_type,
tag::by_erosion_type>
+ : public canvas::reconstruction<I1, I2, tag::parallel_type,
+ binary_reconstruction<I1, I2, tag::parallel_type, tag::by_erosion_type> >
+ {
+ typedef binary_reconstruction<I1, I2, tag::parallel_type,
+ tag::by_erosion_type> self_type;
+ typedef canvas::reconstruction<I1, I2, tag::parallel_type,
+ self_type> super_type;
+
+ using super_type::mask;
+ using super_type::marker;
+ using super_type::save;
+ using super_type::output;
+ using super_type::fwd_p;
+
+ void impl_first_step()
+ {
+ output[fwd_p] = save[fwd_p] and
+ local_and_value(join(save, marker.nbh_get()), fwd_p);
+ }
+
+ void impl_second_step()
+ {
+ output[fwd_p] = mask[fwd_p] or output[fwd_p];
+ }
+
+ void impl_preconditions() const
+ {
+ precondition(level::is_lower_or_equal(mask, marker));
+ }
+
+ binary_reconstruction(const abstract::binary_image<I1>& marker,
+ const abstract::binary_image<I2>& mask) :
+ super_type(marker, mask)
+ {
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+ }
+
+ };
+
+
+
+
+
+
+ // GREYLEVEL
+
+
+
+
+ template <typename I1, typename I2, typename A, typename E>
+ struct greylevel_reconstruction_by_erosion
+ : public canvas::reconstruction<I1, I2, A, E>
+ {
+ typedef canvas::reconstruction<I1, I2, A, E> super_type;
+ typedef oln_type_of(I1, value) value_type;
+ typedef f_::accum_with_init<f_::inf_<value_type>, value_type> accum_type;
+
+ using super_type::mask;
+ using super_type::marker;
+ using super_type::output;
+ using super_type::bkd_p;
+ using super_type::fwd_p;
+ using super_type::n;
+ using super_type::p;
+
void impl_bkd_loop_body()
{
- // FIXME: The call to value_box<>::value is needed to have
- // f_max_alt compile. Try to get rid of it.
- output[bkd_p] = f_max_alt(mask[bkd_p].value(), bkd_and());
+ value_type nbh_min =
+ f_min_alt(output[bkd_p].value(),
+ local_inf_value_bkd(join(output, marker.nbh_get()), bkd_p));
+ output[bkd_p] = f_max_alt(mask[bkd_p].value(), nbh_min);
}
void impl_fwd_loop_body()
{
- // FIXME: The call to value_box<>::value is needed to have
- // f_max_alt compile. Try to get rid of it.
- output[fwd_p] = f_max_alt(mask[fwd_p].value(), fwd_and());
+ value_type nbh_min =
+ f_min_alt(output[fwd_p].value(),
+ local_inf_value_fwd(join(output, marker.nbh_get()), fwd_p));
+ output[fwd_p] = f_max_alt(mask[fwd_p].value(), nbh_min);
}
- reconstruction_by_erosion(const abstract::image_with_nbh<I1>& marker,
- const abstract::image<I2>& mask) :
+
+ greylevel_reconstruction_by_erosion(const abstract::greylevel_image<I1>&
marker,
+ const abstract::greylevel_image<I2>& mask) :
super_type(marker, mask)
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
};
-
// Hybrid version
template<typename I1, typename I2>
- struct reconstruction <I1, I2, tag::hybrid_type, tag::by_erosion_type>
- : public reconstruction_by_erosion<I1, I2, tag::hybrid_type,
- reconstruction<I1, I2, tag::hybrid_type, tag::by_erosion_type> >
+ struct greylevel_reconstruction <I1, I2, tag::hybrid_type,
tag::by_erosion_type>
+ : public greylevel_reconstruction_by_erosion<I1, I2, tag::hybrid_type,
+ greylevel_reconstruction<I1, I2, tag::hybrid_type, tag::by_erosion_type> >
{
- typedef reconstruction<I1, I2, tag::hybrid_type,
+ typedef greylevel_reconstruction<I1, I2, tag::hybrid_type,
tag::by_erosion_type> self_type;
- typedef reconstruction_by_erosion<I1, I2, tag::hybrid_type,
+ typedef greylevel_reconstruction_by_erosion<I1, I2, tag::hybrid_type,
self_type> super_type;
using super_type::mask;
@@ -130,31 +278,31 @@
using super_type::fifo;
+ void impl_preconditions() const
+ {
+ precondition(level::is_lower_or_equal(mask, marker));
+ }
+
void impl_fifo_loop_body()
{
if ((output[n] > output[p]) and (mask[n] != output[n]))
{
- // FIXME: The calls to value_box<>::value are needed to
- // have f_min_alt compile. Try to get rid of it.
- output[n] = f_min_alt(output[p].value(), mask[n].value());
+ output[n] = f_max_alt(output[p].value(), mask[n].value());
fifo.push(n);
}
}
- void impl_preconditions() const
- {
- precondition(level::is_greater_or_equal(marker, mask));
- }
-
bool impl_test_fifo_push()
{
- return output[n] > output[bkd_p] and output[n] > mask[n];
+ return (output[n] > output[bkd_p]) and (output[n] > mask[n]);
}
- reconstruction(const abstract::image_with_nbh<I1>& marker,
- const abstract::image<I2>& mask) :
+
+ greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
+ const abstract::greylevel_image<I2>& mask) :
super_type(marker, mask)
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
};
@@ -163,42 +311,49 @@
// Sequential version
template<typename I1, typename I2>
- struct reconstruction <I1, I2, tag::sequential_type, tag::by_erosion_type>
- : public reconstruction_by_erosion<I1, I2, tag::sequential_type,
- reconstruction<I1, I2, tag::sequential_type,
+ struct greylevel_reconstruction <I1, I2, tag::sequential_type,
tag::by_erosion_type>
+ : public greylevel_reconstruction_by_erosion<I1, I2, tag::sequential_type,
+ greylevel_reconstruction<I1, I2, tag::sequential_type,
tag::by_erosion_type> >
{
- typedef reconstruction<I1, I2, tag::sequential_type,
+ typedef greylevel_reconstruction<I1, I2, tag::sequential_type,
tag::by_erosion_type> self_type;
- typedef reconstruction_by_erosion<I1, I2, tag::sequential_type,
+ typedef greylevel_reconstruction_by_erosion<I1, I2, tag::sequential_type,
self_type> super_type;
+
using super_type::mask;
using super_type::marker;
void impl_preconditions() const
{
- precondition(level::is_greater_or_equal(marker, mask));
+ precondition(level::is_lower_or_equal(mask, marker));
}
- reconstruction(const abstract::image_with_nbh<I1>& marker,
- const abstract::image<I2>& mask) :
+
+ greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
+ const abstract::greylevel_image<I2>& mask) :
super_type(marker, mask)
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
+
};
// Parallel version
template <typename I1, typename I2>
- struct reconstruction<I1, I2, tag::parallel_type, tag::by_erosion_type>
+ struct greylevel_reconstruction<I1, I2, tag::parallel_type,
tag::by_erosion_type>
: public canvas::reconstruction<I1, I2, tag::parallel_type,
- reconstruction<I1, I2, tag::parallel_type, tag::by_erosion_type> >
+ greylevel_reconstruction<I1, I2, tag::parallel_type, tag::by_erosion_type> >
{
- typedef reconstruction<I1, I2, tag::parallel_type,
+ typedef greylevel_reconstruction<I1, I2, tag::parallel_type,
tag::by_erosion_type> self_type;
typedef canvas::reconstruction<I1, I2, tag::parallel_type,
self_type> super_type;
+ typedef oln_type_of(I1, value) value_type;
+ typedef f_::accum_with_init<f_::inf_<value_type>, value_type> accum_type;
+
using super_type::mask;
using super_type::marker;
@@ -206,31 +361,34 @@
using super_type::output;
using super_type::fwd_p;
-
- void impl_preconditions() const
+ void impl_first_step()
{
- precondition(level::is_greater_or_equal(marker, mask));
+ output[fwd_p] =
+ f_min_alt(output[fwd_p].value(),
+ local_inf_value(join(output, marker.nbh_get()), fwd_p));
}
- void impl_fwd_loop_body()
+ void impl_second_step()
{
- // erosion step
- if (output[fwd_p])
- output[fwd_p] = local_and_value(join(save, marker.nbh_get()),
- fwd_p);
+ output[fwd_p] = f_max_alt(mask[fwd_p].value(), output[fwd_p].value());
+ }
- // maximum between mask and output
- output[fwd_p] = f_max_alt(output[fwd_p].value(), mask[fwd_p].value());
+ void impl_preconditions() const
+ {
+ precondition(level::is_lower_or_equal(mask, marker));
}
- reconstruction(const abstract::image_with_nbh<I1>& marker,
- const abstract::image<I2>& mask) :
+ greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
+ const abstract::greylevel_image<I2>& mask) :
super_type(marker, mask)
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
};
+
+
}
}
Index: oln/canvas/reconstruction.hh
--- oln/canvas/reconstruction.hh (revision 275)
+++ oln/canvas/reconstruction.hh (working copy)
@@ -43,7 +43,10 @@
namespace impl {
template <typename T, typename A, typename I1, typename I2>
- struct reconstruction {};
+ struct binary_reconstruction {};
+
+ template <typename T, typename A, typename I1, typename I2>
+ struct greylevel_reconstruction {};
}
@@ -56,6 +59,8 @@
template <typename I1, typename I2, typename A, typename E>
struct reconstruction;
+
+ // HYBRID
template <typename I1, typename I2, typename E>
struct reconstruction<I1, I2, morpho::tag::hybrid_type, E>
: public mlc::any<E>
@@ -146,7 +151,7 @@
protected:
- reconstruction(const abstract::image_with_nbh<I1>& marker,
+ reconstruction(const abstract::image<I1>& marker,
const abstract::image<I2>& mask) :
marker(marker.exact()),
mask(mask.exact()),
@@ -158,6 +163,7 @@
~reconstruction()
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
mlc_check_method_impl(E, bool, test_fifo_push, , );
mlc_check_method_impl(E, void, preconditions, , const);
mlc_check_method_impl(E, void, bkd_loop_body, , );
@@ -182,6 +188,8 @@
+
+ // SEQUENTIAL
template <typename I1, typename I2, typename E>
struct reconstruction<I1, I2, morpho::tag::sequential_type, E> :
public back_and_forth_until_convergence<I1, E>
@@ -228,13 +236,14 @@
protected:
- reconstruction(const abstract::image_with_nbh<I1>& marker,
+ reconstruction(const abstract::image<I1>& marker,
const abstract::image<I2>& mask) :
super_type(marker),
marker(marker.exact()),
mask(mask.exact()),
n(marker)
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
box<oln_type_of(I1, concrete)> save;
@@ -248,9 +257,10 @@
+ // PARALLEL
template <typename I1, typename I2, typename E>
struct reconstruction<I1, I2, morpho::tag::parallel_type, E> :
- public forth_until_convergence<I1, E>
+ public until_convergence<E>
{
typedef forth_until_convergence<I1, E> super_type;
typedef oln_type_of(I1, neighb) nbh_type;
@@ -259,9 +269,24 @@
// Abstract methods.
- void fwd_loop_body()
+ void first_step()
{
- this->exact().impl_fwd_loop_body();
+ this->exact().impl_first_step();
+ }
+
+ void second_step()
+ {
+ this->exact().impl_second_step();
+ }
+
+
+ void impl_loop_body()
+ {
+ for_all_p(fwd_p)
+ first_step();
+
+ for_all_p(fwd_p)
+ second_step();
}
// Concrete methods.
@@ -278,10 +303,8 @@
// called, which is empty (see oln/core/box.hh).
output_type save_tmp(clone(marker));
save = save_tmp;
-
}
-
bool impl_is_stable() const
{
return level::is_equal(save, output);
@@ -302,26 +325,26 @@
protected:
- reconstruction(const abstract::image_with_nbh<I1>& marker,
+ reconstruction(const abstract::image<I1>& marker,
const abstract::image<I2>& mask) :
- super_type(marker),
marker(marker.exact()),
- mask(mask.exact())
+ mask(mask.exact()),
+ fwd_p(marker.size())
{
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+ mlc_check_method_impl(E, void, first_step, , );
+ mlc_check_method_impl(E, void, second_step, , );
}
box<oln_type_of(I1, concrete)> save;
box<oln_type_of(I1, concrete)> output;
box<const I1> marker;
box<const I2> mask;
-
+ oln_type_of(I1, fwd_piter) fwd_p;
};
-
}
-
}
-
#endif // ! OLENA_CANVAS_RECONSTRUCTION_HH