Index: ChangeLog
from Damien Thivolle <damien(a)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;
}
};