https://svn/svn/oln/prototypes/proto-1.0/olena
Index: ChangeLog from Damien Thivolle damien@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;