proto-1.0 115: Reconstruction code factorization

Index: ChangeLog from Damien Thivolle <damien@lrde.epita.fr> * oln/convert/ng_to_se.hh: Remove. * oln/convert/nbh_to_se.hh: New. * oln/core/abstract/internal/image_impl.hh: Add missing inclusion. * oln/makefile.src: Commit name change for ng_to_se.hh. * oln/morpho/reconstruction.hh: Factor code. * oln/morpho/cc_tarjan.hh: Conform to mlc macros. * oln/arith/min.hh: Conform to image_operator. * oln/arith/max.hh: Conform to image_operator. arith/max.hh | 23 - arith/min.hh | 23 - convert/nbh_to_se.hh | 22 - convert/ng_to_se.hh | 88 ---- core/abstract/internal/image_impl.hh | 1 makefile.src | 2 morpho/cc_tarjan.hh | 33 - morpho/reconstruction.hh | 650 ++++++++++++----------------------- 8 files changed, 282 insertions(+), 560 deletions(-) Index: oln/convert/ng_to_se.hh --- oln/convert/ng_to_se.hh (revision 114) +++ oln/convert/ng_to_se.hh (working copy) @@ -1,88 +0,0 @@ -// Copyright (C) 2002, 2004, 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 file 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. - -#ifndef OLENA_CONVERT_NG_TO_SE_HH -# define OLENA_CONVERT_NG_TO_SE_HH - -# include <oln/basics.hh> - -// because of the internal function in this file -//# include <oln/basics1d.hh> -# include <oln/basics2d.hh> -//# include <oln/basics3d.hh> -//# include <oln/core/1d/neighborhood1d.hh> -# include <oln/core/2d/neighborhood2d.hh> -//# include <oln/core/3d/neighborhood3d.hh> - -namespace oln { - namespace convert { - /*! Convert a neighborhood to a window. - ** - ** \see ng_to_cse - */ - template<class N> - oln_type_of(N, window) - ng_to_se(const oln::abstract::neighborhood<N>& ng) - { - oln_type_of(N, window) output; - - for (unsigned i = 0; i < ng.card(); i++) - output.add(ng[i]); - return output; - } - - void dpoint_zero(dpoint2d& dp) - { - dp.row() = 0; - dp.col() = 0; - } - - /*! Convert a neighborhood to a window and add the center. - ** - ** \see ng_to_cs - */ - template<class N> - oln_type_of(N, window) - ng_to_cse(const oln::abstract::neighborhood<N>& ng) - { - oln_type_of(N, window) output; - - for (unsigned i = 0; i < ng.card(); i++) - output.add(ng[i]); - - oln_type_of(N, dpoint) zero; - dpoint_zero(zero); - output.add(zero); - return output; - } - - - } // convert -} // oln - - -#endif // OLENA_CONVERT_NG_TO_SE_HH Index: oln/convert/nbh_to_se.hh --- oln/convert/nbh_to_se.hh (revision 114) +++ oln/convert/nbh_to_se.hh (working copy) @@ -25,8 +25,8 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#ifndef OLENA_CONVERT_NG_TO_SE_HH -# define OLENA_CONVERT_NG_TO_SE_HH +#ifndef OLENA_CONVERT_NBH_TO_SE_HH +# define OLENA_CONVERT_NBH_TO_SE_HH # include <oln/basics.hh> @@ -42,16 +42,16 @@ namespace convert { /*! Convert a neighborhood to a window. ** - ** \see ng_to_cse + ** \see nbh_to_cse */ template<class N> oln_type_of(N, window) - ng_to_se(const oln::abstract::neighborhood<N>& ng) + nbh_to_se(const oln::abstract::neighborhood<N>& nbh) { oln_type_of(N, window) output; - for (unsigned i = 0; i < ng.card(); i++) - output.add(ng[i]); + for (unsigned i = 0; i < nbh.card(); i++) + output.add(nbh[i]); return output; } @@ -63,16 +63,16 @@ /*! Convert a neighborhood to a window and add the center. ** - ** \see ng_to_cs + ** \see nbh_to_cs */ template<class N> oln_type_of(N, window) - ng_to_cse(const oln::abstract::neighborhood<N>& ng) + nbh_to_cse(const oln::abstract::neighborhood<N>& nbh) { oln_type_of(N, window) output; - for (unsigned i = 0; i < ng.card(); i++) - output.add(ng[i]); + for (unsigned i = 0; i < nbh.card(); i++) + output.add(nbh[i]); oln_type_of(N, dpoint) zero; dpoint_zero(zero); @@ -85,4 +85,4 @@ } // oln -#endif // OLENA_CONVERT_NG_TO_SE_HH +#endif // OLENA_CONVERT_NBH_TO_SE_HH Index: oln/core/abstract/internal/image_impl.hh --- oln/core/abstract/internal/image_impl.hh (revision 114) +++ oln/core/abstract/internal/image_impl.hh (working copy) @@ -29,6 +29,7 @@ # define PROTO_OLN_CORE_ABSTRACT_INTERNAL_IMAGE_IMPL_HH # include <mlc/any.hh> +# include <mlc/types.hh> # include <oln/core/properties.hh> Index: oln/makefile.src --- oln/makefile.src (revision 114) +++ oln/makefile.src (working copy) @@ -14,7 +14,7 @@ basics3d.hh \ config/pconf.hh \ config/system.hh \ - convert/ng_to_se.hh \ + convert/nbh_to_se.hh \ convert/value_to_point.hh \ core/1d/array1d.hh \ core/1d/dpoint1d.hh \ Index: oln/morpho/reconstruction.hh --- oln/morpho/reconstruction.hh (revision 114) +++ oln/morpho/reconstruction.hh (working copy) @@ -30,15 +30,20 @@ # include <queue> -# include <mlc/contract.hh> # include <mlc/cmp.hh> +# include <mlc/contract.hh> -# include <oln/convert/ng_to_se.hh> -# include <oln/morpho/splitse.hh> -# include <oln/level/compare.hh> +# include <oln/convert/nbh_to_se.hh> + +# include <oln/core/abstract/image_operator.hh> # include <oln/core/abstract/neighborhood.hh> # include <oln/core/properties.hh> -# include <oln/core/abstract/image_operator.hh> + +# include <oln/level/compare.hh> + +# include <oln/morpho/splitse.hh> +# include <oln/morpho/stat.hh> + # include <oln/utils/clone.hh> // FIXME: ADD TESTS !!!! @@ -73,80 +78,35 @@ { typedef abstract::image_binary_operator<I, I, I, reconstruction_ret<I, N> > super_type; - const N ng; + const N nbh; reconstruction_ret(const abstract::non_vectorial_image<I>& input1, const abstract::non_vectorial_image<I>& input2, - const abstract::neighborhood<N>& ng) : + const abstract::neighborhood<N>& nbh) : super_type(input1.exact(), input2.exact()), - ng(ng.exact()) + nbh(nbh.exact()) {} }; namespace sequential { - /*! - ** \brief Perform a geodesic reconstruction dilation. - ** - ** Compute the reconstruction by dilation of marker with respect - ** to the mask image using se as structuring element. Soille - ** p.160. The algorithm used is the one defined as sequential in - ** Vincent(1993), Morphological grayscale reconstruction in - ** image analysis: applications and efficient algorithms, itip, - ** 2(2), 176--201. - ** - ** \pre Mask must be greater or equal than marker. - ** - ** \param I1 Exact type of image marker. - ** \param I2 Exact type of image mask. - ** \param N Exact type of neighborhood. - ** - ** \arg marker Image to work on. - ** \arg mask Image used for geodesic dilation. - ** \arg Ng Neighborhood to use. - ** - ** \code - ** #include <oln/basics2d.hh> - ** #include <oln/morpho/opening.hh> - ** #include <oln/morpho/reconstruction.hh> - ** #include <oln/level/compare.hh> - ** #include <ntg/all.hh> - ** int main() - ** { - ** typedef oln::image2d<ntg::int_u8> im_type; - ** - ** im_type im1(oln::load(IMG_IN "lena128.pgm")); - ** im_type im2 = oln::morpho::opening(im1, oln::win_c4p()); - ** - ** oln::save(oln::morpho::sequential::geodesic_reconstruction_dilation(im2, - ** im1, - ** oln::neighb_c4()), - ** IMG_OUT "oln_morpho_sequential_geodesic_reconstruction_dilation.pbm"); - ** return 0; - ** } - ** \endcode - ** - ** \image html lena128_pgm.png - ** \image latex lena128_pgm.png - ** => - ** \image html oln_morpho_sequential_geodesic_reconstruction_dilation.png - ** \image latex oln_morpho_sequential_geodesic_reconstruction_dilation.png - ** - */ namespace impl { template <typename I, typename N> - struct reconstruction_dilation_ret : public reconstruction_ret<I, N> + struct reconstruction_sequential_ret : public reconstruction_ret<I, N> { typedef reconstruction_ret<I, N> super_type; - reconstruction_dilation_ret(const abstract::non_vectorial_image<I>& input1, //marker - const abstract::non_vectorial_image<I>& input2, //mask - const abstract::neighborhood<N>& ng) - : super_type(input1, input2, ng) - {} + virtual const oln_type_of(I, value) process(const I& work, + const oln_type_of(I, point)& p, + const oln_type_of(N, window)& se, + const oln_type_of(I, value)& v) + { + std::cerr << "oops in " << __func__ << std::endl; + return oln_type_of(I, value)(); + } void impl_run() { @@ -155,139 +115,153 @@ precondition(level::is_greater_or_equal(this->input2, this->input1)); // Conversion of neighborhood into a SE. - oln_type_of(N, window) se_plus = get_plus_se_p(convert::ng_to_cse(this->ng)); - oln_type_of(N, window) se_minus = get_minus_se_p(convert::ng_to_cse(this->ng)); + oln_type_of(N, window) se_plus = get_plus_se_p(convert::nbh_to_cse(this->nbh)); + oln_type_of(N, window) se_minus = get_minus_se_p(convert::nbh_to_cse(this->nbh)); I output; output = utils::clone(this->input1); bool non_stability = true; oln_type_of(I, fwd_piter) fwd_p(output.size()); - oln_type_of(I, fwd_piter) bkd_p(output.size()); + oln_type_of(I, bkd_piter) bkd_p(output.size()); while (non_stability) { I work; work = utils::clone(output); for_all (fwd_p) - work[fwd_p] = ntg::min(morpho::max(work, fwd_p, se_plus), this->input2[fwd_p].value()); + work[fwd_p] = this->process(work, fwd_p, se_plus, this->input2[fwd_p].value()); for_all (bkd_p) - work[bkd_p] = ntg::min(morpho::max(work, bkd_p, se_minus), this->input2[bkd_p].value()); + work[bkd_p] = this->process(work, bkd_p, se_minus, this->input2[bkd_p].value()); + non_stability = !(level::is_equal(work, output)); output = work; } this->output = output; } + + protected: + reconstruction_sequential_ret(const abstract::non_vectorial_image<I>& input1, //marker + const abstract::non_vectorial_image<I>& input2, //mask + const abstract::neighborhood<N>& nbh) + : super_type(input1, input2, nbh) + {} + + }; + + template <typename I, typename N> + struct reconstruction_dilation_ret : public reconstruction_sequential_ret<I, N> + { + typedef reconstruction_sequential_ret<I, N> super_type; + + reconstruction_dilation_ret(const abstract::non_vectorial_image<I>& input1, //marker + const abstract::non_vectorial_image<I>& input2, //mask + const abstract::neighborhood<N>& nbh) + + : super_type(input1, input2, nbh) + {} + + const oln_type_of(I, value) process(const I& work, + const oln_type_of(I, point)& p, + const oln_type_of(N, window)& se, + const oln_type_of(I, value)& v) + { + return ntg::min(morpho::max(work, p, se), v); + } + + }; + + + template <typename I, typename N> + struct reconstruction_erosion_ret : public reconstruction_sequential_ret<I, N> + { + typedef reconstruction_sequential_ret<I, N> super_type; + + reconstruction_erosion_ret(const abstract::non_vectorial_image<I>& input1, //marker + const abstract::non_vectorial_image<I>& input2, //mask + const abstract::neighborhood<N>& nbh) + + : super_type(input1, input2, nbh) + {} + + const oln_type_of(I, value) process(const I& work, + const oln_type_of(I, point)& p, + const oln_type_of(N, window)& se, + const oln_type_of(I, value)& v) const + { + return ntg::max(morpho::min(work, p, se), v); + } + }; + } template<class I, class N> reconstruction_ret<I, N> geodesic_reconstruction_dilation(const abstract::non_vectorial_image<I> & marker, const abstract::non_vectorial_image<I> & mask, - const abstract::neighborhood<N>& ng) + const abstract::neighborhood<N>& nbh) { - impl::reconstruction_dilation_ret<I, N> tmp(marker, mask, ng); + 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::non_vectorial_image<I> & marker, + const abstract::non_vectorial_image<I> & mask, + const abstract::neighborhood<N>& nbh) + { + impl::reconstruction_erosion_ret<I, N> tmp(marker, mask, nbh); + tmp.run(); + return tmp; + } + }// sequential namespace hybrid { - namespace internal { - - /*! - ** \brief Check if it exists initialization for dilation. - ** - ** \arg p Point to consider. - ** \arg marker Image to work on. - ** \arg mask Image used as mask. - ** \arg Ng Neighborhood to use. - */ - template<class P, class I1, class I2, class E> inline - static bool - exist_init_dilation(const abstract::point<P>& p, - const abstract::non_vectorial_image<I1>& marker, - const abstract::non_vectorial_image<I2>& mask, - const abstract::struct_elt<E>& se) - { - oln_type_of(E, fwd_witer) dp(se.exact()); - for_all (dp) - { - P q = (oln_type_of(E, dpoint))dp + p.exact(); - if (marker.hold(q) && (marker[q] < marker[p.exact()]) && - (marker[q] < mask[q])) - return true; - } - return false; - } - - } //internal - - /*! - ** \brief Perform a geodesic reconstruction dilation. - ** - ** Compute the reconstruction by dilation of marker with - ** respect to the mask image using se as structuring - ** element. Soille p.160. The algorithm used is the one defined - ** as hybrid in Vincent(1993), Morphological grayscale - ** reconstruction in image analysis: applications and efficient - ** algorithms, itip, 2(2), 176--201. - ** - ** \pre Mask must be greater or equal than marker. - ** - ** \param I1 Exact type of image marker. - ** \param I2 Exact type of image mask. - ** \param N Exact type of neighborhood. - ** - ** \arg marker Image to work on. - ** \arg mask Image used for geodesic dilation. - ** \arg Ng Neighborhood to use. - ** - ** \code - ** #include <oln/basics2d.hh> - ** #include <oln/morpho/opening.hh> - ** #include <oln/morpho/reconstruction.hh> - ** #include <oln/level/compare.hh> - ** #include <ntg/all.hh> - ** int main() - ** { - ** typedef oln::image2d<ntg::int_u8> im_type; - ** - ** im_type im1(oln::load(IMG_IN "lena128.pgm")); - ** im_type im2 = oln::morpho::opening(im1, oln::win_c4p()); - ** - ** oln::save(oln::morpho::hybrid::geodesic_reconstruction_dilation(im2, - ** im1, - ** oln::neighb_c4()), - ** IMG_OUT "oln_morpho_hybrid_geodesic_reconstruction_dilation.pbm"); - ** return 0; - ** } - ** \endcode - ** - ** \image html lena128_pgm.png - ** \image latex lena128_pgm.png - ** => - ** \image html oln_morpho_hybrid_geodesic_reconstruction_dilation.png - ** \image latex oln_morpho_hybrid_geodesic_reconstruction_dilation.png - ** - */ - namespace impl { template <typename I, typename N> - struct reconstruction_dilation_ret : public reconstruction_ret<I, N> + struct reconstruction_hybrid_ret : public reconstruction_ret<I, N> { typedef reconstruction_ret<I, N> super_type; - reconstruction_dilation_ret(const abstract::non_vectorial_image<I>& input1, //marker - const abstract::non_vectorial_image<I>& input2, //mask - const abstract::neighborhood<N>& ng) + reconstruction_hybrid_ret(const abstract::non_vectorial_image<I>& input1, //marker + const abstract::non_vectorial_image<I>& input2, //mask + const abstract::neighborhood<N>& nbh) - : super_type(input1, input2, ng) + : super_type(input1, input2, nbh) {} + virtual const oln_type_of(I, value) process(const I& work, + const oln_type_of(I, point)& p, + const oln_type_of(N, window)& se, + const oln_type_of(I, value)& v) const + { + std::cerr << "oops in " << __func__ << std::endl; + return oln_type_of(I, value)(); + } + + virtual void loop_body(const oln_type_of(I, point)& p, + const oln_type_of(I, point)& q, + oln_type_of(I, concrete)& output, + std::queue<oln_type_of(I, point) >& fifo) + { + std::cerr << "oops in " << __func__ << std::endl; + } + + virtual bool exist_init(const oln_type_of(I, point)& p, + const oln_type_of(I, concrete)& output, + const oln_type_of(N, window)& se) const + { + std::cerr << "oops in " << __func__ << std::endl; + return true; + } + + void impl_run() { mlc::eq<oln_type_of(I, size), oln_type_of(N, size)>::ensure(); @@ -297,22 +271,19 @@ oln_type_of(I, concrete) output; output = utils::clone(this->input1); { - oln_type_of(N, window) se_plus = get_plus_se_p(convert::ng_to_cse(this->ng)); - oln_type_of(N, window) se_minus = get_minus_se_p(convert::ng_to_cse(this->ng)); + oln_type_of(N, window) se_plus = get_plus_se_p(convert::nbh_to_cse(this->nbh)); + oln_type_of(N, window) se_minus = get_minus_se_p(convert::nbh_to_cse(this->nbh)); oln_type_of(I, fwd_piter) fwd_p(output.size()); oln_type_of(I, fwd_piter) bkd_p(output.size()); for_all (fwd_p) - output[fwd_p] = ntg::min(morpho::max(output, fwd_p, se_plus), - this->input2[fwd_p].value()); + output[fwd_p] = this->process(output, fwd_p, se_plus, this->input2[fwd_p].value()); std::queue<oln_type_of(I, point) > fifo; for_all (bkd_p) { - output[bkd_p] = ntg::min(morpho::max(output, bkd_p, se_minus), - this->input2[bkd_p].value()); - if (internal::exist_init_dilation((oln_type_of(I, point))bkd_p, output, - this->input2, se_minus)) + output[bkd_p] = this->process(output, bkd_p, se_minus, this->input2[bkd_p].value()); + if (this->exist_init((oln_type_of(I, point))bkd_p, output, se_minus)) fifo.push(bkd_p); } // Propagation Step @@ -321,22 +292,13 @@ oln_type_of(I, point) p = fifo.front(); fifo.pop(); typedef oln_type_of(N, window) window_type; - window_type w = convert::ng_to_se(this->ng); + window_type w = convert::nbh_to_se(this->nbh); oln_type_of(window_type, fwd_witer) dp(w); for_all (dp) { oln_type_of(I, point) q = (oln_type_of(window_type, dpoint))dp + p; - if (output.hold(q)) - { - if ((output[q] < output[p]) && - (this->input2[q] != output[q])) - { - output[q] = ntg::min(output[p].value(), - this->input2[q].value()); - fifo.push(q); - } - } + this->loop_body(p, q, output, fifo); } } } @@ -344,294 +306,144 @@ } }; - } - template<class I, class N> - reconstruction_ret<I, N> - geodesic_reconstruction_dilation(const abstract::non_vectorial_image<I> & marker, - const abstract::non_vectorial_image<I> & mask, - const abstract::neighborhood<N>& ng) - { - impl::reconstruction_dilation_ret<I, N> tmp(marker, mask, ng); - tmp.run(); - return tmp; - } - }// hybrid - - - namespace sequential { - - /*! - ** \brief Perform a geodesic reconstruction erosion. - ** - ** Compute the reconstruction by erosion of marker with respect - ** to the mask image using se as structuring element. Soille - ** p.160. The algorithm used is the one defined as sequential - ** in Vincent(1993), Morphological grayscale reconstruction in - ** image analysis: applications and efficient algorithms, itip, - ** 2(2), 176--201. - ** - ** \pre Marker must be greater or equal than mask. - ** - ** \param I1 Exact type of image marker. - ** \param I2 Exact type of image mask. - ** \param N Exact type of neighborhood. - ** - ** \arg marker Image to work on. - ** \arg mask Image used for geodesic erosion. - ** \arg Ng Neighborhood to use. - ** - ** \code - ** #include <oln/basics2d.hh> - ** #include <oln/morpho/opening.hh> - ** #include <oln/morpho/reconstruction.hh> - ** #include <oln/level/compare.hh> - ** #include <ntg/all.hh> - ** int main() - ** { - ** typedef oln::image2d<ntg::int_u8> im_type; - ** - ** im_type im1(oln::load(IMG_IN "lena128.pgm")); - ** im_type im2 = oln::morpho::opening(im1, oln::win_c4p()); - ** - ** oln::save(oln::morpho::sequential::geodesic_reconstruction_erosion(im1, - ** im2, - ** oln::neighb_c4()), - ** IMG_OUT "oln_morpho_sequential_geodesic_reconstruction_erosion.pbm"); - ** return 0; - ** } - ** \endcode - ** - ** \image html lena128_pgm.png - ** \image latex lena128_pgm.png - ** => - ** \image html oln_morpho_sequential_geodesic_reconstruction_erosion.png - ** \image latex oln_morpho_sequential_geodesic_reconstruction_erosion.png - ** - */ - - - namespace impl { - template <typename I, typename N> - struct reconstruction_erosion_ret : public reconstruction_ret<I, N> + struct reconstruction_dilation_ret : public reconstruction_hybrid_ret<I, N> { - typedef reconstruction_ret<I, N> super_type; + typedef reconstruction_hybrid_ret<I, N> super_type; - reconstruction_erosion_ret(const abstract::non_vectorial_image<I>& input1, //marker + reconstruction_dilation_ret(const abstract::non_vectorial_image<I>& input1, //marker const abstract::non_vectorial_image<I>& input2, //mask - const abstract::neighborhood<N>& ng) + const abstract::neighborhood<N>& nbh) - : super_type(input1, input2, ng) + : super_type(input1, input2, nbh) {} - void impl_run() + const oln_type_of(I, value) process(const I& work, + const oln_type_of(I, point)& p, + const oln_type_of(N, window)& se, + const oln_type_of(I, value)& v) const { - mlc::eq<oln_type_of(I, size), oln_type_of(N, size)>::ensure(); - precondition(this->input1.size() == this->input2.size()); - precondition(level::is_greater_or_equal(this->input2, this->input1)); + return ntg::min(morpho::max(work, p, se), v); + } - // Conversion of neighborhood into a SE. - oln_type_of(N, window) se_plus = get_plus_se_p(convert::ng_to_cse(this->ng)); - oln_type_of(N, window) se_minus = get_minus_se_p(convert::ng_to_cse(this->ng)); - - I output; - output = utils::clone(this->input1); - bool non_stability = true; - oln_type_of(I, fwd_piter) fwd_p(output.size()); - oln_type_of(I, fwd_piter) bkd_p(output.size()); - while (non_stability) + virtual void loop_body(const oln_type_of(I, point)& p, + const oln_type_of(I, point)& q, + oln_type_of(I, concrete)& output, + std::queue<oln_type_of(I, point) >& fifo) + { + if (output.hold(q)) { - I work; - work = utils::clone(output); - for_all (fwd_p) - work[fwd_p] = ntg::max(morpho::min(work, fwd_p, se_plus), - this->input2[fwd_p].value()); - for_all (bkd_p) - work[bkd_p] = ntg::max(morpho::min(work, bkd_p, se_minus), - this->input2[bkd_p].value()); - non_stability = !(level::is_equal(work, output)); - output = work; + if ((output[q] < output[p]) && + (this->input2[q] != output[q])) + { + output[q] = ntg::min(output[p].value(), + this->input2[q].value()); + fifo.push(q); + } } - this->output = output; + } - }; - } - template<class I, class N> - reconstruction_ret<I, N> - geodesic_reconstruction_erosion(const abstract::non_vectorial_image<I> & marker, - const abstract::non_vectorial_image<I> & mask, - const abstract::neighborhood<N>& ng) - { - impl::reconstruction_erosion_ret<I, N> tmp(marker, mask, ng); - tmp.run(); - return tmp; - } + virtual bool exist_init(const oln_type_of(I, point)& p, + const oln_type_of(I, concrete)& marker, + const oln_type_of(N, window)& se) const + { + typedef oln_type_of(N, window) se_type; + oln_type_of(se_type, fwd_witer) dp(se); + for_all (dp) + { + oln_type_of(I, point) q = (oln_type_of(se_type, dpoint))dp + p; + if (marker.hold(q) && (marker[q] < marker[p]) && + (marker[q] < this->input2[q])) + return true; + } + return false; + } - } // sequential + }; - namespace hybrid { - namespace internal { - /*! - ** \brief Check if it exists initialization for erosion. - ** - ** \arg p Point to consider. - ** \arg marker Image to work on. - ** \arg mask Image used as mask. - ** \arg Ng Neighborhood to use. - */ - template<class P, class I1, class I2, class E> inline - static bool - exist_init_erosion(const abstract::point<P>& p, - const abstract::non_vectorial_image<I1>& marker, - const abstract::non_vectorial_image<I2>& mask, - const abstract::struct_elt<E>& se) - { - oln_type_of(E, fwd_witer) dp(se.exact()); - for_all (dp) - { - P q = (oln_type_of(E, dpoint))dp + p.exact(); - if (marker.hold(q) && (marker[q] > marker[p.exact()]) && - (marker[q] > mask[q])) - return true; - } - return false; - } - - } //internal - - /*! - ** \brief Perform a geodesic reconstruction erosion. - ** - ** Compute the reconstruction by erosion of marker with respect - ** to the mask mask image using se as structuring - ** element. Soille p.160. The algorithm used is the one defined - ** as hybrid in Vincent(1993), Morphological grayscale - ** reconstruction in image analysis: applications and efficient - ** algorithms, itip, 2(2), 176--201. - ** - ** \pre Marker must be greater or equal than mask. - ** - ** \param I1 Exact type of image marker. - ** \param I2 Exact type of image mask. - ** \param N Exact type of neighborhood. - ** - ** \arg marker Image to work on. - ** \arg mask Image used for geodesic erosion. - ** \arg Ng Neighborhood to use. - ** - ** \code - ** #include <oln/basics2d.hh> - ** #include <oln/morpho/opening.hh> - ** #include <oln/morpho/reconstruction.hh> - ** #include <oln/level/compare.hh> - ** #include <ntg/all.hh> - ** int main() - ** { - ** typedef oln::image2d<ntg::int_u8> im_type; - ** - ** im_type im1(oln::load(IMG_IN "lena128.pgm")); - ** im_type im2 = oln::morpho::opening(im1, oln::win_c4p()); - ** - ** oln::save(oln::morpho::hybrid::geodesic_reconstruction_erosion(im1, - ** im2, - ** oln::neighb_c4()), - ** IMG_OUT "oln_morpho_hybrid_geodesic_reconstruction_erosion.pbm"); - ** return 0; - ** } - ** \endcode - ** - ** \image html lena128_pgm.png - ** \image latex lena128_pgm.png - ** => - ** \image html oln_morpho_hybrid_geodesic_reconstruction_erosion.png - ** \image latex oln_morpho_hybrid_geodesic_reconstruction_erosion.png - ** - */ - - namespace impl { - template <typename I, typename N> - struct reconstruction_erosion_ret : public reconstruction_ret<I, N> + struct reconstruction_erosion_ret : public reconstruction_hybrid_ret<I, N> { - typedef reconstruction_ret<I, N> super_type; + typedef reconstruction_hybrid_ret<I, N> super_type; reconstruction_erosion_ret(const abstract::non_vectorial_image<I>& input1, //marker const abstract::non_vectorial_image<I>& input2, //mask - const abstract::neighborhood<N>& ng) + const abstract::neighborhood<N>& nbh) - : super_type(input1, input2, ng) + : super_type(input1, input2, nbh) {} - void impl_run() + const oln_type_of(I, value) process(const I& work, + const oln_type_of(I, point)& p, + const oln_type_of(N, window)& se, + const oln_type_of(I, value)& v) const { - mlc::eq<oln_type_of(I, size), oln_type_of(N, size)>::ensure(); - precondition(this->input1.size() == this->input2.size()); - precondition(level::is_greater_or_equal(this->input2, this->input1)); + return ntg::max(morpho::min(work, p, se), v); + } - oln_type_of(I, concrete) output; - output = utils::clone(this->input1); - { - oln_type_of(N, window) se_plus = get_plus_se_p(convert::ng_to_cse(this->ng)); - oln_type_of(N, window) se_minus = get_minus_se_p(convert::ng_to_cse(this->ng)); - oln_type_of(I, fwd_piter) fwd_p(output.size()); - oln_type_of(I, fwd_piter) bkd_p(output.size()); + virtual void loop_body(const oln_type_of(I, point)& p, + const oln_type_of(I, point)& q, + oln_type_of(I, concrete)& output, + std::queue<oln_type_of(I, point) >& fifo) + { + if (output.hold(q)) + { + if ((output[q] > output[p]) && + (this->input2[q] != output[q])) + { + output[q] = ntg::max(output[p].value(), + this->input2[q].value()); + fifo.push(q); + } + } + } - for_all (fwd_p) - output[fwd_p] = ntg::max(morpho::min(output, fwd_p, se_plus), - this->input2[fwd_p].value()); - std::queue<oln_type_of(I, point) > fifo; - for_all (bkd_p) - { - output[bkd_p] = ntg::max(morpho::min(output, bkd_p, se_minus), - this->input2[bkd_p].value()); - if (internal::exist_init_erosion((oln_type_of(I, point))bkd_p, output, - this->input2, se_minus)) - fifo.push(bkd_p); - } - // Propagation Step - while (!fifo.empty()) - { - oln_type_of(I, point) p = fifo.front(); - fifo.pop(); - typedef oln_type_of(N, window) window_type; - window_type w = convert::ng_to_se(this->ng); - oln_type_of(window_type, fwd_witer) dp(w); - - for_all (dp) - { - oln_type_of(I, point) q = (oln_type_of(window_type, dpoint))dp + p; - if (output.hold(q)) - { - if ((output[q] > output[p]) && - (this->input2[q] != output[q])) - { - output[q] = ntg::max(output[p].value(), - this->input2[q].value()); - fifo.push(q); - } - } - } - } - } - this->output = output; + virtual bool exist_init(const oln_type_of(I, point)& p, + const oln_type_of(I, concrete)& marker, + const oln_type_of(N, window)& se) const + { + typedef oln_type_of(N, window) se_type; + oln_type_of(se_type, fwd_witer) dp(se); + for_all (dp) + { + oln_type_of(I, point) q = (oln_type_of(se_type, dpoint))dp + p; + if (marker.hold(q) && (marker[q] > marker[p]) && + (marker[q] > this->input2[q])) + return true; + } + return false; } + }; + + } template<class I, class N> reconstruction_ret<I, N> + geodesic_reconstruction_dilation(const abstract::non_vectorial_image<I> & marker, + const abstract::non_vectorial_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::non_vectorial_image<I> & marker, const abstract::non_vectorial_image<I> & mask, - const abstract::neighborhood<N>& ng) + const abstract::neighborhood<N>& nbh) { - impl::reconstruction_erosion_ret<I, N> tmp(marker, mask, ng); + impl::reconstruction_erosion_ret<I, N> tmp(marker, mask, nbh); tmp.run(); return tmp; } Index: oln/morpho/cc_tarjan.hh --- oln/morpho/cc_tarjan.hh (revision 114) +++ oln/morpho/cc_tarjan.hh (working copy) @@ -53,7 +53,7 @@ // category template <typename T, typename I, typename E> - struct set_category< morpho::cc_tarjan_ret<T,I,E> > + struct set_category< morpho::cc_tarjan_ret<T,I,E> > { typedef category::image ret; }; // super_type @@ -61,7 +61,7 @@ struct set_super_type< morpho::cc_tarjan_ret<T,I,E> > { typedef abstract::image_unary_operator - <tmp_mute(I, T), I, morpho::cc_tarjan_ret<T, I, E> > + <tmp_mute(I, T), I, morpho::cc_tarjan_ret<T, I, E> > ret; }; @@ -69,24 +69,24 @@ namespace morpho { template <typename T, typename I, typename E> - struct cc_tarjan_ret + struct cc_tarjan_ret : public abstract::image_unary_operator <tmp_mute(I, T), I, cc_tarjan_ret<T, I, E> > { typedef abstract::image_unary_operator - <tmp_mute(I, T), I, cc_tarjan_ret<T, I, E> > + <tmp_mute(I, T), I, cc_tarjan_ret<T, I, E> > super_type; typedef typename super_type::output_type output_type; const E ng; - + cc_tarjan_ret(const abstract::image<I>& input, const abstract::neighborhood<E>& ng) : super_type(input), ng(ng.exact()) { } - + }; @@ -123,8 +123,8 @@ } } // end of misc namespace - + template <typename T, typename I, typename N> struct generic_cc_tarjan : public cc_tarjan_ret<T, I, N> { @@ -143,8 +143,7 @@ void impl_run() { - mlc::is_true<mlc::type::eq<oln_type_of(I, size), - oln_type_of(N, size)>::ret>::ensure(); + mlc::eq<oln_type_of(I, size), oln_type_of(N, size)>::ensure(); output_type tmp(this->input.size()); // FIXME: trick this->output = tmp; @@ -167,20 +166,20 @@ if (this->input[n]) do_union(n, p); } - } + } } void second_pass() { oln_type_of(I, fwd_piter) p(this->input.size()); - level::fill(output, 0); + level::fill(this->output, 0); ncomps = 0; for_all(p) if (this->input[p]) - { + { oln_type_of(I, point) q = parent[p]; // FIXME: test if ncomps > T::max() - output[p] = (q == p ? ++ncomps : output[q]); + this->output[p] = (q == p ? ++ncomps : this->output[q]); } } @@ -198,16 +197,16 @@ } return x; } - - void do_union(const oln_type_of(I, point)& n, + + void do_union(const oln_type_of(I, point)& n, const oln_type_of(I, point)& p) { oln_type_of(I, point) r = find_root(n); if (r != p) parent[r] = p; } - - + + }; } // end of namespace oln::morpho::impl Index: oln/arith/min.hh --- oln/arith/min.hh (revision 114) +++ oln/arith/min.hh (working copy) @@ -29,7 +29,8 @@ # define OLENA_ARITH_MIN_HH # include <oln/basics.hh> -# include <oln/core/abstract/op.hh> +# include <oln/core/abstract/image_operator.hh> + # include <ntg/all.hh> namespace oln { @@ -53,7 +54,7 @@ template <typename I> struct set_super_type< arith::impl::min_type<I> > { - typedef abstract::op<I, arith::impl::min_type<I> > ret; + typedef abstract::image_binary_operator<I, I, I, arith::impl::min_type<I> > ret; }; namespace arith { @@ -61,27 +62,25 @@ namespace impl { template <class I> - struct min_type : public abstract::op<I, min_type<I> > + struct min_type : public abstract::image_binary_operator<I, I, I, min_type<I> > { - box<const I> input1_; - box<const I> input2_; + typedef abstract::image_binary_operator<I, I, I, min_type<I> > super_type; min_type(const abstract::non_vectorial_image<I>& input1, const abstract::non_vectorial_image<I>& input2) : - input1_(input1.exact()), - input2_(input2.exact()) + super_type(input1.exact(), input2.exact()) {} void impl_run() { - precondition(input1_.size() == input2_.size()); - I output(input1_.size()); - oln_type_of(I, fwd_piter) p(input1_.size()); + precondition(this->input1.size() == this->input2.size()); + I output(this->input1.size()); + oln_type_of(I, fwd_piter) p(this->input1.size()); for_all(p) - output[p] = ntg::min(input1_[p].value(), input2_[p].value()); + output[p] = ntg::min(this->input1[p].value(), this->input2[p].value()); - this->image_ = output; + this->output = output; } }; Index: oln/arith/max.hh --- oln/arith/max.hh (revision 114) +++ oln/arith/max.hh (working copy) @@ -29,7 +29,8 @@ # define OLENA_ARITH_MAX_HH # include <oln/basics.hh> -# include <oln/core/abstract/op.hh> +# include <oln/core/abstract/image_operator.hh> + # include <ntg/all.hh> namespace oln { @@ -53,7 +54,7 @@ template <typename I> struct set_super_type< arith::impl::max_type<I> > { - typedef abstract::op<I, arith::impl::max_type<I> > ret; + typedef abstract::image_binary_operator<I, I, I, arith::impl::max_type<I> > ret; }; namespace arith { @@ -61,27 +62,25 @@ namespace impl { template <class I> - struct max_type : public abstract::op<I, max_type<I> > + struct max_type : public abstract::image_binary_operator<I, I, I, max_type<I> > { - box<const I> input1_; - box<const I> input2_; + typedef abstract::image_binary_operator<I, I, I, max_type<I> > super_type; max_type(const abstract::non_vectorial_image<I>& input1, const abstract::non_vectorial_image<I>& input2) : - input1_(input1.exact()), - input2_(input2.exact()) + super_type(input1.exact(), input2.exact()) {} void impl_run() { - precondition(input1_.size() == input2_.size()); - I output(input1_.size()); - oln_type_of(I, fwd_piter) p(input1_.size()); + precondition(this->input1.size() == this->input2.size()); + I output(this->input1.size()); + oln_type_of(I, fwd_piter) p(this->input1.size()); for_all(p) - output[p] = ntg::max(input1_[p].value(), input2_[p].value()); + output[p] = ntg::max(this->input1[p].value(), this->input2[p].value()); - this->image_ = output; + this->output = output; } };
participants (1)
-
Damien Thivolle