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(a)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(a)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