https://svn/svn/oln/prototypes/proto-1.0/olena
Index: ChangeLog from Damien Thivolle damien@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; - image2dntg::bin marker; - image2dntg::bin mask; - image_with_nbh<image2dntg::bin, neighborhood2d> res_dil_hyb; - image_with_nbh<image2dntg::bin, neighborhood2d> res_dil_seq; - image_with_nbh<image2dntg::bin, neighborhood2d> res_dil_par; - image_with_nbh<image2dntg::bin, neighborhood2d> res_ero_hyb; - image_with_nbh<image2dntg::bin, neighborhood2d> res_ero_seq; - image_with_nbh<image2dntg::bin, neighborhood2d> res_ero_par; - image_with_nbh<image2dntg::bin, neighborhood2d> res_selfdual; - image_with_nbh<image2dntg::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());
- image2dntg::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
"Damien" == Damien Thivolle damien@lrde.epita.fr writes:
Damien> https://svn/svn/oln/prototypes/proto-1.0/olena
Index: ChangeLog from Damien Thivolle damien@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.
[...]
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;
What about UCHAR_MAX? I know char's size is fixed, but nevertheless.