proto-1.0 236: Add hit-or-miss transform
ChangeLog | 30 +++++++++++ oln/core/1d/window1d.hh | 7 +- oln/core/2d/window2d.hh | 7 +- oln/core/3d/window3d.hh | 7 +- oln/core/abstract/window.hh | 15 ++++- oln/core/gen/regular_window.hh | 48 +++++++++++++++++- oln/funobj/invert.hh | 9 +++ oln/level/arith.hh | 3 - oln/level/invert.hh | 63 +++++++++++++++++++++++ oln/makefile.src | 2 oln/morpho/hit_or_miss.hh | 109 +++++++++++++++++++++++++++++++++++++++++ oln/morpho/thick_gradient.hh | 9 ++- tests/morpho/tests/hit_or_miss | 33 ++++++++++++ 13 files changed, 328 insertions(+), 14 deletions(-) Index: olena/ChangeLog from Roland Levillain <roland@lrde.epita.fr> Add hit-or-miss transform. * oln/morpho/hit_or_miss.hh: New file. * oln/core/2d/window1d.hh (window1d::add(const dpoint1d&)): Remove method. (window1d::add(coord_t)): New method. * oln/core/2d/window2d.hh (window2d::add(const dpoint2d&)): Remove method. (window2d::add(coord_t, coord_t)): New method. * oln/core/3d/window2d.hh (window3d::add(const dpoint3d&)): Remove method. (window3d::add(coord_t, coord_t, coord_t)): New method. * oln/core/abstract/window.hh (window::card, window::has): New abstract methods. * oln/core/gen/regular_window.hh (regular_window::card): Rename as... (regular_window::impl_card): ...this. (regular_window::impl_has, regular_window::add): New methods. (inter, uni): New functions. * tests/morpho/tests/hit_or_miss: New test. * oln/level/invert.hh: New file. * oln/funobj/invert.hh (invert::operator()(const value_box<V>&): New operator. * oln/morpho/thick_gradient.hh: Re-indent. * oln/makefile.src (OLN_DEP): Add level/invert.hh and morpho/hit_or_miss.hh. 2005-07-07 Roland Levillain <roland@lrde.epita.fr> Index: olena/tests/morpho/tests/hit_or_miss --- olena/tests/morpho/tests/hit_or_miss (révision 0) +++ olena/tests/morpho/tests/hit_or_miss (révision 0) @@ -0,0 +1,33 @@ + // -*- C++ -*- +#include "data.hh" +#include <oln/utils/md5.hh> + +#include <ntg/bin.hh> +#include <oln/io/read_image.hh> +#include <oln/basics2d.hh> +#include <oln/morpho/hit_or_miss.hh> + +using namespace oln; + +bool check() +{ + utils::key::value_type data_key[16] = + { 0x11, 0x78, 0x96, 0x7f, 0x20, 0xab, 0xb1, 0xad, + 0x3c, 0x39, 0xef, 0x56, 0xf0, 0x12, 0x59, 0x1 } ; + utils::key key(data_key); + + image2d<ntg::bin> ima; + ima = io::read(rdata("object.pbm")); + + oln::window2d win1; + win1 + .add(-3,-2).add(-3,-1).add(-3,0).add(-3,1).add(-3,2) + .add(-2,-1).add(-2,0).add(-2,1) + .add(-1,0); + oln::window2d win2 = -win1; + + if (utils::md5(morpho::hit_or_miss(ima, win1, win2)) != key) + return true; + + return false; +} Index: olena/oln/funobj/invert.hh --- olena/oln/funobj/invert.hh (révision 235) +++ olena/oln/funobj/invert.hh (copie de travail) @@ -36,6 +36,8 @@ namespace funobj { + // FIXME: funobj::invert should be turned into a f_::invert + // functor. struct invert { template <typename V> @@ -68,6 +70,13 @@ return ret; } + template <typename I> + typename value_box<I>::value_type + operator()(const value_box<I>& v) const + { + return operator()(v.value()); + } + invert() {} }; Index: olena/oln/core/abstract/window.hh --- olena/oln/core/abstract/window.hh (révision 235) +++ olena/oln/core/abstract/window.hh (copie de travail) @@ -98,14 +98,24 @@ struct window : public mlc::any<W> { public: + typedef oln_wn_type_of(W, dpoint) dpoint_type; const W operator-() const { return this->exact().impl_op_minus(); } - protected: + unsigned card() const + { + return this->exact().impl_card(); + } + + bool has (const dpoint_type& dp) const + { + return this->exact().impl_has(dp); + } + protected: window() {} @@ -113,10 +123,11 @@ { get_props<category::window, W>::ensure(); mlc_check_method_impl(W, const W, op_minus, , const); + mlc_check_method_impl(W, unsigned, card, , const); + mlc_check_method_impl(W, bool, has, const dpoint_type& , const); } }; - } // end of namespace oln::abstract } // end of namespace oln Index: olena/oln/core/1d/window1d.hh --- olena/oln/core/1d/window1d.hh (révision 235) +++ olena/oln/core/1d/window1d.hh (copie de travail) @@ -56,9 +56,12 @@ super_type(n, crd) {} - window1d& add(const dpoint1d& dp) + // Don't hide the add() method from the super class. + using super_type::add; + + window1d& add(coord_t index) { - this->add_(dp); + this->add_(dpoint1d(index)); return *this; } Index: olena/oln/core/2d/window2d.hh --- olena/oln/core/2d/window2d.hh (révision 235) +++ olena/oln/core/2d/window2d.hh (copie de travail) @@ -59,9 +59,12 @@ super_type(n, crd) {} - window2d& add(const dpoint2d& dp) + // Don't hide the add() method from the super class. + using super_type::add; + + window2d& add(coord_t row, coord_t col) { - this->add_(dp); + this->add_(dpoint2d(row, col)); return *this; } Index: olena/oln/core/3d/window3d.hh --- olena/oln/core/3d/window3d.hh (révision 235) +++ olena/oln/core/3d/window3d.hh (copie de travail) @@ -56,9 +56,12 @@ super_type(n, crd) {} - window3d& add(const dpoint3d& dp) + // Don't hide the add() method from the super class. + using super_type::add; + + window3d& add(coord_t slice, coord_t row, coord_t col) { - this->add_(dp); + this->add_(dpoint3d(slice, row, col)); return *this; } Index: olena/oln/core/gen/regular_window.hh --- olena/oln/core/gen/regular_window.hh (révision 235) +++ olena/oln/core/gen/regular_window.hh (copie de travail) @@ -86,7 +86,7 @@ return this->delta_; } - unsigned card() const + unsigned impl_card() const { return this->dp_.size(); } @@ -103,6 +103,17 @@ return this->dp_[i]; } + E& add(const dpoint_type& dp) + { + add_(dp); + return this->exact(); + } + + bool impl_has (const dpoint_type& dp) const + { + return std::find(dp_.begin(), dp_.end(), dp) != dp_.end(); + } + const E impl_op_minus() const { E tmp = this->exact(); // FIXME: use clone(?) @@ -268,8 +279,41 @@ } // end of namespace oln::abstract -} // end of namespace oln + /// Compute intersection between two regular windows. + template <typename G, typename E> + inline + E + inter(const abstract::regular_window<G, E>& lhs, + const abstract::regular_window<G, E>& rhs) + { + E win; + for (unsigned i = 0; i < lhs.card(); ++i) + if (rhs.has(lhs.dp(i))) + win.add(lhs.dp(i)); + for (unsigned j = 0; j < rhs.card(); ++j) + if (! win.has(rhs.dp(j)) && lhs.has(rhs.dp(j))) + win.add(rhs.dp(j)); + return win; + } + + /// Compute union between two regular windows. + template <typename G, typename E> + inline + E + uni(const abstract::regular_window<G, E>& lhs, + const abstract::regular_window<G, E>& rhs) + { + E win; + for (unsigned i = 0; i < lhs.card(); ++i) + win.add(lhs.dp(i)); + for (unsigned j = 0; j < rhs.card(); ++j) + if (! win.has(rhs.dp(j))) + win.add(rhs.dp(j)); + return win; + } + +} // end of namespace oln template<typename G, typename E> Index: olena/oln/makefile.src --- olena/oln/makefile.src (révision 235) +++ olena/oln/makefile.src (copie de travail) @@ -168,6 +168,7 @@ level/compare.hh \ level/extrema_components.hh \ level/fill.hh \ + level/invert.hh \ level/level_components.hh \ level/logic.hh \ \ @@ -179,6 +180,7 @@ morpho/geodesic_dilation.hh \ morpho/geodesic_erosion.hh \ morpho/gradient.hh \ + morpho/hit_or_miss.hh \ morpho/local.hh \ morpho/lower_completion.hh \ morpho/opening.hh \ Index: olena/oln/morpho/hit_or_miss.hh --- olena/oln/morpho/hit_or_miss.hh (révision 0) +++ olena/oln/morpho/hit_or_miss.hh (révision 0) @@ -0,0 +1,109 @@ +// Copyright (C) 2001, 2003, 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_MORPHO_HIT_OR_MISS_HH +# define OLENA_MORPHO_HIT_OR_MISS_HH + +# include <mlc/cmp.hh> + +# include <oln/utils/record.hh> +# include <oln/morpho/erosion.hh> +# include <oln/level/arith.hh> +# include <oln/level/invert.hh> + + +namespace oln { + + namespace morpho { + + namespace impl { + + /// Hit-or-miss transform using regular windows, checking that their + /// intersection is empty. + template<class I, class G, class W1, class W2> + oln_type_of(I, concrete) + hit_or_miss_(const abstract::image<I>& input, + const abstract::regular_window<G, W1>& win1, + const abstract::regular_window<G, W2>& win2) + { + precondition(inter(win1.exact(), win2.exact()).card() == 0); + entering("->generic_on_regular_window"); + registering(input, "input"); + + oln_type_of(I, concrete) output(input.size(), "output"); + output = level::min(erosion(input, win1), + erosion(level::invert(input), win2)); + + exiting("->generic_on_regular_window"); + return output; + } + + /// Hit-or-miss transform using non-regular windows. + template<class I, class W1, class W2> + oln_type_of(I, concrete) + hit_or_miss_(const abstract::image<I>& input, + const abstract::window<W1>& win1, + const abstract::window<W2>& win2) + { + entering("->generic_on_non_regular_window"); + registering(input, "input"); + + oln_type_of(I, concrete) output(input.size(), "output"); + output = level::min(erosion(input, win1), + erosion(level::invert(input), win2)); + + exiting("->generic_on_non_regular_window"); + return output; + } + + } // end of namespace oln::morpho::impl + + + /// Generic hit-or-miss transform (facade). + template<class I, class W1, class W2> + oln_type_of(I, concrete) + hit_or_miss(const abstract::image<I>& input, + const abstract::window<W1>& win1, + const abstract::window<W2>& win2) + { + mlc::eq<oln_type_of(I, grid), oln_wn_type_of(W1, grid)>::ensure(); + mlc::eq<oln_type_of(I, grid), oln_wn_type_of(W2, grid)>::ensure(); + entering("morpho::hit_or_miss"); + + oln_type_of(I, concrete) output("output"); + output = impl::hit_or_miss_(input, win1.exact(), win2.exact()); + + exiting("morpho::hit_or_miss"); + return output; + } + + } // end of namespace oln::morpho + +} // end of namespace oln + + +#endif // ! OLENA_MORPHO_HIT_OR_MISS_HH Index: olena/oln/morpho/thick_gradient.hh --- olena/oln/morpho/thick_gradient.hh (révision 235) +++ olena/oln/morpho/thick_gradient.hh (copie de travail) @@ -42,7 +42,8 @@ /// Beucher thick gradient. template<typename I, typename W> - oln_type_of(I, concrete) thick_gradient_beucher(const abstract::image<I>& input, + oln_type_of(I, concrete) + thick_gradient_beucher(const abstract::image<I>& input, const abstract::window<W>& win) { mlc::eq<oln_type_of(I, grid), oln_wn_type_of(W, grid)>::ensure(); @@ -63,7 +64,8 @@ /// Internal thick gradient. template<typename I, typename W> - oln_type_of(I, concrete) thick_gradient_internal(const abstract::image<I>& input, + oln_type_of(I, concrete) + thick_gradient_internal(const abstract::image<I>& input, const abstract::window<W>& win) { mlc::eq<oln_type_of(I, grid), oln_wn_type_of(W, grid)>::ensure(); @@ -83,7 +85,8 @@ /// External thick gradient. template<typename I, typename W> - oln_type_of(I, concrete) thick_gradient_external(const abstract::image<I>& input, + oln_type_of(I, concrete) + thick_gradient_external(const abstract::image<I>& input, const abstract::window<W>& win) { mlc::eq<oln_type_of(I, grid), oln_wn_type_of(W, grid)>::ensure(); Index: olena/oln/level/arith.hh --- olena/oln/level/arith.hh (révision 235) +++ olena/oln/level/arith.hh (copie de travail) @@ -218,7 +218,8 @@ return output; } - // Variant taking a conversion function in parameter. + // FIXME: Should we keep this? + /// Variant taking a conversion function in parameter. template <typename C, typename B, typename I1, typename I2> typename ch_value_type<I1, typename convoutput<C, B, typename arith_output<f_::minus_, I1, I2>::T>::ret>::ret minus (const convert::abstract::conversion<C, B>& conv, Index: olena/oln/level/invert.hh --- olena/oln/level/invert.hh (révision 0) +++ olena/oln/level/invert.hh (révision 0) @@ -0,0 +1,63 @@ +// 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 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_LEVEL_INVERT_HH +# define OLENA_LEVEL_INVERT_HH + +# include <oln/funobj/invert.hh> + +namespace oln +{ + + namespace level + { + + /// Invert the values of an image. + template <typename I> + oln_type_of(I, concrete) invert (const abstract::image<I>& input) + { + entering("level::invert"); + registering(input, "input"); + + // FIXME: funobj::invert should be turned into a f_::invert + // functor, and we should use apply() here. + funobj::invert f_invert; + oln_type_of(I, concrete) output(input.size(), "output"); + oln_type_of(I, piter) p(input.size()); + for_all_p (p) + output[p] = f_invert(input[p]); + + exiting("level::invert"); + return output; + } + + } // end of namespace oln::level + +} // end of namespace oln + + +#endif // ! OLENA_LEVEL_INVERT_HH
participants (1)
-
Roland Levillain