
https://svn.lrde.epita.fr/svn/oln/trunk/olena criteres ? - contrat sur les attributs. - implementation par defaut. - fragmentation du code / lisibilite. - temps d'execution. - temps de compilation. - simplicite. - coherance. - clarte des messages d'erreurs. v0: procedure -ecriture difficile et longue -pas forcement plus rapide qu'avec un canevas v1: donnees tenues +performant +tres lisible -function obligatoirement parametree v2: donnees tenues sauf image -moins coherent que v1 +la function peut ne pas etre parametree v3: donnee passe en argument dans une classe. -peu elegant -lent ? ... v4: heritage +performant +principe naturelle en poo +function peut etre tres specifique (pas de parametre) -fragmentation du code si classe de factorisation -lisibilite bof (code perdu parmis les appelles d'implementation) +permet d'imposer des attributs CODE: ------------------------------------------- #include <oln/core/2d/image2d.hh> #include <oln/core/2d/neighb2d.hh> #include <oln/canvas/two_pass.hh> #include <oln/morpho/cc_tarjan_v ? .hh> int main() { using namespace oln; unsigned N = 1024; image2d<bool> img(N, N); float tmp; for (unsigned i = 0; i < N; i++) for (unsigned j = 0; j < N; j++) { tmp = 5 * cos(i) * cos(j); img.at(i, j) = (tmp > 0) ? tmp : 0; } morpho::cc_tarjan(img + c4); } ------------------------------------------- Without Options : ----------------- test_v0: compile: 16.357s execution: 1m27.001s test_v1 compile: 16.229s execution: 1m14.485s test_v2 compile: 16.485s execution: 1m20.421s test_v4 compile: 16.377s execution: 1m13.705s -O3 -DNDEBUG : -------------- test_v0 compile: 1m5.236s execution: 1.732s test_v1 compile: 1m7.844s execution: 1.560s test_v2 compile: 1m7.528s execution: 1.724s test_v4 compile: 1m7.624s execution: 1.560s -O2 -DNDEBUG : -------------- test_v0 compile: 1m3.108s execution: 4.196s test_v1 compile: 1m7.872s execution: 3.856s test_v2 compile: 1m9.240s execution: 4.328s test_v4 compile: 1m8.360s execution: 3.720s -O1 -DNDEBUG : -------------- test_v0 compile: 21.301s execution: 4.692s test_v1 compile: 22.145s execution: 4.336s test_v2 compile: 22.185s execution: 4.604s test_v4 compile: 22.069s execution: 4.620s --------------- version procedurale plus lente !?? Index: ChangeLog from Ugo Jardonnet <ugo.jardonnet@lrde.epita.fr> Fix Reconstruction. Draft canvas unionfind. . * oln/morpho/binary_reconstruction_v0.hh: . * oln/morpho/cc_tarjan_v4.hh: . * oln/morpho/cc_tarjan_v1.hh: . * oln/level/local_sup.hh: . * oln/level/local_inf.hh: . * oln/canvas/union_find.hh: . * oln/canvas/two_pass.hh: . canvas/two_pass.hh | 104 ++++++++++++++++++++++++++++++------- canvas/union_find.hh | 27 ++++++--- level/local_inf.hh | 18 +++--- level/local_sup.hh | 18 +++--- morpho/binary_reconstruction_v0.hh | 40 +++++++------- morpho/cc_tarjan_v1.hh | 5 - morpho/cc_tarjan_v4.hh | 76 ++++++++++++--------------- 7 files changed, 181 insertions(+), 107 deletions(-) Index: oln/morpho/binary_reconstruction_v0.hh --- oln/morpho/binary_reconstruction_v0.hh (revision 974) +++ oln/morpho/binary_reconstruction_v0.hh (working copy) @@ -33,6 +33,7 @@ # include <oln/accumulator/max.hh> # include <oln/level/clone.hh> # include <oln/level/fill.hh> +# include <oln/level/compare.hh> # include <oln/level/local_inf.hh> # include <oln/level/local_sup.hh> @@ -52,18 +53,6 @@ namespace impl { - template <typename I> - bool - stability(const Image_with_Nbh<I>& marker, - oln_plain(I)& tmp) - { - oln_piter(I) p(marker.points()); - for_all(p) - if (marker(p) != tmp(p)) - return false; - return true; - } - template <typename I, typename J> oln_plain(I) binary_reconstruction_loop(const Image_with_Nbh<I>& marker, @@ -88,19 +77,32 @@ } template <typename I , typename J> - void // FIXME : Slow impl. + oln_plain(I) binary_reconstruction_(const Image_with_Nbh<I>& marker, const Binary_Image<J>& mask) { - oln_plain(I) tmp = level::clone(marker); + accumulator::max_<oln_value(I)> max; + oln_plain(I) + output = level::clone(marker), + memo; - while ( not stability(marker, tmp) ) + do { - level::fill(inplace(exact(marker).image()), tmp); - tmp = binary_reconstruction_loop(marker, mask); - } + memo = level::clone(output); - level::fill(inplace(exact(marker).image()), tmp); + // first pass + oln_fwd_piter(I) p1(marker.points()); + for_all(p1) + output(p1) = level::local_sup(max, output, p1) and mask(p1); + + // second pass + oln_bkd_piter(I) p2(marker.points()); + for_all(p2) + output(p2) = level::local_inf(max, output, p2) and mask(p2); + + } while (output != memo); + + return output; } } // end of namespace oln::morpho::impl Index: oln/morpho/cc_tarjan_v4.hh --- oln/morpho/cc_tarjan_v4.hh (revision 974) +++ oln/morpho/cc_tarjan_v4.hh (working copy) @@ -29,10 +29,9 @@ # define OLN_MORPHO_CC_TARJAN_HH # include <oln/core/concept/image.hh> -# include <oln/core/internal/f_ch_value.hh> - # include <oln/canvas/two_pass.hh> # include <oln/level/fill.hh> +# include <oln/core/internal/f_ch_value.hh> namespace oln { @@ -40,8 +39,6 @@ namespace morpho { - // Fwd declaration. - template <typename I> oln_plain_value(I, unsigned) cc_tarjan(const Image_with_Nbh<I>& f); @@ -50,95 +47,95 @@ namespace impl { - template <typename I> - struct cc_tarjan_ : public canvas::v4::two_pass<I> + struct cc_tarjan_ : public canvas::v4::two_pass<I, cc_tarjan_<I> > { typedef oln_point(I) point; + const I& f; + oln_plain_value(I, unsigned) output; oln_plain_value(I, bool) is_processed; oln_plain_value(I, point) parent; + unsigned nlabels; - cc_tarjan_(const I& img) + cc_tarjan_(const I& f) + : canvas::v4::two_pass<I, cc_tarjan_<I> >(f), + f(f) { } - void init() + void impl_init() { - prepare(is_processed, with, this.f); - prepare(output, with, this.f); - prepare(parent, with, this.f); + prepare(is_processed, with, f); + prepare(output, with, f); + prepare(parent, with, f); level::fill(inplace(is_processed), false); + nlabels = 0; } - void first_pass_body(const point& p) + void impl_first_pass_body(const point& p) { parent(p) = p; - if ( f(p) ) + if (f(p) == true) { - oln_niter(I) n(this.f, p); + oln_niter(I) n(f, p); for_all(n) { - if ( this.f(n) == true and is_processed(n) ) - do_union(this.f, n, p); + if ( f(n) == true and is_processed(n) ) + do_union(n, p); } is_processed(p) = true; } - } - void second_pass_body(const point& p) + void impl_second_pass_body(const point& p) { - unsigned current_label = 0; - if ( this.f(p) == true and parent(p) == p ) - output(p) = ++current_label; + if (f(p) == true) + { + if (parent(p) == p) + output(p) = ++nlabels; else output(p) = output(parent(p)); } + else + output(p) = 0; // bg label + } - void final() + void impl_final() { } - // auxiliary methods - point find_root(const I& ima, - const point& x) + point find_root(const point& x) // FIXME: or w/o const&? { - if (parent(x) != x) - { - parent(x) = find_root(ima, parent(x)); - return parent(x); - } + if (parent(x) == x) return x; + else + return parent(x) = find_root(parent(x)); } - void do_union(const I& ima, - const point& n, + void do_union(const point& n, const point& p) { - point r = find_root(ima, n); + point r = find_root(n); if (r != p) parent(r) = p; } - }; } // end of namespace oln::morpho::impl -// Facades. - template <typename I> oln_plain_value(I, unsigned) cc_tarjan(const Image_with_Nbh<I>& f) { - impl::cc_tarjan_<I> f_cc_tarjan(exact(f)); + impl::cc_tarjan_<I> cc(exact(f)); - f_cc_tarjan.run(); + cc.run(); - return f_cc_tarjan.output; + return cc.output; } # endif // ! OLN_INCLUDE_ONLY @@ -147,5 +144,4 @@ } // end of namespace oln - #endif // ! OLN_MORPHO_CC_TARJAN_HH Index: oln/morpho/cc_tarjan_v1.hh --- oln/morpho/cc_tarjan_v1.hh (revision 974) +++ oln/morpho/cc_tarjan_v1.hh (working copy) @@ -54,8 +54,7 @@ namespace impl { - template <typename I> // FIXME : template< op_<I, extended_by, N>, - // typename I, Typename N> ? + template <typename I> struct cc_tarjan_ { typedef oln_point(I) point; @@ -129,7 +128,7 @@ { point r = find_root(n); if (r != p) - parent(r) = p5A5A; + parent(r) = p; } }; Index: oln/level/local_sup.hh --- oln/level/local_sup.hh (revision 974) +++ oln/level/local_sup.hh (working copy) @@ -68,9 +68,9 @@ const oln_point(I)& p) { f.init_with(input(p)); - oln_niter(I) n(p, input); + oln_niter(I) n(input, p); for_all(n) - if (n > p) + if (n < p) f(input(n)); return f.value(); } @@ -86,9 +86,9 @@ f.init_with(input(p)); if (f.value() == true) return true; - oln_niter(I) n(p, input); + oln_niter(I) n(input, p); for_all(n) - if (n > p) + if (n < p) { f(input(n)); // FIXME: Change to f.take(input(n))? if (f.value() == true) @@ -106,9 +106,9 @@ const oln_point(I)& p) { f.init_with(input(p)); - oln_niter(I) n(p, input); + oln_niter(I) n(input, p); for_all(n) - if (n > p) + if (n < p) { f(input(n)); // FIXME: Change to f.take(input(n))? if (f.value() == false) @@ -135,7 +135,7 @@ f.init_with(input(p)); oln_qiter(W) q(win, p); for_all(q) - if (q > p) + if (q < p) if (input.owns_(q)) f(input(q)); return f.value(); @@ -155,7 +155,7 @@ return true; oln_qiter(W) q(win, p); for_all(q) - if (q > p) + if (q < p) { if (input.owns_(q)) f(input(q)); @@ -177,7 +177,7 @@ f.init_with(input(p)); oln_qiter(W) q(win, p); for_all(q) - if (q > p) + if (q < p) { if (input.owns_(q)) f(input(q)); Index: oln/level/local_inf.hh --- oln/level/local_inf.hh (revision 974) +++ oln/level/local_inf.hh (working copy) @@ -68,9 +68,9 @@ const oln_point(I)& p) { f.init_with(input(p)); - oln_niter(I) n(p, input); + oln_niter(I) n(input, p); for_all(n) - if (n < p) + if (n > p) f(input(n)); return f.value(); } @@ -86,9 +86,9 @@ f.init_with(input(p)); if (f.value() == true) return true; - oln_niter(I) n(p, input); + oln_niter(I) n(input, p); for_all(n) - if (n < p) + if (n > p) { f(input(n)); // FIXME: Change to f.take(input(n))? if (f.value() == true) @@ -106,9 +106,9 @@ const oln_point(I)& p) { f.init_with(input(p)); - oln_niter(I) n(p, input); + oln_niter(I) n(input, p); for_all(n) - if (n < p) + if (n > p) { f(input(n)); // FIXME: Change to f.take(input(n))? if (f.value() == false) @@ -135,7 +135,7 @@ f.init_with(input(p)); oln_qiter(W) q(win, p); for_all(q) - if (q < p) + if (q > p) if (input.owns_(q)) f(input(q)); return f.value(); @@ -155,7 +155,7 @@ return true; oln_qiter(W) q(win, p); for_all(q) - if (q < p) + if (q > p) { if (input.owns_(q)) f(input(q)); @@ -177,7 +177,7 @@ f.init_with(input(p)); oln_qiter(W) q(win, p); for_all(q) - if (q < p) + if (q > p) { if (input.owns_(q)) f(input(q)); Index: oln/canvas/union_find.hh --- oln/canvas/union_find.hh (revision 974) +++ oln/canvas/union_find.hh (working copy) @@ -43,15 +43,24 @@ oln_bkd_piter(I) p1(fun.f.points()); for_all(p1) { - fun.parent(p1) = p1; - if (fun.f(p) == true) + if (fun.is_in_I(p1)) { - oln_niter(I) n(f, p); + fun.make_set(p); + oln_niter(I) n(fun.f.points(), p); for_all(n) { + if ( fun.p_in_D_upper_or_equal(p1) ) + { if (is_processed(n)) - if (f.condition_bck(p1, n)) - fun.first_pass_body(p1); + fun.first_pass_body1(p1); + } + else + if ( fun.p_in_Do(p1) ) + fun.is_processed(p1) = false; + else ( fun.p_in_D_lower_or_equal(p1) ) + { + fun.first_pass_body2(p1); + } } } } @@ -60,10 +69,12 @@ oln_fwd_piter(I) p2(fun.f.points()); for_all(p2) { - if (fun.f(p2) == true) - if (fun.condition_fwd(p2)) + if (fun.is_in_I(p2)) { - fun.second_pass_body(p2); + if (fun.is_root(p2)) + fun.set_output_value(p2); + else + fun.output(p) = fun.output(fun.parent(p)) ; //bg label } } Index: oln/canvas/two_pass.hh --- oln/canvas/two_pass.hh (revision 974) +++ oln/canvas/two_pass.hh (working copy) @@ -25,11 +25,15 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#include <oln/core/concept/image.hh> - #ifndef OLN_CANVAS_TWO_PASS_HH # define OLN_CANVAS_TWO_PASS_HH +# include <oln/core/concept/image.hh> + + +namespace oln +{ + namespace canvas { @@ -39,7 +43,7 @@ typename I> // Data owned by f. void two_pass(F<I>& fun) { -// mlc::assert_< mlc_is_a(I, Image) >::check(); + mlc::assert_< mlc_is_a(I, Image) >::check(); fun.init(); @@ -62,7 +66,7 @@ template <typename F, typename I> void two_pass(F& fun, I f) { -// mlc::assert_< mlc_is_a(I, Image) >::check(); + mlc::assert_< mlc_is_a(I, Image) >::check(); fun.init(f); @@ -83,9 +87,9 @@ namespace v3 // Auxiliar data given as argument. { template <typename F, typename I, typename A> - void two_pass(F fun, I f, A& aux) + void two_pass(F& fun, I& f, A& aux) { -// mlc::assert_< mlc_is_a(I, Image) >::check(); + mlc::assert_< mlc_is_a(I, Image) >::check(); f.init(f, aux); @@ -106,51 +110,113 @@ namespace v4 // Via Inheritance. { + template <typename I, typename Exact> + struct two_pass : public virtual Any<Exact> + { + void init() + { + exact(this)->impl_init(); + } + + void first_pass_body(const oln_point(I)& p) + { + exact(this)->impl_first_pass_body(p); + } + + void second_pass_body(const oln_point(I)& p) + { + exact(this)->impl_second_pass_body(p); + } + + void final() + { + exact(this)->impl_final(); + } + + // Concrete method. + void run() + { + init(); + + // first pass + for_all(p1) + first_pass_body(p1); + + // second pass + + for_all(p2) + second_pass_body(p2); + + final(); + } + + + protected: + + // Ctor. + two_pass(const Image<I>& f) : + p1(f.points()), + p2(f.points()) + { + } - template <typename Exact> + oln_bkd_piter(I) p1; + oln_fwd_piter(I) p2; + + }; + } + + + namespace v5 + { + template<typename I, typename Exact> struct two_pass { + const I& f; + void init() { - this->exact().impl_init(); + assert(0 && "'void init()' not implemented."); } void final() { - this->exact().impl_final(); + assert(0 && "'void final()' not implemented."); } - void first_pass_body(const oln_point(I)& p) + void first_pass_body(const oln_point(I)&) { - this->exact().impl_first_pass_body(p); + assert(0 && "'void first_pass_body(const oln_point(I)& p)' not implemented."); } - void second_pass_body(const oln_point(I)& p) + void second_pass_body(const oln_point(I)&) { - this->exact().impl_second_pass_body(p); + assert(0 && "'void second_pass_body(const oln_point(I)& p)' not implemented."); } void run() { - init(f); + init(); // first pass - oln_bkd_piter(typename Exact::I) p1(f.points()); + oln_bkd_piter(I) p1(f.points()); for_all(p1) first_pass_body(p1); // second pass - oln_fwd_piter(typename Exact::I) p2(f.points()); + oln_fwd_piter(I) p2(f.points()); for_all(p2) second_pass_body(p2); - final(f); + typename Exact::final(); } }; - } + } // end of namespace v5 -} + } // end of namespace morpho + +} // end of namespace oln #endif // ! OLN_CANVAS_TWO_PASS_HH