Index: ChangeLog from Damien Thivolle <damien@lrde.epita.fr> * tests/morpho/tests/reconstruction: New. * oln/convert/nbh_to_se.hh: Adapt to new neighborhoods. * oln/core/abstract/image_neighbness.hh (impl_get_nbh): Add missing method. * oln/morpho/reconstruction.hh: New hierarchy. * oln/morpho/splitse.hh: Adapt to new neighborhoods. * oln/morpho/reconstruction_by_erosion.inc: New. Implementation for reconstruction by erosion. * oln/morpho/reconstruction_canvas.inc: New. Canvas for reconstruction: sequential & hybrid. * oln/morpho/reconstruction_by_dilation.inc: New. Implementation for reconstruction by dilation. * img/marker.pbm: New. * img/mask.pbm: New. img/marker.pbm | 0 img/mask.pbm | 0 oln/convert/nbh_to_se.hh | 8 oln/core/abstract/image_neighbness.hh | 6 oln/morpho/reconstruction.hh | 514 +++++++----------------------- oln/morpho/reconstruction_by_dilation.inc | 142 ++++++++ oln/morpho/reconstruction_by_erosion.inc | 141 ++++++++ oln/morpho/reconstruction_canvas.inc | 238 +++++++++++++ oln/morpho/splitse.hh | 127 +++---- tests/morpho/tests/reconstruction | 66 +++ 10 files changed, 780 insertions, 462 deletions Index: tests/morpho/tests/reconstruction --- tests/morpho/tests/reconstruction (revision 0) +++ tests/morpho/tests/reconstruction (revision 0) @@ -0,0 +1,66 @@ +// -*- C++ -*- + +#include "data.hh" +#include <oln/basics2d.hh> +#include <ntg/all.hh> + +#include <oln/core/gen/image_with_nbh.hh> + +#include <oln/morpho/reconstruction.hh> + +#include <oln/io/read_image.hh> +#include <oln/io/write_image.hh> + +#include <oln/level/compare.hh> +#include <oln/utils/md5.hh> +#include <oln/utils/invert.hh> + +bool check() +{ + using namespace oln; + image2d<ntg::bin> marker; + image2d<ntg::bin> mask; + image2d<ntg::bin> res_dil_hyb; + image2d<ntg::bin> res_dil_seq; + image2d<ntg::bin> res_ero_hyb; + image2d<ntg::bin> res_ero_seq; + + utils::key::value_type data_key[16] = + { + 0x36, 0xa6, 0x2e, 0x7e, 0xbf, 0x21, 0xf6, 0x2b, + 0xbf, 0x57, 0x58, 0xdc, 0x9d, 0x72, 0x41, 0x8f + }; + utils::key key(data_key); + + marker = io::read(rdata("marker.pbm")); + mask = io::read(rdata("mask.pbm")); + + res_dil_hyb = morpho::reconstruction(tag::by_dilation(), + join(marker, neighb_c4()), + mask, + tag::hybrid()); + res_dil_seq = morpho::reconstruction(tag::by_dilation(), + join(marker, neighb_c4()), + mask, + tag::sequential()); + + res_ero_hyb = morpho::reconstruction(tag::by_erosion(), + utils::invert(join(marker, neighb_c4())), + utils::invert(mask), + tag::hybrid()); + res_ero_seq = morpho::reconstruction(tag::by_erosion(), + utils::invert(join(marker, neighb_c4())), + utils::invert(mask), + tag::sequential()); + + if (utils::md5(res_dil_hyb) != key) + return true; + if (!level::is_equal(res_dil_hyb, res_dil_seq)) + return true; + if (!level::is_equal(res_ero_hyb, res_ero_seq)) + return true; + if (!level::is_equal(res_dil_hyb, utils::invert(res_ero_seq))) + return true; + + return false; +} Index: oln/convert/nbh_to_se.hh --- oln/convert/nbh_to_se.hh (revision 162) +++ oln/convert/nbh_to_se.hh (working copy) @@ -40,12 +40,12 @@ */ template<class N> oln_nbh_type_of(N, window) - nbh_to_se(const oln::abstract::neighborhood<N>& nbh) + nbh_to_se(const N& nbh) // FIXME: UGLY oln::abstract::neighborhood<N>& nbh) { oln_nbh_type_of(N, window) output; for (unsigned i = 0; i < nbh.card(); i++) - output.add(nbh[i]); + output.add(nbh.dp(i)); return output; } @@ -61,12 +61,12 @@ */ template<class N> oln_nbh_type_of(N, window) - nbh_to_cse(const oln::abstract::neighborhood<N>& nbh) + nbh_to_cse(const N& nbh) // FIXME: UGLY oln::abstract::neighborhood<N>& nbh) { oln_nbh_type_of(N, window) output; for (unsigned i = 0; i < nbh.card(); i++) - output.add(nbh[i]); + output.add(nbh.dp(i)); oln_nbh_type_of(N, dpoint) zero; dpoint_zero(zero); Index: oln/core/abstract/image_neighbness.hh --- oln/core/abstract/image_neighbness.hh (revision 162) +++ oln/core/abstract/image_neighbness.hh (working copy) @@ -53,6 +53,12 @@ return this->exact().impl_nbh_get(); } + //FIXME: is it the right way ? + const neighb_type& impl_nbh_get() const + { + return this->exact().delegate().nbh_get(); + } + protected: image_with_nbh() {} Index: oln/morpho/reconstruction.hh --- oln/morpho/reconstruction.hh (revision 162) +++ oln/morpho/reconstruction.hh (working copy) @@ -49,453 +49,181 @@ namespace oln { - namespace morpho { - // fwd decl - template <typename I, typename E> struct reconstruction_ret; + namespace tag { - } + template <typename Op> struct oper {}; - // category - template <typename I, typename E> - struct set_category< morpho::reconstruction_ret<I,E> > { typedef category::image ret; }; + struct by_dilation : public oper< by_dilation > {}; + struct by_erosion : public oper< by_erosion > {}; - // super_type - template <typename I, typename E> - struct set_super_type< morpho::reconstruction_ret<I,E> > - { - typedef abstract::image_binary_operator<I, I, I, morpho::reconstruction_ret<I, E> > ret; - // FIXME: see below - }; + template <typename A> struct algo {}; - namespace morpho { + struct sequential : public algo< sequential > {}; + struct hybrid : public algo< hybrid > {}; - template <typename I, typename N> - struct reconstruction_ret : public abstract::image_binary_operator<I, I, I, reconstruction_ret<I, N> > - // FIXME: abstract::image_binary_operator<oln_type_of(I, concrete), ... - { - typedef abstract::image_binary_operator<I, I, I, reconstruction_ret<I, N> > super_type; + } // end of namespace oln::morpho::tag - const N nbh; - reconstruction_ret(const abstract::image<I>& input1, - const abstract::image<I>& input2, - const abstract::neighborhood<N>& nbh) : - super_type(input1.exact(), input2.exact()), - nbh(nbh.exact()) - {} - }; + namespace morpho { + template <typename I1, typename I2> struct reconstruction_ret; + } // end of namespace oln::morpho - namespace sequential { + // super_type - namespace impl { + template <typename I1, typename I2> + struct set_super_type< morpho::reconstruction_ret<I1, I2> > + { + typedef oln_type_of(I1, concrete) output_type; - template <typename I, typename N, typename E> - struct reconstruction_sequential_ret : public reconstruction_ret<I, N> - { - typedef reconstruction_ret<I, N> super_type; + typedef morpho::reconstruction_ret<I1,I2> self_type; + typedef abstract::image_binary_operator<output_type, I1, I2, self_type > ret; + }; - void fwd_loop_body() - { - static_cast<E*>((void*)this)->fwd_loop_body_impl(); - } + namespace morpho { - void bkd_loop_body() - { - static_cast<E*>((void*)this)->bkd_loop_body_impl(); - } + // Reconstruction as a 'classical' procedure returning an image (do not + // use it; prefer morpho::reconstruction). - void preconditions() - { - precondition(this->input1.size() == this->input2.size()); - static_cast<E*>((void*)this)->preconditions_impl(); - } + namespace proc { - void impl_run() - { - mlc::eq<oln_type_of(I, size), oln_type_of(N, size)>::ensure(); + // FIXME: ... - I output; - output = utils::clone(this->input1); - bool non_stability = true; - while (non_stability) - { - work.unbox() = utils::clone(output); - for_all_p (fwd_p) - fwd_loop_body(); - for_all_p (bkd_p) - bkd_loop_body(); + } // end of namespace oln::morpho::proc - non_stability = !(level::is_equal(work, output)); - output = work.unbox(); - } - this->output = output; - } - protected: - reconstruction_sequential_ret(const abstract::image<I>& input1, //marker - const abstract::image<I>& input2, //mask - const abstract::neighborhood<N>& nbh) - : super_type(input1, input2, nbh), - fwd_p(input1.size()), - bkd_p(input1.size()) - { - se_plus = get_plus_se_p(convert::nbh_to_cse(this->nbh)); - se_minus = get_minus_se_p(convert::nbh_to_cse(this->nbh)); - } + template <typename I1, typename I2> + struct reconstruction_ret : + // FIXME: oln_super_of_ + public oln::internal::get_super_type< reconstruction_ret<I1,I2> >::ret + { + typedef reconstruction_ret<I1, I2> self_type; + typedef typename oln::internal::get_super_type<self_type>::ret super_type; - oln_type_of(N, window) se_plus; - oln_type_of(N, window) se_minus; - oln_type_of(I, fwd_piter) fwd_p; - oln_type_of(I, bkd_piter) bkd_p; - box<I> work; + box<const I1> marker; + box<const I2> mask; - }; + reconstruction_ret(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask) : + super_type(marker, mask), + marker(marker), + mask(mask) + { + } - template <typename I, typename N> - struct reconstruction_dilation_ret : - public reconstruction_sequential_ret<I, N, reconstruction_dilation_ret<I, N> > - { - typedef reconstruction_sequential_ret<I, N, reconstruction_dilation_ret<I, N> > super_type; + const oln_type_of(I1, neighb)& impl_nbh_get() const + { + return marker.nbh_get(); + } - reconstruction_dilation_ret(const abstract::image<I>& input1, //marker - const abstract::image<I>& input2, //mask - const abstract::neighborhood<N>& nbh) + }; - : super_type(input1, input2, nbh) - {} + } // end of namespace morpho - void fwd_loop_body_impl() - { - this->work[this->fwd_p] = ntg::min(morpho::max(this->work.unbox(), - this->fwd_p, - this->se_plus), - this->input2[this->fwd_p].value()); - } +} // end of namespace oln - void bkd_loop_body_impl() - { - this->work[this->bkd_p] = ntg::min(morpho::max(this->work.unbox(), - this->bkd_p, - this->se_minus), - this->input2[this->bkd_p].value()); - } +# include <oln/morpho/reconstruction_canvas.inc> - void preconditions_impl() - { - precondition(level::is_greater_or_equal(this->input2, this->input1)); - } +namespace oln { - }; + namespace morpho { + namespace impl { - template <typename I, typename N> - struct reconstruction_erosion_ret : - public reconstruction_sequential_ret<I, N, reconstruction_erosion_ret<I, N> > - { - typedef reconstruction_sequential_ret<I, N, reconstruction_erosion_ret<I, N> > super_type; + template<typename Op, typename A, typename I1, typename I2> + struct generic_reconstruction; - reconstruction_erosion_ret(const abstract::image<I>& input1, //marker - const abstract::image<I>& input2, //mask - const abstract::neighborhood<N>& nbh) + } // end of namespace impl - : super_type(input1, input2, nbh) - {} + } // end of namespace morpho - void fwd_loop_body_impl() - { - this->work[this->fwd_p] = ntg::max(morpho::min(this->work.unbox(), - this->fwd_p, - this->se_plus), - this->input2[this->fwd_p].value()); - } +} // end of namespace oln - void bkd_loop_body_impl() - { - this->work[this->bkd_p] = ntg::max(morpho::min(this->work.unbox(), - this->bkd_p, - this->se_minus), - this->input2[this->bkd_p].value()); - } +# include <oln/morpho/reconstruction_by_dilation.inc> +# include <oln/morpho/reconstruction_by_erosion.inc> - void preconditions_impl() - { - precondition(level::is_greater_or_equal(this->input1, this->input2)); - } +namespace oln { - }; + namespace morpho { - } + namespace impl { - template<class I, class N> - reconstruction_ret<I, N> - geodesic_reconstruction_dilation(const abstract::image<I> & marker, - const abstract::image<I> & mask, - const abstract::neighborhood<N>& nbh) - { - impl::reconstruction_dilation_ret<I, N> tmp(marker, mask, nbh); - tmp.run(); - return tmp; - } + // Generic implementation of reconstruction (routine). - template<class I, class N> - reconstruction_ret<I, N> - geodesic_reconstruction_erosion(const abstract::image<I> & marker, - const abstract::image<I> & mask, - const abstract::neighborhood<N>& nbh) + template<typename Op, typename A, typename I1, typename I2> + reconstruction_ret<I1,I2> + reconstruction(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask) { - impl::reconstruction_erosion_ret<I, N> tmp(marker, mask, nbh); + generic_reconstruction<Op, A, I1, I2> tmp(marker, mask); tmp.run(); return tmp; } - }// sequential + } // end of namespace impl + /// Generic reconstruction (facade). - namespace hybrid { + template<typename Op, typename I1, typename I2, typename A> + reconstruction_ret<I1,I2> + reconstruction(const tag::oper<Op>& oper_, + const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask, + const tag::algo<A>& algo_) + { + return impl::reconstruction<Op,A>(marker.exact(), mask.exact()); + } - namespace impl { + // by dilation - template <typename I, typename N, typename E> - struct reconstruction_hybrid_ret : public reconstruction_ret<I, N> - { - typedef reconstruction_ret<I, N> super_type; + template<typename I1, typename I2, typename A> + reconstruction_ret<I1,I2> + reconstruction_by_dilation(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask, + const tag::algo<A>& algo_) + { + mlc::eq<oln_type_of(I1, grid), oln_type_of(I2, grid)>::ensure(); + precondition(marker.size() == mask.size()); + return reconstruction(tag::by_dilation(), marker, mask, algo_); + } - bool exist_init() - { - // FIXME: to many changes => rewrite! -// typedef oln_type_of(N, window) se_type; -// oln_type_of(se_type, fwd_qiter) dp(se_minus); -// for_all (dp) -// { -// q = (oln_type_of(se_type, dpoint))dp + -// (oln_type_of(I, point))bkd_p; -// if (static_cast<E*>((void*)this)->exist_init_impl()) -// return true; -// } - return false; - } + template<typename I1, typename I2> + reconstruction_ret<I1,I2> + reconstruction_by_dilation(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask) + { + mlc::eq<oln_type_of(I1, grid), oln_type_of(I2, grid)>::ensure(); + precondition(marker.size() == mask.size()); + return reconstruction(tag::by_dilation(), marker, mask, tag::hybrid()); + } - void fwd_loop_body() - { - static_cast<E*>((void*)this)->fwd_loop_body_impl(); - } + // by erosion - void bkd_loop_body() - { - static_cast<E*>((void*)this)->bkd_loop_body_impl(); - } + template<typename I1, typename I2, typename A> + reconstruction_ret<I1,I2> + reconstruction_by_erosion(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask, + const tag::algo<A>& algo_) + { + mlc::eq<oln_type_of(I1, grid), oln_type_of(I2, grid)>::ensure(); + precondition(marker.size() == mask.size()); + return reconstruction(tag::by_erosion(), marker, mask, algo_); + } - void fifo_loop_body() - { - static_cast<E*>((void*)this)->fifo_loop_body_impl(); - } + template<typename I1, typename I2> + reconstruction_ret<I1,I2> + reconstruction_by_erosion(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask) + { + mlc::eq<oln_type_of(I1, grid), oln_type_of(I2, grid)>::ensure(); + precondition(marker.size() == mask.size()); + return reconstruction(tag::by_erosion(), marker, mask, tag::hybrid()); + } - void preconditions() - { - precondition(this->input1.size() == this->input2.size()); - static_cast<E*>((void*)this)->preconditions_impl(); - } + } // end of namespace oln::morpho - void impl_run() - { - mlc::eq<oln_type_of(I, size), oln_type_of(N, size)>::ensure(); - preconditions(); +} // end of namespace oln - this->output.unbox() = utils::clone(this->input1); - - for_all_p (fwd_p) - fwd_loop_body(); - - for_all_p (bkd_p) - { - bkd_loop_body(); - if (exist_init()) - fifo.push(bkd_p); - } - // Propagation Step - while (!fifo.empty()) - { - p = fifo.front(); - fifo.pop(); - // FIXME: AWFUL commented cause too many changes! -// typedef oln_type_of(N, window) window_type; -// window_type w = convert::nbh_to_se(this->nbh); -// oln_wn_type_of(window_type, fwd_iter) q(w); - -// for_all_q_of_p (q) -// { -// if (this->output.hold(q)) -// fifo_loop_body(); -// } - } - } - - protected: - - reconstruction_hybrid_ret(const abstract::image<I>& input1, //marker - const abstract::image<I>& input2, //mask - const abstract::neighborhood<N>& nbh) - - : super_type(input1, input2, nbh), - fwd_p(input1.size()), - bkd_p(input1.size()) - { - se_plus = get_plus_se_p(convert::nbh_to_cse(this->nbh)); - se_minus = get_minus_se_p(convert::nbh_to_cse(this->nbh)); - } - - oln_type_of(N, window) se_plus; - oln_type_of(N, window) se_minus; - oln_type_of(I, fwd_piter) fwd_p; - oln_type_of(I, bkd_piter) bkd_p; - oln_type_of(I, point) p; - oln_type_of(I, point) q; - std::queue<oln_type_of(I, point) > fifo; - - - }; - - - template <typename I, typename N> - struct reconstruction_dilation_ret : - public reconstruction_hybrid_ret<I, N, reconstruction_dilation_ret<I, N> > - { - typedef reconstruction_hybrid_ret<I, N, reconstruction_dilation_ret<I, N> > super_type; - - reconstruction_dilation_ret(const abstract::image<I>& input1, //marker - const abstract::image<I>& input2, //mask - const abstract::neighborhood<N>& nbh) - - : super_type(input1, input2, nbh) - {} - - void fwd_loop_body_impl() - { - this->output[this->fwd_p] = ntg::min(morpho::max(this->output.unbox(), - this->fwd_p, - this->se_plus), - this->input2[this->fwd_p].value()); - } - - void bkd_loop_body_impl() - { - this->output[this->bkd_p] = ntg::min(morpho::max(this->output.unbox(), - this->bkd_p, - this->se_minus), - this->input2[this->bkd_p].value()); - } - - void fifo_loop_body_impl() - { - if ((this->output[this->q] < this->output[this->p]) && - (this->input2[this->q] != this->output[this->q])) - { - this->output[this->q] = ntg::min(this->output[this->p].value(), - this->input2[this->q].value()); - this->fifo.push(this->q); - } - } - - bool exist_init_impl() - { - return this->output.hold(this->q) && - (this->output[this->q] < this->output[this->bkd_p]) && - (this->output[this->q] < this->input2[this->q]); - } - - void preconditions_impl() - { - precondition(level::is_greater_or_equal(this->input2, this->input1)); - } - - }; - - - - template <typename I, typename N> - struct reconstruction_erosion_ret : - public reconstruction_hybrid_ret<I, N, reconstruction_erosion_ret<I, N> > - { - typedef reconstruction_hybrid_ret<I, N, reconstruction_erosion_ret<I, N> > super_type; - - reconstruction_erosion_ret(const abstract::image<I>& input1, //marker - const abstract::image<I>& input2, //mask - const abstract::neighborhood<N>& nbh) - - : super_type(input1, input2, nbh) - {} - - void fwd_loop_body_impl() - { - this->output[this->fwd_p] = ntg::max(morpho::min(this->output.unbox(), - this->fwd_p, - this->se_plus), - this->input2[this->fwd_p].value()); - } - - void bkd_loop_body_impl() - { - this->output[this->bkd_p] = ntg::max(morpho::min(this->output.unbox(), - this->bkd_p, - this->se_minus), - this->input2[this->bkd_p].value()); - } - - void fifo_loop_body_impl() - { - if ((this->output[this->q] > this->output[this->p]) && - (this->input2[this->q] != this->output[this->q])) - { - this->output[this->q] = ntg::max(this->output[this->p].value(), - this->input2[this->q].value()); - this->fifo.push(this->q); - } - } - - bool exist_init_impl() - { - return this->output.hold(this->q) && - (this->output[this->q] > this->output[this->bkd_p]) && - (this->output[this->q] > this->input2[this->q]); - } - - void preconditions_impl() - { - precondition(level::is_greater_or_equal(this->input1, this->input2)); - } - - }; - - } - - template<class I, class N> - reconstruction_ret<I, N> - geodesic_reconstruction_dilation(const abstract::image<I> & marker, - const abstract::image<I> & mask, - const abstract::neighborhood<N>& nbh) - { - impl::reconstruction_dilation_ret<I, N> tmp(marker, mask, nbh); - tmp.run(); - return tmp; - } - - template<class I, class N> - reconstruction_ret<I, N> - geodesic_reconstruction_erosion(const abstract::image<I> & marker, - const abstract::image<I> & mask, - const abstract::neighborhood<N>& nbh) - { - impl::reconstruction_erosion_ret<I, N> tmp(marker, mask, nbh); - tmp.run(); - return tmp; - } - }// hybrid - - } - -} - #endif // ! OLENA_MORPHO_RECONSTRUCTION_HH Index: oln/morpho/splitse.hh --- oln/morpho/splitse.hh (revision 162) +++ oln/morpho/splitse.hh (working copy) @@ -34,6 +34,10 @@ # include <oln/core/2d/size2d.hh> # include <oln/core/3d/size3d.hh> +# include <oln/core/abstract/window.hh> +# include <oln/core/abstract/window.hh> + + namespace oln { namespace morpho { @@ -76,22 +80,21 @@ template<class W> W - get_plus_win_only(const abstract::window<W>& win) + get_plus_win_only(const W& win) // FIXME: abstract::window<W>& win) { - oln_wn_type_of(W, fwd_iter) q(win.exact()); W out; - // FIXME: too many changes: rewrite! -// for_all (q) -// { -// unsigned n; -// for (n = 0; n < dim_traits<oln_wn_type_of(W, size)>::dim; ++n) -// if (dp.nth(n) < 0) { -// out.add(dp); -// break; -// } else if (dp.nth(n) > 0) { -// break; -// } -// } + for (unsigned i = 0; i < win.card(); ++i) + { + const oln_wn_type_of(W, dpoint)& dp = win.get_dp()[i]; + unsigned n; + for (n = 0; n < dim_traits<oln_wn_type_of(W, size)>::dim; ++n) + if (dp.nth(n) < 0) { + out.add(dp); + break; + } else if (dp.nth(n) > 0) { + break; + } + } return out; } @@ -110,26 +113,24 @@ */ template<class W> W - get_plus_win_p(const abstract::window<W>& win) + get_plus_win_p(const W& win) // abstract::window<W>& win) { - oln_wn_type_of(W, fwd_iter) q(win.exact()); W out; - - // FIXME: too many changes: rewrite! -// for_all (dp) -// { -// unsigned n; -// for (n = 0; n < dim_traits<oln_wn_type_of(W, size)>::dim; ++n) -// if (dp.nth(n) < 0) { -// out.add(dp); -// break; -// } else if (dp.nth(n) > 0) { -// break; -// } -// // All p.nth(n) are 0. -// if (n == dim_traits<oln_wn_type_of(W, size)>::dim) -// out.add(dp); -// } + for (unsigned i = 0; i < win.card(); ++i) + { + const oln_wn_type_of(W, dpoint)& dp = win.get_dp()[i]; + unsigned n; + for (n = 0; n < dim_traits<oln_wn_type_of(W, size)>::dim; ++n) + if (dp.nth(n) < 0) { + out.add(dp); + break; + } else if (dp.nth(n) > 0) { + break; + } + // All p.nth(n) are 0. + if (n == dim_traits<oln_wn_type_of(W, size)>::dim) + out.add(dp); + } return out; } @@ -147,23 +148,21 @@ */ template<class W> W - get_minus_win_only(const abstract::window<W>& win) + get_minus_win_only(const W& win) // abstract::window<W>& win) { - oln_wn_type_of(W, fwd_iter) q(win.exact()); W out; - - // FIXME: too many changes: rewrite! -// for_all (dp) -// { -// unsigned n; -// for (n = 0; n < dim_traits<oln_wn_type_of(W, size)>::dim; ++n) -// if (dp.nth(n) > 0) { -// out.add(dp); -// break; -// } else if (dp.nth(n) < 0) { -// break; -// } -// } + for (unsigned i = 0; i < win.card(); ++i) + { + const oln_wn_type_of(W, dpoint)& dp = win.get_dp()[i]; + unsigned n; + for (n = 0; n < dim_traits<oln_wn_type_of(W, size)>::dim; ++n) + if (dp.nth(n) > 0) { + out.add(dp); + break; + } else if (dp.nth(n) < 0) { + break; + } + } return out; } @@ -182,26 +181,24 @@ */ template<class W> W - get_minus_win_p(const abstract::window<W>& win) + get_minus_win_p(const W& win) // abstract::window<W>& win) { - oln_wn_type_of(W, fwd_iter) q(win.exact()); W out; - - // FIXME: too many changes: rewrite! -// for_all (dp) -// { -// unsigned n; -// for (n = 0; n < dim_traits<oln_wn_type_of(W, size)>::dim; ++n) -// if (dp.nth(n) > 0) { -// out.add(dp); -// break; -// } else if (dp.nth(n) < 0) { -// break; -// } -// // All p.nth(n) are 0. -// if (n == dim_traits<oln_wn_type_of(W, size)>::dim) -// out.add(dp); -// } + for (unsigned i = 0; i < win.card(); ++i) + { + const oln_wn_type_of(W, dpoint)& dp = win.get_dp()[i]; + unsigned n; + for (n = 0; n < dim_traits<oln_wn_type_of(W, size)>::dim; ++n) + if (dp.nth(n) > 0) { + out.add(dp); + break; + } else if (dp.nth(n) < 0) { + break; + } + // All p.nth(n) are 0. + if (n == dim_traits<oln_wn_type_of(W, size)>::dim) + out.add(dp); + } return out; } Index: oln/morpho/reconstruction_by_erosion.inc --- oln/morpho/reconstruction_by_erosion.inc (revision 0) +++ oln/morpho/reconstruction_by_erosion.inc (revision 0) @@ -0,0 +1,141 @@ +// Copyright (C) 2005 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library 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 this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. +// +// As a special exception, you may use this filek as part of a free +// software library 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. + +namespace oln { + + namespace morpho { + + namespace impl { + + // Sequential version + + template<typename I1, typename I2> + struct generic_reconstruction <tag::by_erosion, tag::sequential, I1, I2> + : public generic_reconstruction_canvas<I1, I2, tag::sequential, + generic_reconstruction<tag::by_erosion, tag::sequential, I1, I2> > + { + typedef generic_reconstruction<tag::by_erosion, + tag::sequential, I1,I2> self_type; + typedef generic_reconstruction_canvas<I1, I2, tag::sequential, + self_type> super_type; + + generic_reconstruction(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask) : + super_type(marker, mask) + { + } + + + void impl_bkd_loop_body() + { + this->output[this->bkd_p] = ntg::max(morpho::min(this->output, + this->bkd_p, + this->win_minus), + this->mask[this->bkd_p].value()); + } + + void impl_fwd_loop_body() + { + this->output[this->fwd_p] = ntg::max(morpho::min(this->output, + this->fwd_p, + this->win_plus), + this->mask[this->fwd_p].value()); + } + + void impl_preconditions() + { + precondition(level::is_greater_or_equal(this->marker, this->mask)); + } + + }; + + // Hybrid version + + template<typename I1, typename I2> + struct generic_reconstruction <tag::by_erosion, tag::hybrid, I1, I2> + : public generic_reconstruction_canvas<I1, I2, tag::hybrid, + generic_reconstruction<tag::by_erosion, tag::hybrid, I1, I2> > + { + typedef generic_reconstruction<tag::by_erosion, + tag::hybrid, I1,I2> self_type; + typedef generic_reconstruction_canvas<I1, I2, tag::hybrid, + self_type> super_type; + + generic_reconstruction(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask) : + super_type(marker, mask) + { + } + + + + void impl_bkd_loop_body() + { + this->output[this->bkd_p] = ntg::max(morpho::min(this->work, + this->bkd_p, + this->win_minus), + this->mask[this->bkd_p].value()); + } + + void impl_fwd_loop_body() + { + this->output[this->fwd_p] = ntg::max(morpho::min(this->work, + this->fwd_p, + this->win_plus), + this->mask[this->fwd_p].value()); + } + + void impl_fifo_loop_body() + { + if ((this->output[this->q] > this->output[this->p]) && + (this->mask[this->q] != this->output[this->q])) + { + this->output[this->q] = ntg::min(this->output[this->p].value(), + this->mask[this->q].value()); + this->fifo.push(this->q); + } + } + + bool impl_exist_init() + { + return this->output.hold(this->q) && + (this->output[this->q] > this->output[this->bkd_p]) && + (this->output[this->q] > this->mask[this->q]); + } + + void impl_preconditions() + { + precondition(level::is_greater_or_equal(this->marker, this->mask)); + } + + }; + + } + + } + +} Index: oln/morpho/reconstruction_canvas.inc --- oln/morpho/reconstruction_canvas.inc (revision 0) +++ oln/morpho/reconstruction_canvas.inc (revision 0) @@ -0,0 +1,238 @@ +// Copyright (C) 2005 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library 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 this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. +// +// As a special exception, you may use this filek as part of a free +// software library 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. + + +namespace oln { + + namespace morpho { + + namespace impl { + + template <typename I1, typename I2, typename A, typename E> + struct generic_reconstruction_canvas; + + template <typename I1, typename I2, typename E> + struct generic_reconstruction_canvas<I1, I2, tag::sequential, E> : + public reconstruction_ret<I1, I2> + { + typedef reconstruction_ret<I1, I2> super_type; + typedef oln_type_of(I1, neighb) nbh_type; + typedef oln_type_of(I1, concrete) output_type; + + E& exact__() + { + return *(E*)(void*)(this); + } + + void bkd_loop_body() + { + this->exact__().impl_bkd_loop_body(); + } + void fwd_loop_body() + { + this->exact__().impl_fwd_loop_body(); + } + + void preconditions() + { + mlc::eq<oln_type_of(I1, grid), oln_type_of(I2, grid)>::ensure(); + precondition(this->marker.size() == this->mask.size()); + this->exact__().impl_preconditions(); + } + + void init() + { + // no call to impl_init here because this canvas can't be generalized yet. + this->output = utils::clone(this->marker); + this->work = utils::clone(this->marker); + + win_plus = get_plus_win_p(convert::nbh_to_cse(this->marker.nbh_get())); + win_minus = get_minus_win_p(convert::nbh_to_cse(this->marker.nbh_get())); + } + + bool is_stable() + { + // same explanation as above + return level::is_equal(this->work, this->output); + } + + void impl_run() + { + this->preconditions(); + this->init(); + for (;;) + { + for_all_p (fwd_p) + this->fwd_loop_body(); + for_all_p (bkd_p) + this->bkd_loop_body(); + if (this->is_stable()) + return; + work = utils::clone(this->output); + } + } + + protected: + + generic_reconstruction_canvas(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask) : + super_type(marker, mask), + bkd_p(marker.size()), + fwd_p(marker.size()) + { + } + + + oln_type_of(I1, bkd_piter) bkd_p; + oln_type_of(I1, fwd_piter) fwd_p; + + oln_nbh_type_of(nbh_type, window) win_plus; + oln_nbh_type_of(nbh_type, window) win_minus; + + box<oln_type_of(I1, concrete)> work; + }; + + template <typename I1, typename I2, typename E> + struct generic_reconstruction_canvas<I1, I2, tag::hybrid, E> : + public reconstruction_ret<I1, I2> + { + typedef reconstruction_ret<I1, I2> super_type; + typedef oln_type_of(I1, neighb) nbh_type; + typedef oln_nbh_type_of(nbh_type, window) window_type; + typedef oln_type_of(I1, concrete) output_type; + + E& exact__() + { + return *(E*)(void*)(this); + } + + + bool exist_init() + { + for (unsigned i = 0; i < win_minus.card(); ++i) + { + q = win_minus.get_dp()[i] + (oln_type_of(I1, point))bkd_p; + if (this->exact__().impl_exist_init()) + return true; + } + return false; + } + + void bkd_loop_body() + { + this->exact__().impl_bkd_loop_body(); + } + void fwd_loop_body() + { + this->exact__().impl_fwd_loop_body(); + } + + void fifo_loop_body() + { + this->exact__().impl_fifo_loop_body(); + } + + void preconditions() + { + mlc::eq<oln_type_of(I1, grid), oln_type_of(I2, grid)>::ensure(); + precondition(this->marker.size() == this->mask.size()); + this->exact__().impl_preconditions(); + } + + void init() + { + output_type tmp(this->marker.size()); + + this->output = tmp; + this->work = utils::clone(this->marker); + + win_plus = get_plus_win_p(convert::nbh_to_cse(this->marker.nbh_get())); + win_minus = get_minus_win_p(convert::nbh_to_cse(this->marker.nbh_get())); + } + + void impl_run() + { + this->preconditions(); + this->init(); + + for_all_p (fwd_p) + this->fwd_loop_body(); + + for_all_p (bkd_p) + { + bkd_loop_body(); + if (exist_init()) + fifo.push(bkd_p); + } + // Propagation Step + while (!fifo.empty()) + { + p = fifo.front(); + fifo.pop(); + + window_type win = convert::nbh_to_se(this->marker.nbh_get()); + for (unsigned i = 0; i < win.card(); ++i) + { + q = win.get_dp()[i] + p; + + if (this->output.hold(q)) + fifo_loop_body(); + } + } + } + + protected: + + generic_reconstruction_canvas(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask) : + super_type(marker, mask), + bkd_p(marker.size()), + fwd_p(marker.size()) + { + } + + + oln_type_of(I1, bkd_piter) bkd_p; + oln_type_of(I1, fwd_piter) fwd_p; + + oln_type_of(I1, point) p; + oln_type_of(I1, point) q; + + window_type win_plus; + window_type win_minus; + + box<oln_type_of(I1, concrete)> work; + + std::queue<oln_type_of(I1, point) > fifo; + + }; + + } // end of namespace impl + + } // end of namespace morpho + +} // end of namespace oln Index: oln/morpho/reconstruction_by_dilation.inc --- oln/morpho/reconstruction_by_dilation.inc (revision 0) +++ oln/morpho/reconstruction_by_dilation.inc (revision 0) @@ -0,0 +1,142 @@ +// Copyright (C) 2005 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library 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 this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. +// +// As a special exception, you may use this filek as part of a free +// software library 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. + +namespace oln { + + namespace morpho { + + namespace impl { + + // Sequential version + + template<typename I1, typename I2> + struct generic_reconstruction <tag::by_dilation, tag::sequential, I1, I2> + : public generic_reconstruction_canvas<I1, I2, tag::sequential, + generic_reconstruction<tag::by_dilation, tag::sequential, I1, I2> > + { + typedef generic_reconstruction<tag::by_dilation, + tag::sequential, I1,I2> self_type; + typedef generic_reconstruction_canvas<I1, I2, tag::sequential, + self_type> super_type; + + generic_reconstruction(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask) : + super_type(marker, mask) + { + } + + + void impl_bkd_loop_body() + { + this->output[this->bkd_p] = ntg::min(morpho::max(this->output, + this->bkd_p, + this->win_minus), + this->mask[this->bkd_p].value()); + } + + void impl_fwd_loop_body() + { + this->output[this->fwd_p] = ntg::min(morpho::max(this->output, + this->fwd_p, + this->win_plus), + this->mask[this->fwd_p].value()); + } + + void impl_preconditions() + { + precondition(level::is_greater_or_equal(this->mask, this->marker)); + } + + }; + + + // Hybrid version + + template<typename I1, typename I2> + struct generic_reconstruction <tag::by_dilation, tag::hybrid, I1, I2> + : public generic_reconstruction_canvas<I1, I2, tag::hybrid, + generic_reconstruction<tag::by_dilation, tag::hybrid, I1, I2> > + { + typedef generic_reconstruction<tag::by_dilation, + tag::hybrid, I1,I2> self_type; + typedef generic_reconstruction_canvas<I1, I2, tag::hybrid, + self_type> super_type; + + generic_reconstruction(const abstract::image_with_nbh<I1>& marker, + const abstract::image<I2>& mask) : + super_type(marker, mask) + { + } + + + + void impl_bkd_loop_body() + { + this->output[this->bkd_p] = ntg::min(morpho::max(this->work, + this->bkd_p, + this->win_minus), + this->mask[this->bkd_p].value()); + } + + void impl_fwd_loop_body() + { + this->output[this->fwd_p] = ntg::min(morpho::max(this->work, + this->fwd_p, + this->win_plus), + this->mask[this->fwd_p].value()); + } + + void impl_fifo_loop_body() + { + if ((this->output[this->q] < this->output[this->p]) && + (this->mask[this->q] != this->output[this->q])) + { + this->output[this->q] = ntg::min(this->output[this->p].value(), + this->mask[this->q].value()); + this->fifo.push(this->q); + } + } + + bool impl_exist_init() + { + return this->output.hold(this->q) && + (this->output[this->q] < this->output[this->bkd_p]) && + (this->output[this->q] < this->mask[this->q]); + } + + void impl_preconditions() + { + precondition(level::is_greater_or_equal(this->mask, this->marker)); + } + + }; + + } + + } + +} Index: img/marker.pbm Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: img/marker.pbm ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: img/mask.pbm Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: img/mask.pbm ___________________________________________________________________ Name: svn:mime-type + application/octet-stream