Index: ChangeLog
from Christophe Berger <christophe(a)lrde.epita.fr>
* olena/oln/core/gen/regular_window.hh: Make it compile.
* olena/oln/appli/astro/tree_coherence_check.hh: Fix type in comments.
* olena/oln/appli/astro/tree_statistics.hh: Fix typo in comments.
* olena/oln/appli/astro/graphical_interface/interface.pro: Add a dependency.
appli/astro/graphical_interface/interface.pro | 2 +-
appli/astro/tree_coherence_check.hh | 2 +-
appli/astro/tree_statistics.hh | 3 ++-
core/gen/regular_window.hh | 8 ++++----
4 files changed, 8 insertions(+), 7 deletions(-)
Index: olena/oln/appli/astro/tree_coherence_check.hh
--- olena/oln/appli/astro/tree_coherence_check.hh (revision 241)
+++ olena/oln/appli/astro/tree_coherence_check.hh (working copy)
@@ -146,7 +146,7 @@
** search for parent (par) of p
** ensure (p) is contained in children of (par)
** else
- ** // nothing, root parent of hitself
+ ** // nothing, root parent of itself
**
** \endcode
**
Index: olena/oln/appli/astro/graphical_interface/interface.pro
--- olena/oln/appli/astro/graphical_interface/interface.pro (revision 241)
+++ olena/oln/appli/astro/graphical_interface/interface.pro (working copy)
@@ -7,7 +7,7 @@
SOURCES += main.cc
-HEADERS += filterinterface.hh image_viewer.hh qtincludes.hh utils.hh ../../../canvas/tree.hh ../../../canvas/maxtree.hh
+HEADERS += filterinterface.hh image_viewer.hh qtincludes.hh utils.hh ../../../canvas/tree.hh ../../../canvas/maxtree.hh ../clean.hh
FORMS = visualization_window.ui
Index: olena/oln/appli/astro/tree_statistics.hh
--- olena/oln/appli/astro/tree_statistics.hh (revision 241)
+++ olena/oln/appli/astro/tree_statistics.hh (working copy)
@@ -131,7 +131,8 @@
**
** count <- 0
** for all points of input
- ** if p is global root or if p has a different value than his parent's value in input image
+ ** if p is global root or if p has a different value
+ ** than his parent's value in input image
** then increment count (p is a local root)
** at the end, return the count
**
Index: olena/oln/core/gen/regular_window.hh
--- olena/oln/core/gen/regular_window.hh (revision 241)
+++ olena/oln/core/gen/regular_window.hh (working copy)
@@ -137,7 +137,7 @@
{
E out;
- for (unsigned i = 0; i < card(); ++i)
+ for (unsigned i = 0; i < this->dp_.card(); ++i)
{
const dpoint_type& dp = dp_[i];
@@ -159,7 +159,7 @@
E out;
- for (unsigned i = 0; i < card(); ++i)
+ for (unsigned i = 0; i < this->dp_.card(); ++i)
{
const dpoint_type& dp = dp_[i];
@@ -186,7 +186,7 @@
{
E out;
- for (unsigned i = 0; i < card(); ++i)
+ for (unsigned i = 0; i < this->dp_.card(); ++i)
{
const dpoint_type& dp = dp_[i];
@@ -207,7 +207,7 @@
{
E out;
- for (unsigned i = 0; i < card(); ++i)
+ for (unsigned i = 0; i < this->dp_.card(); ++i)
{
const dpoint_type& dp = get_dp()[i];
ChangeLog | 10 ++
oln/morpho/hit_or_miss.hh | 14 +--
oln/morpho/top_hat.hh | 190 +++++++++++++++++++++++++++++++++++++++++++++
tests/morpho/tests/top_hat | 55 +++++++++++++
4 files changed, 262 insertions(+), 7 deletions(-)
Index: olena/ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Add top-hat operators.
* oln/morpho/top_hat.hh: New file.
* tests/morpho/tests/top_hat: New test.
* olena/oln/morpho/hit_or_miss.hh: Add missing Doxygen tags in
comments.
2005-07-08 Roland Levillain <roland(a)lrde.epita.fr>
Index: olena/tests/morpho/tests/top_hat
--- olena/tests/morpho/tests/top_hat (révision 0)
+++ olena/tests/morpho/tests/top_hat (révision 0)
@@ -0,0 +1,55 @@
+ // -*- C++ -*-
+#include "data.hh"
+#include <oln/utils/md5.hh>
+
+#include <ntg/int.hh>
+#include <oln/io/read_image.hh>
+#include <oln/basics2d.hh>
+#include <oln/morpho/top_hat.hh>
+
+using namespace oln;
+
+bool check()
+{
+ image2d<ntg::int_u8> ima;
+ ima = io::read(rdata("lena-small.pgm"));
+
+ // White top-hat.
+ utils::key::value_type data_key_wth[16] =
+ { 0x59, 0x93, 0x51, 0xde, 0x4, 0x43, 0xb8, 0x7e,
+ 0xf8, 0xf4, 0xd1, 0x7, 0x6c, 0x81, 0x2b, 0xb4 };
+ utils::key key_wth(data_key_wth);
+
+ if (utils::md5(morpho::white_top_hat(ima, win_c8p())) != key_wth)
+ return true;
+
+ // Black top-hat.
+ utils::key::value_type data_key_bth[16] =
+ {0x8e, 0xe6, 0x26, 0x8e, 0x80, 0x8d, 0xcc, 0x9e,
+ 0x35, 0x1e, 0xe5, 0x2b, 0x41, 0xb1, 0xde, 0x53 };
+ utils::key key_bth(data_key_bth);
+
+ if (utils::md5(morpho::black_top_hat(ima, win_c8p())) != key_bth)
+ return true;
+
+ // Self-complementary top-hat.
+ utils::key::value_type data_key_scth[16] =
+ { 0x50, 0xec, 0xca, 0x22, 0xce, 0xa4, 0x45, 0x32,
+ 0x52, 0x7b, 0x47, 0x4a, 0x4a, 0xe4, 0x8, 0x45 };
+ utils::key key_scth(data_key_scth);
+
+ if (utils::md5(morpho::self_complementary_top_hat(ima, win_c8p())) !=
+ key_scth)
+ return true;
+
+ // Top-hat contrast operator.
+ utils::key::value_type data_key_thco[16] =
+ { 0x6d, 0x4, 0x75, 0xf5, 0xb0, 0x79, 0xba, 0xe8,
+ 0x8e, 0x81, 0x69, 0x37, 0xf4, 0xbe, 0x27, 0x2d };
+ utils::key key_thco(data_key_thco);
+
+ if (utils::md5(morpho::top_hat_contrast_op(ima, win_c8p())) != key_thco)
+ return true;
+
+ return false;
+}
Index: olena/oln/morpho/hit_or_miss.hh
--- olena/oln/morpho/hit_or_miss.hh (révision 239)
+++ olena/oln/morpho/hit_or_miss.hh (copie de travail)
@@ -117,7 +117,7 @@
/*! \brief Perform an hit-or-miss opening.
- Compute the hit-or-miss opening of input by the composite
+ Compute the hit-or-miss opening of \a input by the composite
structuring element (win1, win2).
REF: Soille, 2nd ed., p.149.
@@ -153,7 +153,7 @@
/*! \brief Perform an hit-or-miss opening of background.
- Compute the hit-or-miss opening of the background of input by
+ Compute the hit-or-miss opening of the background of \a input by
the composite structuring element (win1, win2).
REF: Soille, 2nd ed., p.149.
@@ -189,7 +189,7 @@
/*! \brief Perform an hit-or-miss closing.
- Compute the hit-or-miss closing of input by the composite
+ Compute the hit-or-miss closing of \a input by the composite
structuring element (win1, win2). This is the dual
transformation of hit-or-miss opening with respect to set
complementation.
@@ -229,10 +229,10 @@
/*! \brief Perform an hit-or-miss closing of the background.
- Compute the hit-or-miss closing of the background of input by
- the composite structuring element (win1, win2). This is the
- dual transformation of hit-or-miss opening of the background
- with respect to set complementation.
+ Compute the hit-or-miss closing of the background of \a input
+ by the composite structuring element (win1, win2). This is
+ the dual transformation of hit-or-miss opening of the
+ background with respect to set complementation.
REF: Soille, 2nd ed., p.149.
Index: olena/oln/morpho/top_hat.hh
--- olena/oln/morpho/top_hat.hh (révision 0)
+++ olena/oln/morpho/top_hat.hh (révision 0)
@@ -0,0 +1,190 @@
+// 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_MORPHO_TOP_HAT_HH
+# define OLENA_MORPHO_TOP_HAT_HH
+
+# include <mlc/cmp.hh>
+
+# include <oln/utils/record.hh>
+# include <oln/morpho/opening.hh>
+# include <oln/morpho/closing.hh>
+# include <oln/morpho/temp.hh>
+# include <oln/level/arith.hh>
+
+// FIXME: More documentation (in particular, code snippets). See Olena
+// 0.10's doc.
+
+namespace oln {
+
+ namespace morpho {
+
+ /*! \brief Compute the white top-hat of an image (also called
+ top-hat by opening).
+
+ Compute white top-hat of \a input using \a win as structuring
+ element.
+
+ REF: Soille, 2nd ed., p.121.
+
+ \arg \c I exact type of the input image.
+ \arg \c W exact type of the first structuring element.
+
+ \param input image to process.
+ \param win structuring element. */
+ template<typename I, typename W>
+ oln_type_of(I, concrete)
+ white_top_hat(const abstract::image<I>& input,
+ const abstract::window<W>& win)
+ {
+ mlc::eq<oln_type_of(I, grid), oln_wn_type_of(W, grid)>::ensure();
+
+ entering("morpho::white_top_hat");
+ registering(input, "input");
+ oln_type_of(I, concrete) open("open"), output("output");
+
+ open = opening(input, win);
+ output = force_value_type_to<oln_type_of(I, concrete)>(input - open);
+
+ exiting("morpho::white_top_hat");
+ return output;
+ }
+
+ /*! \brief Compute the black top-hat of an image (also called
+ top-hat by closing).
+
+ Compute black top-hat of \a input using \a win as structuring
+ element.
+
+ REF: Soille, 2nd ed., p.122.
+
+ \arg \c I exact type of the input image.
+ \arg \c W exact type of the first structuring element.
+
+ \param input image to process.
+ \param win structuring element. */
+ template<typename I, typename W>
+ oln_type_of(I, concrete)
+ black_top_hat(const abstract::image<I>& input,
+ const abstract::window<W>& win)
+ {
+ mlc::eq<oln_type_of(I, grid), oln_wn_type_of(W, grid)>::ensure();
+
+ entering("morpho::black_top_hat");
+ registering(input, "input");
+ oln_type_of(I, concrete) close("close"), output("output");
+
+ close = closing(input, win);
+ output = force_value_type_to<oln_type_of(I, concrete)>(close - input);
+
+ exiting("morpho::black_top_hat");
+ return output;
+ }
+
+ /*! \brief Compute the self-complementary top-hat of an image.
+
+ Compute self-complementary top-hat of \a input using \a win as
+ structuring element.
+
+ REF: Soille, 2nd ed., p.122.
+
+ \arg \c I exact type of the input image.
+ \arg \c W exact type of the first structuring element.
+
+ \param input image to process.
+ \param win structuring element. */
+ template<typename I, typename W>
+ oln_type_of(I, concrete)
+ self_complementary_top_hat(const abstract::image<I>& input,
+ const abstract::window<W>& win)
+ {
+ mlc::eq<oln_type_of(I, grid), oln_wn_type_of(W, grid)>::ensure();
+
+ entering("morpho::self_complementary_top_hat");
+ registering(input, "input");
+ oln_type_of(I, concrete) close("close"), open("open"), output("output");
+
+ close = closing(input, win);
+ open = opening(input, win);
+ output = force_value_type_to<oln_type_of(I, concrete)>(close - open);
+
+ exiting("morpho::self_complementary_top_hat");
+ return output;
+ }
+
+ /*! \brief Top-hat contrast operator.
+
+ Enhance contrast of \a input by adding the white top-hat, then
+ subtracting the black top-hat to \a input. Top-hats are
+ computed using \win as structuring element.
+
+ REF: Soille, 2nd ed., p.126.
+
+ \arg \c I exact type of the input image.
+ \arg \c W exact type of the first structuring element.
+
+ \param input image to process.
+ \param win structuring element. */
+ template<typename I, typename W>
+ oln_type_of(I, concrete)
+ top_hat_contrast_op(const abstract::image<I>& input,
+ const abstract::window<W>& win)
+ {
+ mlc::eq<oln_type_of(I, grid), oln_wn_type_of(W, grid)>::ensure();
+
+ entering("morpho::top_hat_contrast_op");
+ registering(input, "input");
+ oln_type_of(I, concrete) wth("wth"), bth("bth"), output("output");
+
+ wth = white_top_hat(input, win);
+ bth = black_top_hat(input, win);
+ /* FIXME: A more efficient computation might be achieved using
+ this formula:
+
+ output =
+ force_value_type_to<oln_type_of(I, concrete)>
+ (3 * input + closing(input, win) - opening(input, win));
+
+ but we don't have the product of image with a literal yet in
+ Olena. */
+ /* FIXME: `force' is not necessary the preferred behavior.
+ Consider adding another facade to this operator, to let the
+ user choose another behavior (`bound', for example). See
+ Olena 0.10's oln/morpho/top_hat.inc. */
+ output =
+ force_value_type_to<oln_type_of(I, concrete)>(input + wth - bth);
+
+ exiting("morpho::top_hat_contrast_op");
+ return output;
+ }
+
+ } // end of namespace oln::morpho
+
+} // end of namespace oln
+
+
+#endif // ! OLENA_MORPHO_TOP_HAT_HH
Je ne suis pas sûr des définitions de hit_or_miss_closing et de
hit_or_miss_opening_bg (Soille est assez laconique là-dessus).
ChangeLog | 11 ++
oln/morpho/hit_or_miss.hh | 168 ++++++++++++++++++++++++++++++++-
tests/morpho/tests/hit_or_miss_closing | 43 ++++++++
tests/morpho/tests/hit_or_miss_opening | 43 ++++++++
4 files changed, 264 insertions(+), 1 deletion(-)
Index: olena/ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Add hit-or-miss opening/closing and hit-or-miss opening/closing of
the background.
* oln/morpho/hit_or_miss.hh: More documentation.
(hit_or_miss_opening, hit_or_miss_opening_bg)
(hit_or_miss_closing, hit_or_miss_closing_bg): New.
* tests/morpho/tests/hit_or_miss_opening,
* tests/morpho/tests/hit_or_miss_closing: New tests.
2005-07-08 Roland Levillain <roland(a)lrde.epita.fr>
Index: olena/tests/morpho/tests/hit_or_miss_closing
--- olena/tests/morpho/tests/hit_or_miss_closing (révision 0)
+++ olena/tests/morpho/tests/hit_or_miss_closing (révision 0)
@@ -0,0 +1,43 @@
+ // -*- 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_hom_closing[16] =
+ { 0x9d, 0x9d, 0xbb, 0xd7, 0x6b, 0x5, 0x38, 0x29,
+ 0x69, 0x6e, 0x30, 0xd4, 0x30, 0x99, 0x13, 0x29 };
+ utils::key key_hom_closing(data_key_hom_closing);
+
+ utils::key::value_type data_key_hom_closing_bg[16] =
+ { 0xfa, 0x7, 0x26, 0x34, 0x16, 0x36, 0xc, 0xf4,
+ 0x5e, 0x19, 0x53, 0xa2, 0x89, 0x1e, 0xdb, 0xae };
+ utils::key key_hom_closing_bg(data_key_hom_closing_bg);
+
+ 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_closing(ima, win1, win2)) !=
+ key_hom_closing)
+ return true;
+
+ if (utils::md5(morpho::hit_or_miss_closing_bg(ima, win1, win2)) !=
+ key_hom_closing_bg)
+ return true;
+
+ return false;
+}
Index: olena/tests/morpho/tests/hit_or_miss_opening
--- olena/tests/morpho/tests/hit_or_miss_opening (révision 0)
+++ olena/tests/morpho/tests/hit_or_miss_opening (révision 0)
@@ -0,0 +1,43 @@
+ // -*- 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_hom_opening[16] =
+ { 0x90, 0xda, 0x98, 0x5a, 0xef, 0x2e, 0x8d, 0x54,
+ 0xa5, 0x6, 0xd, 0x7a, 0x6f, 0x63, 0x55, 0x7 };
+ utils::key key_hom_opening(data_key_hom_opening);
+
+ utils::key::value_type data_key_hom_opening_bg[16] =
+ { 0xd6, 0x45, 0x11, 0xed, 0xdd, 0xf, 0x42, 0x59,
+ 0x95, 0x57, 0x4, 0x66, 0x59, 0x97, 0x6c, 0x8d };
+ utils::key key_hom_opening_bg(data_key_hom_opening_bg);
+
+ 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_opening(ima, win1, win2)) !=
+ key_hom_opening)
+ return true;
+
+ if (utils::md5(morpho::hit_or_miss_opening_bg(ima, win1, win2)) !=
+ key_hom_opening_bg)
+ return true;
+
+ return false;
+}
Index: olena/oln/morpho/hit_or_miss.hh
--- olena/oln/morpho/hit_or_miss.hh (révision 237)
+++ olena/oln/morpho/hit_or_miss.hh (copie de travail)
@@ -32,9 +32,12 @@
# include <oln/utils/record.hh>
# include <oln/morpho/erosion.hh>
+# include <oln/morpho/dilation.hh>
# include <oln/level/arith.hh>
# include <oln/level/invert.hh>
+// FIXME: More documentation (in particular, code snippets). See Olena
+// 0.10's doc.
namespace oln {
@@ -83,7 +86,17 @@
} // end of namespace oln::morpho::impl
- /// Generic hit-or-miss transform (facade).
+ /*! \brief Preform a hit-or-miss transform (generic facade)
+
+ REF: Soille, 2nd ed., p.140.
+
+ \arg \c I exact type of the input image.
+ \arg \c W1 exact type of the first structuring element.
+ \arg \c W2 exact type of the second structuring element.
+
+ \param input image to process.
+ \param win1 first structuring element.
+ \param win2 second structuring element. */
template<class I, class W1, class W2>
oln_type_of(I, concrete)
hit_or_miss(const abstract::image<I>& input,
@@ -101,6 +114,159 @@
return output;
}
+
+ /*! \brief Perform an hit-or-miss opening.
+
+ Compute the hit-or-miss opening of input by the composite
+ structuring element (win1, win2).
+
+ REF: Soille, 2nd ed., p.149.
+
+ By definition \a win1 and \a win2 must have the same origin,
+ and need to be disjoint. This algorithm has been extended to
+ every data types (althought it is not increasing). Beware the
+ result depends upon the image data type if it is not binary.
+
+ \arg \c I Exact type of the input image.
+ \arg \c W1 Exact type of the first structuring element.
+ \arg \c W2 Exact type of the second structuring element.
+
+ \param input image to process.
+ \param win1 first structuring element.
+ \param win2 second structuring element. */
+ template<class I, class W1, class W2>
+ oln_type_of(I, concrete)
+ hit_or_miss_opening(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_opening");
+
+ oln_type_of(I, concrete) output("output");
+ output = dilation(hit_or_miss(input, win1, win2), -win1);
+
+ exiting("morpho::hit_or_miss_opening");
+ return output;
+ }
+
+ /*! \brief Perform an hit-or-miss opening of background.
+
+ Compute the hit-or-miss opening of the background of input by
+ the composite structuring element (win1, win2).
+
+ REF: Soille, 2nd ed., p.149.
+
+ By definition win1 and win2 must have the same origin, and
+ need to be disjoint. This algorithm has been extended to
+ every data types (although it is not increasing). Beware the
+ result depends upon the image data type if it is not bin.
+
+ \arg \c I exact type of the input image.
+ \arg \c W1 exact type of the first structuring element.
+ \arg \c W2 exact type of the second structuring element.
+
+ \param input image to process.
+ \param win1 first structuring element.
+ \param win2 second structuring element. */
+ template<class I, class W1, class W2>
+ oln_type_of(I, concrete)
+ hit_or_miss_opening_bg(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_opening_bg");
+
+ oln_type_of(I, concrete) output("output");
+ output = dilation(hit_or_miss(input, win1, win2), -win2);
+
+ exiting("morpho::hit_or_miss_opening_bg");
+ return output;
+ }
+
+ /*! \brief Perform an hit-or-miss closing.
+
+ Compute the hit-or-miss closing of input by the composite
+ structuring element (win1, win2). This is the dual
+ transformation of hit-or-miss opening with respect to set
+ complementation.
+
+ REF: Soille, 2nd ed., p.149.
+
+ By definition \a win1 and \a win2 must have the same origin,
+ and need to be disjoint. This algorithm has been extended to
+ every data types (althought it is not increasing). Beware the
+ result depends upon the image data type if it is not binary.
+
+ \arg \c I Exact type of the input image.
+ \arg \c W1 Exact type of the first structuring element.
+ \arg \c W2 Exact type of the second structuring element.
+
+ \param input image to process.
+ \param win1 first structuring element.
+ \param win2 second structuring element. */
+ template<class I, class W1, class W2>
+ oln_type_of(I, concrete)
+ hit_or_miss_closing(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_closing");
+
+ oln_type_of(I, concrete) output("output");
+ // FIXME: Is this correct? Soille doesn't detail the definition
+ // of the hit-or-miss closing in his book.
+ output = hit_or_miss_opening(level::invert(input), win1, win2);
+
+ exiting("morpho::hit_or_miss_closing");
+ return output;
+ }
+
+ /*! \brief Perform an hit-or-miss closing of the background.
+
+ Compute the hit-or-miss closing of the background of input by
+ the composite structuring element (win1, win2). This is the
+ dual transformation of hit-or-miss opening of the background
+ with respect to set complementation.
+
+ REF: Soille, 2nd ed., p.149.
+
+ By definition \a win1 and \a win2 must have the same origin,
+ and need to be disjoint. This algorithm has been extended to
+ every data types (althought it is not increasing). Beware the
+ result depends upon the image data type if it is not binary.
+
+ \arg \c I Exact type of the input image.
+ \arg \c W1 Exact type of the first structuring element.
+ \arg \c W2 Exact type of the second structuring element.
+
+ \param input image to process.
+ \param win1 first structuring element.
+ \param win2 second structuring element. */
+ template<class I, class W1, class W2>
+ oln_type_of(I, concrete)
+ hit_or_miss_closing_bg(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_closing_bg");
+
+ oln_type_of(I, concrete) output("output");
+ // FIXME: Is this correct? Soille doesn't detail the definition
+ // of the hit-or-miss closing of the background in his book.
+ output = hit_or_miss_opening_bg(level::invert(input), win1, win2);
+
+ exiting("morpho::hit_or_miss_closing_bg");
+ return output;
+ }
+
} // end of namespace oln::morpho
} // end of namespace oln
2005-07-07 Thierry GERAUD <theo(a)tegucigalpa.lrde.epita.fr>
'set' and 'get' are now only for images; 'at' is for data
storage.
* oln/core/abstract/image_rawness.hh (at): Rename default impl
as...
(impl_at): ...this.
* oln/core/abstract/data_storage.hh (set,get): Remove methods
cause they were obsolete since 'at' has been introduced.
(OLNTRACE): Remove tracing since it is performed in image
classes.
* oln/core/abstract/image_with_data.hh (set,get): Replace by
'at'.
(impl_set): Move to a better place.
(impl_at): Add precondition.
* oln/core/apply.hh (record.hh): Add include.
* oln/core/1d/array1d.hh (impl_set,impl_set): Replace by...
(impl_at): ...this.
(impl_set_data): Remove cause useless.
* oln/core/2d/array2d.hh (impl_set,impl_set): Remove.
* oln/core/3d/array3d.hh (impl_set,impl_set): Remove.
(impl_set_data): Remove cause useless.
Factor data storage instanciations.
* oln/core/traits.hh: New file.
* oln/core/2d/image2d.hh: Remove dead code.
(value_storage_type): Rely on storage type traits.
Preparing a better overloading for classic operators.
* oln/utils/overload.hh: New file.
* oln/core/pw/macros.hh: Add explicit versions of macros where
operators are procedures.
* oln/core/pw/value.hh (value): Qualify explicitly inheritance
to prevent name conflicts.
* oln/core/pw/cmp.hh: Add room for explicit instanciation of
procedures.
Bug fixes.
* tests/morpho/tests/geodesic_erosion (exact): Remove.
* tests/morpho/tests/geodesic_dilation (exact): Remove.
* oln/core/box.hh (inc_ncalls): Qualify method names in strings.
* oln/core/1d/image1d.hh (operator=): New method.
* oln/core/3d/image3d.hh (operator=): New method.
* oln/utils/clone.hh: Fix end of namespace comment.
* oln/morpho/geodesic_erosion.hh (n): Fix default value
definition.
(work): Fix first assignment in bodies.
* oln/morpho/geodesic_dilation.hh: Likewise.
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
Développeuses, développeurs,
Étant donnée sa croissance et ses nombreuses nouvelles
fonctionnalités, il serait bon qu'Olena commence à avoir une vraie
test-suite. Je pense que travailler sur les tests en dehors du travail
de développement est assez fastidieux, aussi je vous encourage à les
mener en parallèle de vos modifications dans Olena.
Par cela, j'entends donc :
1. au minimum, lancer des sanity-checks régulièrement, et corriger le
code fautif le cas échéant (avant de commettre) ;
2. commencer à corriger les tests qui ne marchent pas (ceux qui sont
exécutés via `make check' dans olena/tests) ; il y a notamment
plusieurs tests dont les sommes de contrôle MD5 sont fausses ou
absentes. C'est assez simple à réparer, et c'est un bon indicateur
de mauvais comportement d'un code et/ou de test pas à jour. Si vous
ne savez pas comment les réparer (je pense surtout aux 2007 qui n'y
ont peut-être jamais touché), demandez-moi (ou harcelez un
ancien !) ; :)
3. systématiquement écrire un test pour une nouvelle fonctionnalité. À
défaut, indiquer quelque part qu'un test est manquant lorsque vous
introduisez une nouveauté. Ça peut être sous forme de FIXME dans le
fichier concerné, dans olena/TODO, ou mieux, via Gforge[1] ;
4. écrire les tests manquants. C'est pas évident (et fastidieux à
rechercher à posteriori), mais dès que vous remarquez qu'un test
est manquant, notez-le (again, FIXME, TODO ou Gforge).
Notes:
[1] On en a parlé avec Théo récemment, il faut qu'on note les choses
qui ne vont pas dans Olena quelque part, et Gforge semble un bon
endroit. En plus, ça permet d'affecter des tâches et de les traquer.
Je connais mal Gforge, mais je pense que ça vaut le coup de s'y
mettre.