978: Add raw code for morphological reconstruction by d.

https://svn.lrde.epita.fr/svn/oln/trunk/olena Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Add raw code for morphological reconstruction by d. * oln/morpho/Rd: New directory. * oln/morpho/Rd/hybrid.hh, * oln/morpho/Rd/queue_based.hh, * oln/morpho/Rd/parallel.cc, * oln/morpho/Rd/hybrid.cc, * oln/morpho/Rd/union_find.hh, * oln/morpho/Rd/queue_based.cc, * oln/morpho/Rd/sequential.hh, * oln/morpho/Rd/debase.union_find.hh, * oln/morpho/Rd/parallel.hh, * oln/morpho/Rd/diff.cc, * oln/morpho/Rd/union_find.cc, * oln/morpho/Rd/sequential.cc, * oln/morpho/Rd/utils.hh, * oln/io/save_pgm.hh, * oln/io/load_pgm.hh: New. * oln/debug/format.hh: Update. * oln/core/gen/neighb.hh (niter): New associated type. * oln/level/fill.hh (iterator): Add include. core/gen/neighb.hh | 4 debug/format.hh | 15 +- io/load_pgm.hh | 169 +++++++++++++++++++++++++++ io/save_pgm.hh | 68 +++++++++++ level/fill.hh | 1 morpho/Rd/debase.union_find.hh | 165 +++++++++++++++++++++++++++ morpho/Rd/diff.cc | 28 ++++ morpho/Rd/hybrid.cc | 46 +++++++ morpho/Rd/hybrid.hh | 103 ++++++++++++++++ morpho/Rd/parallel.cc | 46 +++++++ morpho/Rd/parallel.hh | 80 +++++++++++++ morpho/Rd/queue_based.cc | 46 +++++++ morpho/Rd/queue_based.hh | 106 +++++++++++++++++ morpho/Rd/sequential.cc | 46 +++++++ morpho/Rd/sequential.hh | 85 +++++++++++++ morpho/Rd/union_find.cc | 46 +++++++ morpho/Rd/union_find.hh | 165 +++++++++++++++++++++++++++ morpho/Rd/utils.hh | 250 +++++++++++++++++++++++++++++++++++++++++ 18 files changed, 1466 insertions(+), 3 deletions(-) Index: oln/debug/format.hh --- oln/debug/format.hh (revision 977) +++ oln/debug/format.hh (working copy) @@ -28,6 +28,9 @@ #ifndef OLN_DEBUG_FORMAT_HH # define OLN_DEBUG_FORMAT_HH +# include <string> +# include <sstream> + namespace oln { @@ -41,7 +44,7 @@ const T& format(const T& value); - unsigned + std::string format(const unsigned char& value); char @@ -56,9 +59,15 @@ return value; } - unsigned format(const unsigned char& value) + std::string format(const unsigned char& value) { - return value; + std::ostringstream ostr; + if (value < 10) + ostr << "00"; + else if (value < 100) + ostr << '0'; + ostr << unsigned(value); + return ostr.str(); } char format(bool value) Index: oln/core/gen/neighb.hh --- oln/core/gen/neighb.hh (revision 977) +++ oln/core/gen/neighb.hh (working copy) @@ -31,6 +31,7 @@ # include <oln/core/internal/dpoints_impl.hh> # include <oln/core/internal/neighborhood_base.hh> +# include <oln/core/gen/dpoints_piter.hh> namespace oln @@ -65,6 +66,9 @@ { public: + typedef stc_type(Dp, point) P; + typedef dpoints_fwd_piter_<P> niter; + neighb_(); neighb_<Dp>& take(const Dp& dp); Index: oln/morpho/Rd/hybrid.hh --- oln/morpho/Rd/hybrid.hh (revision 0) +++ oln/morpho/Rd/hybrid.hh (revision 0) @@ -0,0 +1,103 @@ +// Copyright (C) 2007 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, 51 Franklin Street, Fifth Floor, +// 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 OLN_MORPHO_RD_HYBRID_HH +# define OLN_MORPHO_RD_HYBRID_HH + +# include <queue> +# include <oln/morpho/Rd/utils.hh> + + +namespace oln +{ + + namespace morpho + { + + namespace Rd + { + + + template <typename I, typename N> + I hybrid(const I& f, const I& g, const N& nbh, + bool echo = false) + { + typedef oln_point(I) point; + std::queue<point> q; + + // initialisation + I o = level::clone(f); + + // sequence + { + oln_bkd_piter(I) p(f.points()); + for_all(p) + o(p) = min( max_Nminus(o, p,nbh), g(p) ); + } + { + oln_fwd_piter(I) p(f.points()); + oln_niter(N) n(nbh, p); + for_all(p) + { + o(p) = min( max_Nplus(o, p,nbh), g(p) ); + for_all(n) if (f.has(n) and n < p) // N+ + if (o(n) < o(p) and o(n) < g(n)) + q.push(p); + } + } + + // propagation + { + point p; + oln_niter(N) n(nbh, p); + while (not q.empty()) + { + p = q.front(); + if (echo) std::cout << std::endl << "pop " << p << " :"; + q.pop(); + for_all(n) if (f.has(n)) + if (o(n) < o(p) and o(n) != g(n)) + { + o(n) = min(o(p), g(n)); + if (echo) std::cout << " push " << n; + q.push(n); + } + } + if (echo) std::cout << std::endl; + } + + return o; + } + + } // end of namespace oln::morpho::Rd + + } // end of namespace oln::morpho + +} // end of namespace oln + + +#endif // ! OLN_MORPHO_RD_HYBRID_HH Index: oln/morpho/Rd/queue_based.hh --- oln/morpho/Rd/queue_based.hh (revision 0) +++ oln/morpho/Rd/queue_based.hh (revision 0) @@ -0,0 +1,106 @@ +// Copyright (C) 2007 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, 51 Franklin Street, Fifth Floor, +// 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 OLN_MORPHO_RD_QUEUE_BASED_HH +# define OLN_MORPHO_RD_QUEUE_BASED_HH + +# include <queue> +# include <oln/morpho/Rd/utils.hh> + + +namespace oln +{ + + namespace morpho + { + + namespace Rd + { + + template <typename I, typename N> + I queue_based(const I& f, const I& g, const N& nbh, + bool echo = false) + { + if (echo) std::cout << std::endl; + + typedef oln_point(I) point; + std::queue<point> q; + I o; + + // initialisation + { + o = regional_maxima(f, nbh); + if (echo) debug::println(o); + + oln_piter(I) p(f.points()); + oln_niter(N) n(nbh, p); + + for_all(p) + if (o(p) != 0) + { + bool ok = false; + for_all(n) if (f.has(n)) + if (o(n) = 0) + ok = true; + if (ok) + q.push(p); + } + } + + // propagation + { + point p; + oln_niter(N) n(nbh, p); + while (not q.empty()) + { + p = q.front(); + if (echo) std::cout << std::endl << "pop " << p << " :"; + q.pop(); + for_all(n) if (f.has(n)) + { + if (o(n) < o(p) and o(n) != g(n)) + { + o(n) = min(o(p), g(n)); + if (echo) std::cout << " push " << n; + q.push(n); + } + } + } + if (echo) std::cout << std::endl; + } + + return o; + } + + } // end of namespace oln::morpho::Rd + + } // end of namespace oln::morpho + +} // end of namespace oln + + +#endif // ! OLN_MORPHO_RD_QUEUE_BASED_HH Index: oln/morpho/Rd/parallel.cc --- oln/morpho/Rd/parallel.cc (revision 0) +++ oln/morpho/Rd/parallel.cc (revision 0) @@ -0,0 +1,46 @@ +#include <oln/core/2d/image2d.hh> +#include <oln/core/2d/neighb2d.hh> + +#include <oln/debug/println.hh> +#include <oln/io/load_pgm.hh> +#include <oln/io/save_pgm.hh> +#include <oln/morpho/Rd/parallel.hh> + + +void usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " f.pgm g.pgm c output.pgm" << std::endl + << "reconstruction by dilation (parallel version; may 2007)" << std::endl + << "f = marker (to be dilated)" << std::endl + << "g = mask (constraint >= f)" << std::endl + << "c: 4 or 8" << std::endl; + exit(1); +} + + +int main(int argc, char* argv[]) +{ + if (argc != 5) + usage(argv); + + using namespace oln; + typedef image2d<unsigned char> I; + + int c = atoi(argv[3]); + if (c != 4 and c != 8) + usage(argv); + + I f = io::load_pgm(argv[1]); + I g = io::load_pgm(argv[2]); + + if (not (f <= g)) + { + std::cerr << "pb" << std::endl; + return 1; + } + + io::save_pgm(morpho::Rd::parallel(f, g, + (c = 4 ? c4 : c8)), + argv[4]); + return 0; +} Index: oln/morpho/Rd/hybrid.cc --- oln/morpho/Rd/hybrid.cc (revision 0) +++ oln/morpho/Rd/hybrid.cc (revision 0) @@ -0,0 +1,46 @@ +#include <oln/core/2d/image2d.hh> +#include <oln/core/2d/neighb2d.hh> + +#include <oln/debug/println.hh> +#include <oln/io/load_pgm.hh> +#include <oln/io/save_pgm.hh> +#include <oln/morpho/Rd/hybrid.hh> + + +void usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " f.pgm g.pgm c output.pgm" << std::endl + << "reconstruction by dilation (hybrid version; may 2007)" << std::endl + << "f = marker (to be dilated)" << std::endl + << "g = mask (constraint >= f)" << std::endl + << "c: 4 or 8" << std::endl; + exit(1); +} + + +int main(int argc, char* argv[]) +{ + if (argc != 5) + usage(argv); + + using namespace oln; + typedef image2d<unsigned char> I; + + int c = atoi(argv[3]); + if (c != 4 and c != 8) + usage(argv); + + I f = io::load_pgm(argv[1]); + I g = io::load_pgm(argv[2]); + + if (not (f <= g)) + { + std::cerr << "pb" << std::endl; + return 1; + } + + io::save_pgm(morpho::Rd::hybrid(f, g, + (c = 4 ? c4 : c8)), + argv[4]); + return 0; +} Index: oln/morpho/Rd/union_find.hh --- oln/morpho/Rd/union_find.hh (revision 0) +++ oln/morpho/Rd/union_find.hh (revision 0) @@ -0,0 +1,165 @@ +// Copyright (C) 2007 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, 51 Franklin Street, Fifth Floor, +// 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 OLN_MORPHO_RD_UNION_FIND_HH +# define OLN_MORPHO_RD_UNION_FIND_HH + +# include <oln/morpho/Rd/utils.hh> + + +namespace oln +{ + + namespace morpho + { + + namespace Rd + { + + + template <typename I, typename N> + struct union_find_t + { + typedef oln_point(I) point; + + // in: + I f, g; + N nbh; + + // out: + I o; + + // aux: + std::vector<point> S; + I data; + oln_plain_value(I, bool) is_proc; + oln_plain_value(I, point) parent; + + union_find_t(const I& f, const I& g, const N& nbh) + : f(f), g(g), nbh(nbh) + { + prepare(o, with, f); + prepare(parent, with, f); + prepare(is_proc, with, f); + prepare(data, with, f); + + // init + + std::cout << "0 "; + level::fill(inplace(is_proc), false); + S = histo_reverse_sort(g); + + // first pass + + std::cout << "1 "; + for (unsigned i = 0; i < S.size(); ++i) + { + point p = S[i]; + + make_set(p); + oln_niter(N) n(nbh, p); + for_all(n) + if (f.has(n) and is_proc(n)) + do_union(n, p); + is_proc(p) = true; + } + + // second pass + + std::cout << "2 "; + level::fill(inplace(is_proc), false); + for (int i = S.size() - 1; i >= 0; --i) + { + point p = S[i]; + assert(is_proc(p) = false); + if (parent(p) = p) + o(p) = data(p) = 255 ? g(p) : data(p); + else + { + assert(is_proc(parent(p)) = true); + o(p) = o(parent(p)); + } + is_proc(p) = true; + } + + } + + void make_set(const point& p) + { + parent(p) = p; + data(p) = f(p); + } + + point find_root(const point& x) + { + if (parent(x) = x) + return x; + else + return parent(x) = find_root(parent(x)); + } + + bool equiv(const point& r, const point& p) + { + return g(r) = g(p) or g(p) >= data(r); + } + + void do_union(const point& n, const point& p) + { + point r = find_root(n); + if (r != p) + { + if (equiv(r, p)) + { + parent(r) = p; + if (data(r) > data(p)) + data(p) = data(r); // increasing criterion + } + else + data(p) = 255; + } + } + + }; + + + template <typename I, typename N> + I union_find(const I& f, const I& g, const N& nbh) + { + precondition(f <= g); + union_find_t<I, N> run(f, g, nbh); + return run.o; + } + + + } // end of namespace oln::morpho::Rd + + } // end of namespace oln::morpho + +} // end of namespace oln + + +#endif // ! OLN_MORPHO_RD_UNION_FIND_HH Index: oln/morpho/Rd/queue_based.cc --- oln/morpho/Rd/queue_based.cc (revision 0) +++ oln/morpho/Rd/queue_based.cc (revision 0) @@ -0,0 +1,46 @@ +#include <oln/core/2d/image2d.hh> +#include <oln/core/2d/neighb2d.hh> + +#include <oln/debug/println.hh> +#include <oln/io/load_pgm.hh> +#include <oln/io/save_pgm.hh> +#include <oln/morpho/Rd/queue_based.hh> + + +void usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " f.pgm g.pgm c output.pgm" << std::endl + << "reconstruction by dilation (queue_based version; may 2007)" << std::endl + << "f = marker (to be dilated)" << std::endl + << "g = mask (constraint >= f)" << std::endl + << "c: 4 or 8" << std::endl; + exit(1); +} + + +int main(int argc, char* argv[]) +{ + if (argc != 5) + usage(argv); + + using namespace oln; + typedef image2d<unsigned char> I; + + int c = atoi(argv[3]); + if (c != 4 and c != 8) + usage(argv); + + I f = io::load_pgm(argv[1]); + I g = io::load_pgm(argv[2]); + + if (not (f <= g)) + { + std::cerr << "pb" << std::endl; + return 1; + } + + io::save_pgm(morpho::Rd::queue_based(f, g, + (c = 4 ? c4 : c8)), + argv[4]); + return 0; +} Index: oln/morpho/Rd/sequential.hh --- oln/morpho/Rd/sequential.hh (revision 0) +++ oln/morpho/Rd/sequential.hh (revision 0) @@ -0,0 +1,85 @@ +// Copyright (C) 2007 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, 51 Franklin Street, Fifth Floor, +// 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 OLN_MORPHO_RD_SEQUENTIAL_HH +# define OLN_MORPHO_RD_SEQUENTIAL_HH + +# include <oln/morpho/Rd/utils.hh> + + +namespace oln +{ + + namespace morpho + { + + namespace Rd + { + + template <typename I, typename N> + I sequential(const I& f, const I& g, const N& nbh) + { + precondition(f <= g); + I o_(f.points()); + + // initialisation + I o = level::clone(f); + + bool stability; + do + { + level::paste(o, inplace(o_)); // memorisation + + // passe 1 + { + oln_bkd_piter(I) p(f.points()); + for_all(p) + o(p) = min( max_Nminus(o, p,nbh), g(p) ); + } + + // passe 2 + { + oln_fwd_piter(I) p(f.points()); + for_all(p) + o(p) = min( max_Nplus(o, p,nbh), g(p) ); + } + + stability = (o = o_); + } + while (not stability); + postcondition(o <= g); + return o; + } + + } // end of namespace oln::morpho::Rd + + } // end of namespace oln::morpho + +} // end of namespace oln + + +#endif // ! OLN_MORPHO_RD_SEQUENTIAL_HH Index: oln/morpho/Rd/debase.union_find.hh --- oln/morpho/Rd/debase.union_find.hh (revision 0) +++ oln/morpho/Rd/debase.union_find.hh (revision 0) @@ -0,0 +1,165 @@ +// Copyright (C) 2007 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, 51 Franklin Street, Fifth Floor, +// 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 OLN_MORPHO_RD_UNION_FIND_HH +# define OLN_MORPHO_RD_UNION_FIND_HH + +# include <oln/morpho/Rd/utils.hh> + + +namespace oln +{ + + namespace morpho + { + + namespace Rd + { + + + template <typename I, typename N> + struct union_find_t + { + typedef oln_point(I) point; + + // in: + I f, g; + N nbh; + + // out: + I o; + + // aux: + std::vector<point> S; + I data; + oln_plain_value(I, bool) is_proc; + oln_plain_value(I, point) parent; + + union_find_t(const I& f, const I& g, const N& nbh) + : f(f), g(g), nbh(nbh) + { + prepare(o, with, f); + prepare(parent, with, f); + prepare(is_proc, with, f); + prepare(data, with, f); + + // init + + std::cout << "0 "; + level::fill(inplace(is_proc), false); + S = histo_reverse_sort(g); + + // first pass + + std::cout << "1 "; + for (unsigned i = 0; i < S.size(); ++i) + { + point p = S[i]; + + make_set(p); + oln_niter(N) n(nbh, p); + for_all(n) + if (f.has(n) and is_proc(n)) + do_union(n, p); + is_proc(p) = true; + } + + // second pass + + std::cout << "2 "; + level::fill(inplace(is_proc), false); + for (int i = S.size() - 1; i >= 0; --i) + { + point p = S[i]; + assert(is_proc(p) = false); + if (parent(p) = p) + o(p) = data(p) = 255 ? g(p) : data(p); + else + { + assert(is_proc(parent(p)) = true); + o(p) = o(parent(p)); + } + is_proc(p) = true; + } + + } + + void make_set(const point& p) + { + parent(p) = p; + data(p) = f(p); + } + + point find_root(const point& x) + { + if (parent(x) = x) + return x; + else + return parent(x) = find_root(parent(x)); + } + + bool equiv(const point& r, const point& p) + { + return g(r) = g(p) or g(p) >= data(r); + } + + void do_union(const point& n, const point& p) + { + point r = find_root(n); + if (r != p) + { + if (equiv(r, p)) + { + parent(r) = p; + if (data(r) > data(p)) + data(p) = data(r); // increasing criterion + } + else + data(p) = 255; + } + } + + }; + + + template <typename I, typename N> + I union_find(const I& f, const I& g, const N& nbh) + { + precondition(f <= g); + union_find_t<I, N> run(f, g, nbh); + return run.o; + } + + + } // end of namespace oln::morpho::Rd + + } // end of namespace oln::morpho + +} // end of namespace oln + + +#endif // ! OLN_MORPHO_RD_UNION_FIND_HH Index: oln/morpho/Rd/parallel.hh --- oln/morpho/Rd/parallel.hh (revision 0) +++ oln/morpho/Rd/parallel.hh (revision 0) @@ -0,0 +1,80 @@ +// Copyright (C) 2007 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, 51 Franklin Street, Fifth Floor, +// 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 OLN_MORPHO_RD_PARALLEL_HH +# define OLN_MORPHO_RD_PARALLEL_HH + +# include <oln/morpho/Rd/utils.hh> + + +namespace oln +{ + + namespace morpho + { + + namespace Rd + { + + template <typename I, typename N> + I parallel(const I& f, const I& g, const N& nbh) + { + precondition(f <= g); + I o_(f.points()); + oln_piter(I) p(f.points()); + + // initialisation + I o = level::clone(f); + + bool stability; + do + { + level::paste(o, inplace(o_)); // memorisation + + // opere + for_all(p) + o(p) = max_N(o_, p,nbh); + // conditionne + for_all(p) + o(p) = min(o(p), g(p)); + + stability = (o = o_); + } + while (not stability); + + postcondition(o <= g); + return o; + } + + } // end of namespace oln::morpho::Rd + + } // end of namespace oln::morpho + +} // end of namespace oln + + +#endif // ! OLN_MORPHO_RD_PARALLEL_HH Index: oln/morpho/Rd/diff.cc --- oln/morpho/Rd/diff.cc (revision 0) +++ oln/morpho/Rd/diff.cc (revision 0) @@ -0,0 +1,28 @@ +#include <oln/core/2d/image2d.hh> +#include <oln/io/load_pgm.hh> +#include <oln/level/compare.hh> + + +void usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " 1.pgm 2.pgm" << std::endl + << "(may 2007)" << std::endl; + exit(1); +} + + +int main(int argc, char* argv[]) +{ + if (argc != 3) + usage(argv); + + using namespace oln; + typedef image2d<unsigned char> I; + + I ima1 = io::load_pgm(argv[1]); + I ima2 = io::load_pgm(argv[2]); + + if (ima1 != ima2) + std::cout << "images differ" << std::endl; + return 0; +} Index: oln/morpho/Rd/union_find.cc --- oln/morpho/Rd/union_find.cc (revision 0) +++ oln/morpho/Rd/union_find.cc (revision 0) @@ -0,0 +1,46 @@ +#include <oln/core/2d/image2d.hh> +#include <oln/core/2d/neighb2d.hh> + +#include <oln/debug/println.hh> +#include <oln/io/load_pgm.hh> +#include <oln/io/save_pgm.hh> +#include <oln/morpho/Rd/union_find.hh> + + +void usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " f.pgm g.pgm c output.pgm" << std::endl + << "reconstruction by dilation (union_find version; may 2007)" << std::endl + << "f = marker (to be dilated)" << std::endl + << "g = mask (constraint >= f)" << std::endl + << "c: 4 or 8" << std::endl; + exit(1); +} + + +int main(int argc, char* argv[]) +{ + if (argc != 5) + usage(argv); + + using namespace oln; + typedef image2d<unsigned char> I; + + int c = atoi(argv[3]); + if (c != 4 and c != 8) + usage(argv); + + I f = io::load_pgm(argv[1]); + I g = io::load_pgm(argv[2]); + + if (not (f <= g)) + { + std::cerr << "pb" << std::endl; + return 1; + } + + io::save_pgm(morpho::Rd::union_find(f, g, + (c = 4 ? c4 : c8)), + argv[4]); + return 0; +} Index: oln/morpho/Rd/sequential.cc --- oln/morpho/Rd/sequential.cc (revision 0) +++ oln/morpho/Rd/sequential.cc (revision 0) @@ -0,0 +1,46 @@ +#include <oln/core/2d/image2d.hh> +#include <oln/core/2d/neighb2d.hh> + +#include <oln/debug/println.hh> +#include <oln/io/load_pgm.hh> +#include <oln/io/save_pgm.hh> +#include <oln/morpho/Rd/sequential.hh> + + +void usage(char* argv[]) +{ + std::cerr << "usage: " << argv[0] << " f.pgm g.pgm c output.pgm" << std::endl + << "reconstruction by dilation (sequential version; may 2007)" << std::endl + << "f = marker (to be dilated)" << std::endl + << "g = mask (constraint >= f)" << std::endl + << "c: 4 or 8" << std::endl; + exit(1); +} + + +int main(int argc, char* argv[]) +{ + if (argc != 5) + usage(argv); + + using namespace oln; + typedef image2d<unsigned char> I; + + int c = atoi(argv[3]); + if (c != 4 and c != 8) + usage(argv); + + I f = io::load_pgm(argv[1]); + I g = io::load_pgm(argv[2]); + + if (not (f <= g)) + { + std::cerr << "pb" << std::endl; + return 1; + } + + io::save_pgm(morpho::Rd::sequential(f, g, + (c = 4 ? c4 : c8)), + argv[4]); + return 0; +} Index: oln/morpho/Rd/utils.hh --- oln/morpho/Rd/utils.hh (revision 0) +++ oln/morpho/Rd/utils.hh (revision 0) @@ -0,0 +1,250 @@ +// Copyright (C) 2007 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, 51 Franklin Street, Fifth Floor, +// 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 OLN_MORPHO_RD_UTILS_HH +# define OLN_MORPHO_RD_UTILS_HH + +# include <vector> + +# include <oln/core/concept/image.hh> +# include <oln/core/internal/f_ch_value.hh> + +# include <oln/level/fill.hh> +# include <oln/level/paste.hh> +# include <oln/level/clone.hh> +# include <oln/level/compare.hh> + + + +namespace oln +{ + + namespace morpho + { + + namespace Rd + { + + + template <typename T> + T min(T v1, T v2) + { + return v1 < v2 ? v1 : v2; + } + + + template <typename I> + std::vector<unsigned> compute_histo(const I& ima) + { + std::vector<unsigned> h(256, 0); + oln_piter(I) p(ima.points()); + for_all(p) + ++h[ima(p)]; + return h; + } + + + template <typename I> + std::vector<oln_point(I)> histo_sort(const I& ima) + { + std::vector<unsigned> h = compute_histo(ima); + // preparing output data + std::vector<int> loc(256); + loc[0] = 0; + for (int l = 1; l < 256; ++l) + loc[l] = loc[l-1] + h[l-1]; + std::vector<oln_point(I)> vec(ima.points().npoints()); + // storing output data + oln_piter(I) p(ima.points()); + for_all(p) + vec[loc[ima(p)]++] = p; + return vec; + } + + + template <typename I> + std::vector<oln_point(I)> histo_reverse_sort(const I& ima) + { + std::vector<unsigned> h = compute_histo(ima); + // preparing output data + std::vector<int> loc(256); + loc[255] = 0; + for (int l = 254; l >= 0; --l) + loc[l] = loc[l+1] + h[l+1]; + std::vector<oln_point(I)> vec(ima.points().npoints()); + // storing output data + oln_piter(I) p(ima.points()); + for_all(p) + vec[loc[ima(p)]++] = p; + return vec; + } + + + template <typename I, typename P, typename N> + oln_value(I) max_Nplus(const I& ima, const P& p, const N& nbh) + { + oln_value(I) v = ima(p); + oln_niter(N) n(nbh, p); + for_all(n) + if (ima.has(n) and n < p and ima(n) > v) + v = ima(n); + return v; + } + + + template <typename I, typename P, typename N> + oln_value(I) max_Nminus(const I& ima, const P& p, const N& nbh) + { + oln_value(I) v = ima(p); + oln_niter(N) n(nbh, p); + for_all(n) + if (ima.has(n) and n > p and ima(n) > v) + v = ima(n); + return v; + } + + + template <typename I, typename P, typename N> + oln_value(I) max_N(const I& ima, const P& p, const N& nbh) + { + oln_value(I) v = ima(p); + oln_niter(N) n(nbh, p); + for_all(n) + if (ima.has(n) and ima(n) > v) + v = ima(n); + return v; + } + + + template <typename I, typename N> + struct regional_maxima_t + { + typedef oln_point(I) point; + typedef oln_plain_value(I, bool) image_bool; + typedef oln_plain_value(I, point) image_point; + + // in: + I f; + N nbh; + + // out: + I o; + + // aux: + std::vector<point> S; + image_bool is_proc; + image_bool attr; + image_point parent; + + regional_maxima_t(const I& f, const N& nbh) + : f(f), nbh(nbh) + { + prepare(o, with, f); + prepare(parent, with, f); + prepare(attr, with, f); + prepare(is_proc, with, f); + + // init + + level::fill(inplace(is_proc), false); + S = histo_reverse_sort(f); + + // first pass + + for (unsigned i = 0; i < S.size(); ++i) + { + point p = S[i]; + + make_set(p); + oln_niter(N) n(nbh, p); + for_all(n) + if (f.has(n) and is_proc(n)) + { + if (f(n) = f(p)) + do_union(n, p); + else // f(n) > f(p) + attr(p) = false; + } + is_proc(p) = true; + } + + // second pass + + for (int i = S.size() - 1; i >= 0; --i) + { + point p = S[i]; + if (parent(p) = p) + o(p) = attr(p) ? f(p) : 0; + else + o(p) = o(parent(p)); + } + } + + void make_set(const point& p) + { + parent(p) = p; + attr(p) = true; + } + + point find_root(const point& x) + { + if (parent(x) = x) + return x; + else + return parent(x) = find_root(parent(x)); + } + + void do_union(const point& n, const point& p) + { + point r = find_root(n); + if (r != p) + { + parent(r) = p; + attr(p) = attr(p) and attr(r); + } + } + + }; + + + template <typename I, typename N> + I + regional_maxima(const I& f, const N& nbh) + { + regional_maxima_t<I, N> run(f, nbh); + return run.o; + } + + + } // end of namespace oln::morpho::Rd + + } // end of namespace oln::morpho + +} // end of namespace oln + + +#endif // ! OLN_MORPHO_RD_UTILS_HH Index: oln/level/fill.hh --- oln/level/fill.hh (revision 977) +++ oln/level/fill.hh (working copy) @@ -33,6 +33,7 @@ # include <oln/core/concept/image.hh> # include <oln/core/concept/point.hh> +# include <oln/core/concept/iterator.hh> # include <oln/core/gen/fun.hh> # include <oln/core/gen/inplace.hh> Index: oln/io/save_pgm.hh --- oln/io/save_pgm.hh (revision 0) +++ oln/io/save_pgm.hh (revision 0) @@ -0,0 +1,68 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 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, 51 Franklin Street, Fifth Floor, +// 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 OLN_IO_SAVE_PGM_HH +# define OLN_IO_SAVE_PGM_HH + +# include <iostream> +# include <fstream> + +# include <oln/core/2d/image2d.hh> + + +namespace oln +{ + + namespace io + { + + void save_pgm(const image2d<unsigned char>& ima, const std::string& filename) + { + std::ofstream file(filename.c_str()); + if (not file) + { + std::cerr << "error: cannot open file '" << filename + << "'!"; + abort(); + } + file << "P5" << std::endl; + file << "# olena" << std::endl; + file << ima.ncols() << ' ' << ima.nrows() << std::endl; + file << "255" << std::endl; + int col = ima.min_col(); + size_t len = ima.ncols() * sizeof(unsigned char); + for (int row = ima.min_row(); row <= ima.max_row(); ++row) + file.write((char*)(&(ima.at(row, col))), len); + } + + } // end of namespace oln::io + +} // end of namespace oln + + +#endif // ! OLN_IO_SAVE_PGM_HH Index: oln/io/load_pgm.hh --- oln/io/load_pgm.hh (revision 0) +++ oln/io/load_pgm.hh (revision 0) @@ -0,0 +1,169 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 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, 51 Franklin Street, Fifth Floor, +// 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 OLN_IO_LOAD_PGM_HH +# define OLN_IO_LOAD_PGM_HH + +# include <iostream> +# include <fstream> +# include <string> + +# include <oln/core/2d/image2d.hh> + + +namespace oln { + + namespace io { + + namespace internal { + + void abort() + { + std::cerr << " aborting." << std::endl; + exit(0); + } + + bool read_pnm_header(std::istream& istr, + char& type, + int& nrows, int& ncols, + bool test = false) + { + // check magic + if (istr.get() != 'P' ) + goto err; + type = istr.get(); + if (type < '1' or type > '6') + goto err; + if (istr.get() != '\n') + goto err; + + // skip comments + while (istr.peek() = '#') + { + std::string line; + std::getline(istr, line); + } + + // get size + istr >> ncols >> nrows; + if (nrows <= 0 or ncols <= 0) + goto err; + + // skip maxvalue + if (istr.get() != '\n') + goto err; + if (type != '1' and type != '4') + { + std::string line; + std::getline(istr, line); + } + return true; + + err: + if (not test) + { + std::cerr << "error: badly formed header!"; + abort(); + } + return false; + } + + void read_pnm_header(char ascii, char raw, + std::istream& istr, + char& type, + int& nrows, int& ncols) + { + read_pnm_header(istr, type, nrows, ncols); + if (not (type = ascii or type = raw)) + { + std::cerr << "error: bad pnm type; " + << "expected P" << ascii + << " or P" << raw + << ", get P" << type << "!"; + abort(); + } + } + + + /// load_ascii. + template <typename I> + void load_pgm_ascii(std::ifstream& file, I& ima) + { + oln_fwd_piter(I) p(ima.points()); + for_all(p) + { + unsigned value; + file >> value; + ima(p) = value; + // FIXME: Test alt code below. + // file >> ima(p); + } + } + + + /// load_raw_2d. + template <typename I> + void load_pgm_raw_2d(std::ifstream& file, I& ima) + { + int col = ima.min_col(); + size_t len = ima.ncols() * sizeof(oln_value(I)); + for (int row = ima.min_row(); row <= ima.max_row(); ++row) + file.read((char*)(&(ima.at(row, col))), len); + } + + + } // end of namespace oln::io::internal + + + image2d<unsigned char> load_pgm(const std::string& filename) + { + std::ifstream file(filename.c_str()); + if (not file) + { + std::cerr << "error: file '" << filename + << "' not found!"; + abort(); + } + char type; + int nrows, ncols; + internal::read_pnm_header('2', '5', file, type, nrows, ncols); + image2d<unsigned char> ima(nrows, ncols); + if (type = '5') + internal::load_pgm_raw_2d(file, ima); + else + if (type = '2') + internal::load_pgm_ascii(file, ima); + return ima; + } + + } // end of namespace oln::io + +} // end of namespace oln + + +#endif // ! OLN_IO_LOAD_PGM_HH
participants (1)
-
Thierry Geraud