---
milena/mln/binarization/tmms_hysteresis.hh | 518 +++++++++++++++-------------
1 files changed, 284 insertions(+), 234 deletions(-)
diff --git a/milena/mln/binarization/tmms_hysteresis.hh
b/milena/mln/binarization/tmms_hysteresis.hh
index 64b5dbf..f80caf5 100644
--- a/milena/mln/binarization/tmms_hysteresis.hh
+++ b/milena/mln/binarization/tmms_hysteresis.hh
@@ -23,19 +23,20 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
-#ifndef MLN_BINARIZATION_TMMS_HH
-# define MLN_BINARIZATION_TMMS_HH
-
-# include <mln/morpho/all.hh>
-//# include <mln/labeling/values.hh>
-#include <mln/labeling/blobs.hh>
-
+#ifndef MLN_BINARIZATION_TMMS_HYSTERESIS_HH
+# define MLN_BINARIZATION_TMMS_HYSTERESIS_HH
/// \file
///
-/// \brief Binarization using TMMS algorithm (see "Text Segmentation
-/// in Natural Scenes Using Toggle-Mapping" from icip09 for more
-/// details) combined with hysteresis.
+/// \brief Binarization using TMMS algorithm combined with hysteresis.
+
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/window.hh>
+# include <mln/core/alias/neighb2d.hh>
+# include <mln/morpho/dilation.hh>
+# include <mln/morpho/erosion.hh>
+# include <mln/labeling/blobs.hh>
namespace mln
@@ -44,280 +45,329 @@ namespace mln
namespace binarization
{
- /**
- Binarize \p in_image by the use of TMMS algorithm (see "Text
- Segmentation in Natural Scenes Using Toggle-Mapping" from icip09
- for more details).
- \tparam image_in_ the input image (not modified by the algorithm.
+ /*!
+ Binarize \p input by the use of TMMS algorithm (see "Text
+ Segmentation in Natural Scenes Using Toggle-Mapping" from
+ icip09 for more details \cite fabrizio2009icip). This version
+ is combined with hysteresis.
+
+ \param[in] input the input image.
- \tparam struct_element the structuring element used to compute
- erosion and dilation of input image (During TMMS algorithm, input
- image is mapped over two fuctions: an erosion and a dilation of
- the input image).
+ \param[in] win the structuring element used to compute erosion
+ and dilation of input image (During TMMS algorithm, input image
+ is mapped over two fuctions: an erosion and a dilation of the
+ input image).
- \param c_min the min contrast allowed to extract feature.
+ \param[in] c_min the min contrast allowed to extract feature.
- \return an image with "foreground" marked with the highest
- possible color (hc), the "background" marked with the lower
- possible color (lc) and homogeneous regions of the image marked
- with the color (hc+lc)/2. (This will fail with two colors images,
- but it seems to be a bit stupid to try to binarize two color
- images?)
+ \return an image with "foreground" marked with the highest
+ possible color (hc), the "background" marked with the lowest
+ possible color (lc) and homogeneous regions of the image marked
+ with the color (hc+lc)/2. (This will fail with two colors
+ images, but it seems to be a bit stupid to try to binarize two
+ color images?)
- \author J. Fabrizio
- */
+ \author J. Fabrizio
+
+ \ingroup modroutines
+ */
template<typename I, typename W>
mln_concrete(I)
- tmms_hysteresis(const Image<I>& in_image_, const Window<W>&
struct_element,
- const mln_value(I)& c_min_low, const mln_value(I)& c_min_high,
- const mln_value(I)& min_level,
- const mln_value(I)& med_level,
- const mln_value(I)& max_level,
- const int pourcent);
+ tmms_hysteresis(const Image<I>& input_, const Window<W>& win,
+ const mln_value(I)& c_min_low,
+ const mln_value(I)& c_min_high,
+ const mln_value(I)& min_level,
+ const mln_value(I)& med_level,
+ const mln_value(I)& max_level,
+ const int pourcent);
+
# ifndef MLN_INCLUDE_ONLY
+ // Implementations
+
namespace impl
{
-
+
namespace generic
{
-
+
template<typename I, typename W>
mln_concrete(I)
- tmms_hysteresis(const Image<I>& in_image_, const Window<W>&
struct_element,
- const mln_value(I)& c_min_low, const mln_value(I)& c_min_high,
- const mln_value(I)& min_level,
- const mln_value(I)& med_level,
- const mln_value(I)& max_level,
- const int pourcent)
+ tmms_hysteresis(const Image<I>& input_, const Window<W>&
win_,
+ const mln_value(I)& c_min_low,
+ const mln_value(I)& c_min_high,
+ const mln_value(I)& min_level,
+ const mln_value(I)& med_level,
+ const mln_value(I)& max_level,
+ const int pourcent)
{
- mln_trace("binarization::tmms_hysteresis");
-
- const I& in_image = exact(in_image_);
+ mln_trace("mln::binarization::impl::generic::tmms_hysteresis");
- mln_concrete(I) low_image;
- mln_concrete(I) high_image;
+ const I& input = exact(input_);
+ const W& win = exact(win_);
- mln_concrete(I) dilation = mln::morpho::dilation(in_image, struct_element);
- mln_concrete(I) erosion = mln::morpho::erosion(in_image, struct_element);
+ mln_precondition(input.is_valid());
+ mln_precondition(win.is_valid());
- unsigned int nlabels;
+ typedef mln_value(I) V;
- mln_piter(I) p(in_image.domain());
+ mln_concrete(I) dilation = mln::morpho::dilation(input, win);
+ mln_concrete(I) erosion = mln::morpho::erosion(input, win);
- initialize(low_image, in_image);
- initialize(high_image, in_image);
+ mln_concrete(I) low_image;
+ initialize(low_image, input);
+ mln_concrete(I) high_image;
+ initialize(high_image, input);
- typedef mln_value(I) V;
+ mln_piter(I) p(input.domain());
for_all(p)
{
V dil = dilation(p); // by def : dil>=ima>=ero
V ero = erosion(p);
- V ima = in_image(p);
-
- if ((V)(dil - ero)<c_min_low) low_image(p) = high_image(p) = med_level;
- else if ((V)(dil - ero)<c_min_high) {
- low_image(p) = med_level;
- if ( (V)(dil - ima) < pourcent*((V)(dil - ero))/100 )
- high_image(p) = max_level;
- else
- high_image(p) = min_level;
- } else {
- if ( (V)(dil - ima) < pourcent*((V)(dil - ero))/100 )
- low_image(p) = high_image(p) = max_level;
- else
- low_image(p) = high_image(p) = min_level;
- }
+ V ima = input(p);
+
+ if ((V)(dil - ero) < c_min_low)
+ {
+ low_image(p) = med_level;
+ high_image(p) = med_level;
+ }
+ else if ((V)(dil - ero) < c_min_high)
+ {
+ low_image(p) = med_level;
+ if ((V)(dil - ima) < pourcent * ((V) (dil - ero)) / 100)
+ high_image(p) = max_level;
+ else
+ high_image(p) = min_level;
+ }
+ else
+ {
+ if ((V)(dil - ima) < pourcent * ((V)(dil - ero)) / 100)
+ {
+ low_image(p) = max_level;
+ high_image(p) = max_level;
+ }
+ else
+ {
+ low_image(p) = min_level;
+ high_image(p) = min_level;
+ }
+ }
}
- mln_ch_value(I, unsigned int) labels_high_images;
- //labels_high_images = mln::labeling::values(high_image, mln::c4(), nlabels);
- labels_high_images = mln::labeling::blobs(high_image, mln::c4(), nlabels);
- V *values = new V[nlabels];
+ unsigned nlabels;
+ mln_ch_value(I, unsigned)
+ labels_high_images = mln::labeling::blobs(high_image, mln::c4(), nlabels);
- for(unsigned int i=0;i<nlabels;i++) {
- values[i]=med_level;
- }
+ std::vector<V> values(nlabels + 1);
- for_all(p) {
- if (low_image(p)!=med_level) {
- values[labels_high_images(p)]=low_image(p);
- }
- }
+ for (unsigned i = 0; i <= nlabels ; i++)
+ values[i] = med_level;
- for_all(p) {
- if (low_image(p)==med_level) {
- low_image(p)=values[labels_high_images(p)];
- }
- }
- delete(values);
+ for_all(p)
+ if (low_image(p) != med_level)
+ values[labels_high_images(p)] = low_image(p);
+
+ for_all(p)
+ if (low_image(p) == med_level)
+ low_image(p) = values[labels_high_images(p)];
return low_image;
}
} // end of namespace mln::binarization::impl::generic
-
- template<typename I, typename W>
- mln_concrete(I)
- tmms_hysteresis_fastest(const Image<I>& in_image_, const
Window<W>& struct_element,
- const mln_value(I)& c_min_low, const mln_value(I)& c_min_high,
- const mln_value(I)& min_level,
- const mln_value(I)& med_level,
- const mln_value(I)& max_level,
- const int pourcent)
- {
- mln_trace("binarization::tmms_hysteresis");
-
- const I& in_image = exact(in_image_);
- mln_concrete(I) low_image;
- mln_concrete(I) high_image;
- mln_concrete(I) dilation = mln::morpho::dilation(in_image, struct_element);
- mln_concrete(I) erosion = mln::morpho::erosion(in_image, struct_element);
+ template<typename I, typename W>
+ mln_concrete(I)
+ tmms_hysteresis_fastest(const Image<I>& input_, const
Window<W>& win_,
+ const mln_value(I)& c_min_low, const mln_value(I)& c_min_high,
+ const mln_value(I)& min_level,
+ const mln_value(I)& med_level,
+ const mln_value(I)& max_level,
+ const int pourcent)
+ {
+ mln_trace("mln::binarization::impl::tmms_hysteresis_fastest");
+
+ const I& input = exact(input_);
+ const W& win = exact(win_);
+
+ mln_precondition(input.is_valid());
+ mln_precondition(win.is_valid());
+
+ typedef mln_value(I) V;
+
+ mln_concrete(I) dilation = mln::morpho::dilation(input, win);
+ mln_concrete(I) erosion = mln::morpho::erosion(input, win);
+
+ // Checking border sizes.
+ border::resize(dilation, input.border());
+ border::resize(erosion, input.border());
+ mln_assertion(input.border() == dilation.border());
+ mln_assertion(input.border() == erosion.border());
+
+ mln_concrete(I) low_image;
+ initialize(low_image, input);
+ mln_concrete(I) high_image;
+ initialize(high_image, input);
+
+ unsigned nrows = geom::nrows(input);
+ unsigned ncols = geom::ncols(input);
+ for (unsigned row = 0; row < nrows; ++row)
+ {
+ const V *p_input = &(input.at_(row, 0));
+ const V *p_dilation = &(dilation.at_(row, 0));
+ const V *p_erosion = &(erosion.at_(row, 0));
+ V *p_low_image = &(low_image.at_(row, 0));
+ V *p_high_image = &(high_image.at_(row, 0));
+
+ for (unsigned col = 0; col < ncols; ++col)
+ {
+ V dil = *p_dilation; // by def : dil>=ima>=ero
+ V ero = *p_erosion;
+ V ima = *p_input;
+
+ if ((V)(dil - ero) < c_min_low)
+ {
+ *p_low_image = med_level;
+ *p_high_image = med_level;
+ }
+ else if ((V)(dil - ero) < c_min_high)
+ {
+ *p_low_image = med_level;
+
+ if ((V)(dil - ima) < (V)(pourcent * (dil - ero) / 100))
+ *p_high_image = max_level;
+ else
+ *p_high_image = min_level;
+ }
+ else
+ {
+ if ((V)(dil - ima) < (V)(pourcent * (dil - ero) / 100))
+ {
+ *p_low_image = max_level;
+ *p_high_image = max_level;
+ }
+ else
+ {
+ *p_low_image = min_level;
+ *p_high_image = min_level;
+ }
+ }
+
+ ++p_input;
+ ++p_dilation;
+ ++p_erosion;
+ ++p_low_image;
+ ++p_high_image;
+ }
+ }
+
+ unsigned nlabels;
+ mln_ch_value(I, unsigned)
+ labels_high_images = mln::labeling::blobs(high_image, c4(), nlabels);
+
+ std::vector<V> values(nlabels + 1);
+
+ for(unsigned i = 0; i <= nlabels; ++i)
+ values[i] = med_level;
+
+ mln_piter(I) p(input.domain());
+ for_all(p)
+ if (low_image(p) != med_level)
+ values[labels_high_images(p)] = low_image(p);
+
+ for_all(p)
+ if (low_image(p) == med_level)
+ low_image(p) = values[labels_high_images(p)];
+
+ return low_image;
+ }
- unsigned int nlabels;
+ }// end of namespace mln::binarization::impl
- initialize(low_image, in_image);
- initialize(high_image, in_image);
- border::resize(dilation, in_image.border());
- border::resize(erosion, in_image.border());
- if (in_image.border()!=dilation.border() ||
- in_image.border()!=erosion.border())
- {
- std::abort();
- }
-
- typedef mln_value(I) V;
-
- unsigned nrows = geom::nrows(in_image);
- unsigned ncols = geom::ncols(in_image);
- for (unsigned row = 0; row < nrows; row += 1)
- {
- const V *p_in_image=&(in_image.at_(row, 0));
- const V *p_dilation=&(dilation.at_(row, 0));
- const V *p_erosion=&(erosion.at_(row, 0));
- V *p_low_image=&(low_image.at_(row, 0));
- V *p_high_image=&(high_image.at_(row, 0));
-
- for (unsigned col = 0; col < ncols; col += 1)
- {
- V dil = *p_dilation; // by def : dil>=ima>=ero
- V ero = *p_erosion;
- V ima = *p_in_image;
-
- if ((V)(dil - ero)<c_min_low) (*p_low_image) = (*p_high_image) =
med_level;
- else if ((V)(dil - ero)<c_min_high) {
- (*p_low_image) = med_level;
- if ( (V)(dil - ima) < pourcent*((V)(dil - ero))/100 )
- (*p_high_image) = max_level;
- else
- (*p_high_image) = min_level;
- } else {
- if ( (V)(dil - ima) < pourcent*((V)(dil - ero))/100 )
- (*p_low_image) = (*p_high_image) = max_level;
- else
- (*p_low_image) = (*p_high_image) = min_level;
- }
- p_in_image++;
- p_dilation++;
- p_erosion++;
- p_low_image++;
- p_high_image++;
- }
- }
+ // Dispatch
- mln_ch_value(I, unsigned int) labels_high_images;
- //labels_high_images = mln::labeling::values(high_image, mln::c4(), nlabels);
- labels_high_images = mln::labeling::blobs(high_image, mln::c4(), nlabels);
- V *values = new V[nlabels];
+ namespace internal
+ {
- for(unsigned int i=0;i<nlabels;i++) {
- values[i]=med_level;
- }
+ template<typename I, typename W>
+ mln_concrete(I)
+ tmms_hysteresis_dispatch(const I& ima, const W& win,
+ const mln_value(I)& c_min_low,
+ const mln_value(I)& c_min_high,
+ const mln_value(I)& min_level,
+ const mln_value(I)& med_level,
+ const mln_value(I)& max_level,
+ const int pourcent, mln::trait::image::speed::any)
+ {
+ return impl::generic::tmms_hysteresis(ima, win,
+ c_min_low, c_min_high,
+ min_level, med_level,
+ max_level, pourcent);
+ }
+
+ template<typename I, typename W>
+ mln_concrete(I)
+ tmms_hysteresis_dispatch(const I& ima, const W& win,
+ const mln_value(I)& c_min_low,
+ const mln_value(I)& c_min_high,
+ const mln_value(I)& min_level,
+ const mln_value(I)& med_level,
+ const mln_value(I)& max_level,
+ const int pourcent, mln::trait::image::speed::fastest)
+ {
+ return impl::tmms_hysteresis_fastest(ima, win,
+ c_min_low, c_min_high,
+ min_level, med_level,
+ max_level, pourcent);
+ }
+
+ template<typename I, typename W>
+ mln_concrete(I)
+ tmms_hysteresis_dispatch(const I& ima, const W& win,
+ const mln_value(I)& c_min_low,
+ const mln_value(I)& c_min_high,
+ const mln_value(I)& min_level,
+ const mln_value(I)& med_level,
+ const mln_value(I)& max_level,
+ const int pourcent)
+ {
+ return tmms_hysteresis_dispatch(ima, win,
+ c_min_low, c_min_high,
+ min_level, med_level,
+ max_level, pourcent,
+ mln_trait_image_speed(I)());
+ }
- mln_piter(I) p(in_image.domain());
- for_all(p) {
- if (low_image(p)!=med_level) {
- values[labels_high_images(p)]=low_image(p);
- }
- }
+ } //end of namespace namespace mln::binarization::internal
- for_all(p) {
- if (low_image(p)==med_level) {
- low_image(p)=values[labels_high_images(p)];
- }
- }
- delete(values);
- return low_image;
- }
-
- }// end of namespace mln::binarization::impl
-
- namespace internal
- {
-
- template<typename I, typename W>
- mln_concrete(I)
- tmms_hysteresis_dispatch(const I& ima, const W& struct_element,
- const mln_value(I)& c_min_low, const mln_value(I)& c_min_high,
- const mln_value(I)& min_level, const mln_value(I)& med_level,
- const mln_value(I)& max_level,
- const int pourcent, mln::trait::image::speed::any)
- {
- return mln::binarization::impl::generic::tmms_hysteresis(ima,
- struct_element, c_min_low, c_min_high,
- min_level, med_level, max_level, pourcent);
- }
+ // Facade
- template<typename I, typename W>
- mln_concrete(I)
- tmms_hysteresis_dispatch(const I& ima, const W& struct_element,
- const mln_value(I)& c_min_low, const mln_value(I)& c_min_high,
- const mln_value(I)& min_level, const mln_value(I)& med_level,
- const mln_value(I)& max_level,
- const int pourcent, mln::trait::image::speed::fastest)
- {
- return mln::binarization::impl::tmms_hysteresis_fastest(ima,
- struct_element, c_min_low, c_min_high,
- min_level, med_level, max_level, pourcent);
- }
-
- template<typename I, typename W>
- mln_concrete(I)
- tmms_hysteresis_dispatch(const I& ima, const W& struct_element,
- const mln_value(I)& c_min_low, const mln_value(I)& c_min_high,
- const mln_value(I)& min_level, const mln_value(I)& med_level,
- const mln_value(I)& max_level,
- const int pourcent)
- {
- return tmms_hysteresis_dispatch(ima,
- struct_element, c_min_low, c_min_high,
- min_level, med_level, max_level, pourcent,
- mln_trait_image_speed(I)()
- );
- }
-
- } //end of namespace namespace mln::binarization::internal
-
template<typename I, typename W>
mln_concrete(I)
- tmms_hysteresis(const Image<I>& in_image_, const Window<W>&
struct_element,
- const mln_value(I)& c_min_low, const mln_value(I)& c_min_high,
- const mln_value(I)& min_level,
- const mln_value(I)& med_level,
- const mln_value(I)& max_level,
- const int pourcent)
+ tmms_hysteresis(const Image<I>& input_, const Window<W>& win_,
+ const mln_value(I)& c_min_low, const mln_value(I)& c_min_high,
+ const mln_value(I)& min_level,
+ const mln_value(I)& med_level,
+ const mln_value(I)& max_level,
+ const int pourcent)
{
- const I& ima = exact(in_image_);
- const W& win = exact(struct_element);
- return mln::binarization::internal::tmms_hysteresis_dispatch(ima,
- win, c_min_low, c_min_high,
- min_level, med_level, max_level, pourcent);
+ mln_trace("mln::binarization::tmms_hysteresis");
+
+ const I& input = exact(input_);
+ const W& win = exact(win_);
+
+ mln_precondition(input.is_valid());
+ mln_precondition(win.is_valid());
+
+ return internal::tmms_hysteresis_dispatch(input, win,
+ c_min_low, c_min_high,
+ min_level, med_level,
+ max_level, pourcent);
}
# endif // ! MLN_INCLUDE_ONLY
@@ -327,4 +377,4 @@ namespace mln
} // end of namespace mln
-#endif // ! MLN_BINARIZATION_TMMS_HH
+#endif // ! MLN_BINARIZATION_TMMS_HYSTERESIS_HH
--
1.7.2.5