https://svn/svn/oln/prototypes/proto-1.0/olena
Index: ChangeLog
from Damien Thivolle <damien(a)lrde.epita.fr>
Add grey level self-dual reconstruction and clean reconstruction classes.
* tests/morpho/tests/reconstruction: Remove. Split into two files
(binary and grey level).
* tests/morpho/tests/reconstruction_binary: New. Test reconstruction
algorithms on binary images.
* tests/morpho/tests/reconstruction_greylevel: New. Test
reconstruction algorithms on grey level images.
* oln/funobj/invert.hh: Now use UCHAR_MAX.
* oln/morpho/reconstruction_by_dilation.hh: Call exact() when passing
input images to the upper class.
* oln/morpho/reconstruction_by_erosion.hh: Likewise.
* oln/morpho/reconstruction_selfdual.hh: Add grey level self-dual
reconstruction class.
* oln/canvas/reconstruction.hh: Remove useless image boxes.
oln/canvas/reconstruction.hh | 62 +++-----------
oln/funobj/invert.hh | 2
oln/morpho/reconstruction_by_dilation.hh | 21 ++--
oln/morpho/reconstruction_by_erosion.hh | 18 ++--
oln/morpho/reconstruction_selfdual.hh | 122 ++++++++++++++++++++++++++--
tests/morpho/tests/reconstruction_greylevel | 106 ++++++++++++++++++++++++
6 files changed, 256 insertions(+), 75 deletions(-)
Index: tests/morpho/tests/reconstruction_greylevel
--- tests/morpho/tests/reconstruction_greylevel (revision 0)
+++ tests/morpho/tests/reconstruction_greylevel (revision 0)
@@ -0,0 +1,106 @@
+// -*- C++ -*-
+
+#include "data.hh"
+#include <oln/basics2d.hh>
+#include <ntg/all.hh>
+
+#include <oln/core/gen/image_with_nbh.hh>
+
+#include <oln/morpho/reconstruction.hh>
+
+#include <oln/io/read_image.hh>
+
+#include <oln/level/compare.hh>
+#include <oln/utils/md5.hh>
+#include <oln/level/invert.hh>
+
+// FIXME: Debug.
+#include <oln/io/write_image.hh>
+
+bool check()
+{
+ using namespace oln;
+ image2d<unsigned char> marker;
+ image2d<unsigned char> mask;
+ image_with_nbh<image2d<unsigned char>, neighborhood2d> res_dil_hyb;
+ image_with_nbh<image2d<unsigned char>, neighborhood2d> res_dil_seq;
+ image_with_nbh<image2d<unsigned char>, neighborhood2d> res_dil_par;
+ image_with_nbh<image2d<unsigned char>, neighborhood2d> res_ero_hyb;
+ image_with_nbh<image2d<unsigned char>, neighborhood2d> res_ero_seq;
+ image_with_nbh<image2d<unsigned char>, neighborhood2d> res_ero_par;
+ image_with_nbh<image2d<unsigned char>, neighborhood2d> res_selfdual;
+ image_with_nbh<image2d<unsigned char>, neighborhood2d>
res_selfdual_invert;
+
+ utils::key::value_type data_key[16] =
+ {0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x0, 0xb2, 0x4,
+ 0xe9, 0x80, 0x9, 0x98, 0xec, 0xf8, 0x42, 0x7e};
+ utils::key key(data_key);
+
+ marker = io::read(rdata("marker.pgm"));
+ mask = io::read(rdata("mask.pgm"));
+
+ res_dil_hyb =
+ morpho::reconstruction(join(marker, neighb_c4()),
+ mask,
+ morpho::tag::hybrid(),
+ morpho::tag::by_dilation());
+ res_dil_seq =
+ morpho::reconstruction(join(marker, neighb_c4()),
+ mask,
+ morpho::tag::sequential(),
+ morpho::tag::by_dilation());
+
+ res_dil_par =
+ morpho::reconstruction(join(marker, neighb_c4()),
+ mask,
+ morpho::tag::parallel(),
+ morpho::tag::by_dilation());
+
+ image2d<unsigned char> marker_c(level::invert(marker));
+
+ res_ero_hyb =
+ morpho::reconstruction(join(marker_c, neighb_c4()),
+ level::invert(mask),
+ morpho::tag::hybrid(),
+ morpho::tag::by_erosion());
+ res_ero_seq =
+ morpho::reconstruction(join(marker_c, neighb_c4()),
+ level::invert(mask),
+ morpho::tag::sequential(),
+ morpho::tag::by_erosion());
+
+ res_ero_par =
+ morpho::reconstruction(join(marker_c, neighb_c4()),
+ level::invert(mask),
+ morpho::tag::parallel(),
+ morpho::tag::by_erosion());
+
+ res_selfdual =
+ morpho::reconstruction_selfdual(join(marker, neighb_c4()),
+ mask);
+
+ res_selfdual_invert =
+ morpho::reconstruction_selfdual(join(marker_c, neighb_c4()),
+ level::invert(mask));
+
+ if (utils::md5(res_dil_hyb) != key)
+ return true;
+
+
+ if (!level::is_equal(res_dil_hyb, res_dil_seq))
+ return true;
+ if (!level::is_equal(res_ero_hyb, res_ero_seq))
+ return true;
+ if (!level::is_equal(res_dil_hyb, res_dil_par))
+ return true;
+ if (!level::is_equal(res_ero_hyb, res_ero_par))
+ return true;
+ if (!level::is_equal(res_selfdual, level::invert(res_selfdual_invert)))
+ return true;
+ if (!level::is_equal(res_dil_hyb, level::invert(res_ero_seq)))
+ return true;
+
+ return false;
+}
+
+
Index: oln/funobj/invert.hh
--- oln/funobj/invert.hh (revision 276)
+++ oln/funobj/invert.hh (working copy)
@@ -46,7 +46,7 @@
{
unsigned char operator()(const unsigned char& v) const
{
- return 255 - v;
+ return UCHAR_MAX - v;
}
bool operator()(const bool& v) const
Index: oln/morpho/reconstruction_by_dilation.hh
--- oln/morpho/reconstruction_by_dilation.hh (revision 276)
+++ oln/morpho/reconstruction_by_dilation.hh (working copy)
@@ -53,9 +53,6 @@
using super_type::output;
using super_type::bkd_p;
using super_type::fwd_p;
- using super_type::n;
- using super_type::p;
-
void impl_bkd_loop_body()
{
@@ -71,7 +68,7 @@
binary_reconstruction_by_dilation(const abstract::binary_image<I1>& marker,
const abstract::binary_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -123,7 +120,7 @@
binary_reconstruction(const abstract::binary_image<I1>& marker,
const abstract::binary_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -155,7 +152,7 @@
binary_reconstruction(const abstract::binary_image<I1>& marker,
const abstract::binary_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -199,7 +196,7 @@
binary_reconstruction(const abstract::binary_image<I1>& marker,
const abstract::binary_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -244,7 +241,7 @@
greylevel_reconstruction_by_dilation(const abstract::greylevel_image<I1>&
marker,
const abstract::greylevel_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -294,7 +291,7 @@
greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
const abstract::greylevel_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -326,7 +323,7 @@
greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
const abstract::greylevel_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -360,7 +357,7 @@
{
output[fwd_p] =
f_max_alt(output[fwd_p].value(),
- local_sup_value(join(output, marker.nbh_get()), fwd_p));
+ local_sup_value(join(save, marker.nbh_get()), fwd_p));
}
void impl_second_step()
@@ -375,7 +372,7 @@
greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
const abstract::greylevel_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
Index: oln/morpho/reconstruction_selfdual.hh
--- oln/morpho/reconstruction_selfdual.hh (revision 276)
+++ oln/morpho/reconstruction_selfdual.hh (working copy)
@@ -57,7 +57,7 @@
binary_reconstruction(const abstract::binary_image<I1>& marker,
const abstract::binary_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -74,7 +74,8 @@
void impl_bkd_loop_body()
{
- if (output[bkd_p] < mask[bkd_p])
+ // output[bkd_p] < mask[bkd_p]
+ if (not output[bkd_p] and mask[bkd_p])
output[bkd_p] = mask[bkd_p] and
(output[bkd_p] or local_or_value_bkd(join(output, marker.nbh_get()), bkd_p));
else
@@ -84,7 +85,8 @@
void impl_fwd_loop_body()
{
- if (output[fwd_p] < mask[fwd_p])
+ // output[fwd_p] < mask[fwd_p]
+ if (not output[fwd_p] and mask[fwd_p])
output[fwd_p] = mask[fwd_p] and
(output[fwd_p] or local_or_value_fwd(join(output, marker.nbh_get()), fwd_p));
else
@@ -95,16 +97,120 @@
void impl_fifo_loop_body()
{
+ // output[n] < mask[p]
+ if (not output[n] and mask[p])
+ {
+ // output[n] < output[p] and mask[n] != output[n]
+ if (output[p] and mask[n] != output[n])
+ {
+ output[n] = output[p] and mask[n];
+ fifo.push(n);
+ }
+ }
+ else
+ // output[n] > output[p] && mask[n] != output[n]
+ if (output[n] and not output[p] and mask[n] != output[n])
+ {
+ output[n] = output[p] or mask[n];
+ fifo.push(n);
+ }
+ }
+
+ bool impl_test_fifo_push()
+ {
+ // (output[n] < output[bkd_p] and output[n] < mask[n]) or
+ // (output[n] > output[bkd_p] and output[n] > mask[n])
+ return output.hold(n) &&
+ ((not output[n] and output[bkd_p] and mask[n]) ||
+ (output[n] and not output[bkd_p] and not mask[n]));
+ }
+
+ void impl_preconditions() const
+ {
+ }
+
+ };
+
+
+
+ // GREY LEVEL
+
+ template<typename I1, typename I2>
+ struct greylevel_reconstruction <I1, I2, tag::selfdual_type, tag::none_type>
+ : public canvas::reconstruction<I1, I2, tag::hybrid_type,
+ greylevel_reconstruction<I1, I2, tag::selfdual_type, tag::none_type> >
+ {
+ typedef greylevel_reconstruction<I1, I2, tag::selfdual_type,
+ tag::none_type> self_type;
+ typedef canvas::reconstruction<I1, I2, tag::hybrid_type,
+ self_type> super_type;
+ typedef oln_type_of(I1, value) value_type;
+
+ greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
+ const abstract::greylevel_image<I2>& mask) :
+ super_type(marker.exact(), mask.exact())
+ {
+ mlc_is_a(I1, abstract::image_with_nbh)::ensure();
+ }
+
+ using super_type::mask;
+ using super_type::marker;
+ using super_type::output;
+ using super_type::fwd_p;
+ using super_type::bkd_p;
+ using super_type::p;
+ using super_type::n;
+ using super_type::fifo;
+
+
+ void impl_bkd_loop_body()
+ {
+ if (output[bkd_p] < mask[bkd_p])
+ {
+ value_type max =
+ f_max_alt(output[bkd_p].value(),
+ local_sup_value_bkd(join(output, marker.nbh_get()), bkd_p));
+ output[bkd_p] = f_min_alt(mask[bkd_p].value(), max);
+ }
+ else
+ {
+ value_type min =
+ f_min_alt(output[bkd_p].value(),
+ local_inf_value_bkd(join(output, marker.nbh_get()), bkd_p));
+ output[bkd_p] = f_max_alt(mask[bkd_p].value(), min);
+ }
+ }
+
+ void impl_fwd_loop_body()
+ {
+ if (output[fwd_p] < mask[fwd_p])
+ {
+ value_type max =
+ f_max_alt(output[fwd_p].value(),
+ local_sup_value_fwd(join(output, marker.nbh_get()), fwd_p));
+ output[fwd_p] = f_min_alt(mask[fwd_p].value(), max);
+ }
+ else
+ {
+ value_type min =
+ f_min_alt(output[fwd_p].value(),
+ local_inf_value_fwd(join(output, marker.nbh_get()), fwd_p));
+ output[fwd_p] = f_max_alt(mask[fwd_p].value(), min);
+ }
+ }
+
+ void impl_fifo_loop_body()
+ {
if (output[n] < mask[p])
{
- if (output[n] < output[p] && mask[n] != output[n])
+ if (output[n] < output[p] and mask[n] != output[n])
{
output[n] = f_min_alt(output[p].value(), mask[n].value());
fifo.push(n);
}
}
else
- if (output[n] > output[p] && mask[n] != output[n])
+ if (output[n] > output[p] and mask[n] != output[n])
{
output[n] = f_max_alt(output[p].value(), mask[n].value());
fifo.push(n);
@@ -113,9 +219,9 @@
bool impl_test_fifo_push()
{
- return output.hold(n) &&
- ((output[n] < output[bkd_p] && output[n] < mask[n]) ||
- (output[n] > output[bkd_p] && output[n] > mask[n]));
+ return output.hold(n) and
+ ((output[n] < output[bkd_p] and output[n] < mask[n]) or
+ (output[n] > output[bkd_p] and output[n] > mask[n]));
}
void impl_preconditions() const
Index: oln/morpho/reconstruction_by_erosion.hh
--- oln/morpho/reconstruction_by_erosion.hh (revision 276)
+++ oln/morpho/reconstruction_by_erosion.hh (working copy)
@@ -70,7 +70,7 @@
binary_reconstruction_by_erosion(const abstract::binary_image<I1>& marker,
const abstract::binary_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -122,7 +122,7 @@
binary_reconstruction(const abstract::binary_image<I1>& marker,
const abstract::binary_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -154,7 +154,7 @@
binary_reconstruction(const abstract::binary_image<I1>& marker,
const abstract::binary_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -198,7 +198,7 @@
binary_reconstruction(const abstract::binary_image<I1>& marker,
const abstract::binary_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -250,7 +250,7 @@
greylevel_reconstruction_by_erosion(const abstract::greylevel_image<I1>&
marker,
const abstract::greylevel_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -300,7 +300,7 @@
greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
const abstract::greylevel_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -332,7 +332,7 @@
greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
const abstract::greylevel_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
@@ -365,7 +365,7 @@
{
output[fwd_p] =
f_min_alt(output[fwd_p].value(),
- local_inf_value(join(output, marker.nbh_get()), fwd_p));
+ local_inf_value(join(save, marker.nbh_get()), fwd_p));
}
void impl_second_step()
@@ -380,7 +380,7 @@
greylevel_reconstruction(const abstract::greylevel_image<I1>& marker,
const abstract::greylevel_image<I2>& mask) :
- super_type(marker, mask)
+ super_type(marker.exact(), mask.exact())
{
mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
Index: oln/canvas/reconstruction.hh
--- oln/canvas/reconstruction.hh (revision 276)
+++ oln/canvas/reconstruction.hh (working copy)
@@ -108,11 +108,7 @@
void init()
{
- // FIXME: We can't use `output = clone(marker)' directly here,
- // because box's op=(const abstract::image<II>& rhs) would be
- // called, which is empty (see oln/core/box.hh).
- output_type output_tmp(clone(marker));
- output = output_tmp;
+ output = clone(marker);
}
void run()
@@ -146,12 +142,12 @@
oln_type_of(I1, concrete) get_output()
{
- return output.unbox();
+ return output;
}
protected:
- reconstruction(const abstract::image<I1>& marker,
+ reconstruction(const abstract::image_with_nbh<I1>& marker,
const abstract::image<I2>& mask) :
marker(marker.exact()),
mask(mask.exact()),
@@ -180,7 +176,7 @@
oln_type_of(I1, point) p;
oln_type_of(I1, niter) n;
- box<oln_type_of(I1, concrete)> output;
+ oln_type_of(I1, concrete) output;
std::queue<oln_type_of(I1, point) > fifo;
@@ -203,17 +199,8 @@
void impl_init()
{
- // FIXME: We can't use `output = clone(marker)' directly here,
- // because box's op=(const abstract::image<II>& rhs) would be
- // called, which is empty (see oln/core/box.hh).
- output_type output_tmp(clone(marker));
- output = output_tmp;
- // FIXME: We can't use `save = clone(marker)' directly here,
- // because box's op=(const abstract::image<II>& rhs) would be
- // called, which is empty (see oln/core/box.hh).
- output_type save_tmp(clone(marker));
- save = save_tmp;
-
+ output = clone(marker);
+ save = clone(marker);
}
bool impl_is_stable() const
@@ -223,31 +210,27 @@
void impl_re_loop()
{
- // FIXME: We can't use `save = clone(output)' directly here,
- // because box's op=(const abstract::image<II>& rhs) would be
- // called, which is empty (see oln/core/box.hh).
- save.unbox() = clone(output);
+ save = clone(output);
}
oln_type_of(I1, concrete) get_output()
{
- return output.unbox();
+ return output;
}
protected:
- reconstruction(const abstract::image<I1>& marker,
+ reconstruction(const abstract::image_with_nbh<I1>& marker,
const abstract::image<I2>& mask) :
super_type(marker),
marker(marker.exact()),
mask(mask.exact()),
n(marker)
{
- mlc_is_a(I1, abstract::image_with_nbh)::ensure();
}
- box<oln_type_of(I1, concrete)> save;
- box<oln_type_of(I1, concrete)> output;
+ oln_type_of(I1, concrete) save;
+ oln_type_of(I1, concrete) output;
box<const I1> marker;
box<const I2> mask;
oln_type_of(I1, point) p;
@@ -293,16 +276,8 @@
void impl_init()
{
- // FIXME: We can't use `output = clone(marker)' directly here,
- // because box's op=(const abstract::image<II>& rhs) would be
- // called, which is empty (see oln/core/box.hh).
- output_type output_tmp(clone(marker));
- output = output_tmp;
- // FIXME: We can't use `save = clone(marker)' directly here,
- // because box's op=(const abstract::image<II>& rhs) would be
- // called, which is empty (see oln/core/box.hh).
- output_type save_tmp(clone(marker));
- save = save_tmp;
+ output = clone(marker);
+ save = clone(marker);
}
bool impl_is_stable() const
@@ -312,15 +287,12 @@
void impl_re_loop()
{
- // FIXME: We can't use `save = clone(output)' directly here,
- // because box's op=(const abstract::image<II>& rhs) would be
- // called, which is empty (see oln/core/box.hh).
- save.unbox() = clone(output);
+ save = clone(output);
}
oln_type_of(I1, concrete) get_output()
{
- return output.unbox();
+ return output;
}
protected:
@@ -336,8 +308,8 @@
mlc_check_method_impl(E, void, second_step, , );
}
- box<oln_type_of(I1, concrete)> save;
- box<oln_type_of(I1, concrete)> output;
+ oln_type_of(I1, concrete) save;
+ oln_type_of(I1, concrete) output;
box<const I1> marker;
box<const I2> mask;
oln_type_of(I1, fwd_piter) fwd_p;