Milena (Olena)
User documentation 2.0a Id
|
00001 // Copyright (C) 2007, 2008, 2009 EPITA Research and Development 00002 // Laboratory (LRDE) 00003 // 00004 // This file is part of Olena. 00005 // 00006 // Olena is free software: you can redistribute it and/or modify it under 00007 // the terms of the GNU General Public License as published by the Free 00008 // Software Foundation, version 2 of the License. 00009 // 00010 // Olena is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 // General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Olena. If not, see <http://www.gnu.org/licenses/>. 00017 // 00018 // As a special exception, you may use this file as part of a free 00019 // software project without restriction. Specifically, if other files 00020 // instantiate templates or use macros or inline functions from this 00021 // file, or you compile this file and link it with other files to produce 00022 // an executable, this file does not by itself cause the resulting 00023 // executable to be covered by the GNU General Public License. This 00024 // exception does not however invalidate any other reasons why the 00025 // executable file might be covered by the GNU General Public License. 00026 00027 #ifndef MLN_CANVAS_MORPHO_ATTRIBUTE_FILTER_HH 00028 # define MLN_CANVAS_MORPHO_ATTRIBUTE_FILTER_HH 00029 00033 00034 00035 # include <mln/core/concept/image.hh> 00036 # include <mln/core/concept/neighborhood.hh> 00037 # include <mln/core/concept/accumulator.hh> 00038 00039 # include <mln/data/sort_offsets.hh> 00040 # include <mln/trait/accumulators.hh> 00041 # include <mln/util/pix.hh> 00042 00043 # include <mln/border/get.hh> 00044 # include <mln/data/fill.hh> 00045 # include <mln/extension/adjust_fill.hh> 00046 # include <mln/data/sort_psites.hh> 00047 00048 namespace mln 00049 { 00050 00051 namespace canvas 00052 { 00053 00054 namespace morpho 00055 { 00056 00057 // FIXME: Doc! 00058 00059 template <typename I, typename N, typename A> 00060 mln_concrete(I) 00061 attribute_filter(const Image<I>& input, const Neighborhood<N>& nbh, 00062 const Accumulator<A>& a, const mln_result(A)& lambda, 00063 bool increasing); 00064 00065 00066 00067 # ifndef MLN_INCLUDE_ONLY 00068 00069 namespace impl 00070 { 00071 00072 template <typename A, typename I> 00073 void take_as_init_fastest(trait::accumulator::when_pix::use_none, A& accu, 00074 const I& input, const unsigned p) 00075 { 00076 (void)input; 00077 (void)p; 00078 accu.take_as_init(); 00079 } 00080 00081 template <typename A, typename I, typename P> 00082 void take_as_init(trait::accumulator::when_pix::use_p, A& accu, 00083 const I& input, const P& p) 00084 { 00085 (void)input; 00086 accu.take_as_init(p); 00087 } 00088 00089 template <typename A, typename I, typename P> 00090 void take_as_init(trait::accumulator::when_pix::use_none, A& accu, 00091 const I& input, const P& p) 00092 { 00093 (void)input; 00094 (void)p; 00095 accu.take_as_init(); 00096 } 00097 00098 template <typename A, typename I, typename P> 00099 void take_as_init(trait::accumulator::when_pix::use_pix, A& accu, 00100 const I& input, const P& p) 00101 { 00102 accu.take_as_init(make::pix(input, p)); 00103 } 00104 00105 template <typename A, typename I, typename P> 00106 void take_as_init(trait::accumulator::when_pix::use_v, A& accu, 00107 const I& input, const P& p) 00108 { 00109 accu.take_as_init(input(p)); 00110 } 00111 00112 template <typename A, typename I> 00113 void take_as_init_fastest(trait::accumulator::when_pix::use_v, A& accu, 00114 const I& input, const unsigned p) 00115 { 00116 accu.take_as_init(input.element(p)); 00117 } 00118 00119 00120 template <typename A, typename I, typename P> 00121 void take_as_init(A& accu, const I& input, const P& p) 00122 { 00123 take_as_init(mln_trait_accumulator_when_pix(A)(), accu, input, p); 00124 } 00125 00126 template <typename A, typename I, typename P> 00127 void take_as_init_fastest(A& accu, const I& input, const P& p) 00128 { 00129 take_as_init_fastest(mln_trait_accumulator_when_pix(A)(), accu, input, p); 00130 } 00131 00132 00133 00134 namespace generic 00135 { 00136 00140 00141 00142 template <typename I> 00143 static inline 00144 mln_psite(I) 00145 find_root(I& parent, const mln_psite(I) & x) 00146 { 00147 if (parent(x) == x) 00148 return x; 00149 else 00150 return parent(x) = find_root(parent, parent(x)); 00151 } 00152 00153 template <typename I, typename N, typename S, typename A> 00154 mln_concrete(I) 00155 attribute_filter(const Image<I>& input_, 00156 const Neighborhood<N>& nbh_, 00157 const Site_Set<S>& s_, 00158 const Accumulator<A>& a_, 00159 const mln_result(A)& lambda) 00160 { 00161 trace::entering("canvas::morpho::impl::generic::attribute_filter"); 00162 // FIXME: Test?! 00163 00164 const I& input = exact(input_); 00165 const N& nbh = exact(nbh_); 00166 const S& s = exact(s_); 00167 (void)a_; // To avoid warning at compilation 00168 00169 mln_concrete(I) output; 00170 initialize(output, input); 00171 00172 // Local type. 00173 typedef mln_psite(I) P; 00174 00175 00176 // Auxiliary data. 00177 mln_ch_value(I, bool) deja_vu; 00178 mln_ch_value(I, bool) activity; 00179 mln_ch_value(I, P) parent; 00180 mln_ch_value(I, A) data; 00181 00182 // Initialization. 00183 { 00184 initialize(deja_vu, input); 00185 data::fill(deja_vu, false); 00186 initialize(activity, input); 00187 data::fill(activity, true); 00188 initialize(parent, input); 00189 initialize(data, input); 00190 //a.init(); // init required. 00191 } 00192 00193 // First pass. 00194 { 00195 mln_fwd_piter(S) p(s); // s required. 00196 mln_niter(N) n(nbh, p); 00197 00198 for_all(p) 00199 { 00200 // Make set. 00201 { 00202 parent(p) = p; 00203 00204 // Check accumulator trait to handle argument type (Pix or Site). 00205 take_as_init(data(p), input, p); 00206 } 00207 00208 for_all(n) 00209 if (input.domain().has(n) && deja_vu(n)) 00210 { 00211 //do_union(n, p); 00212 P r = find_root(parent, n); 00213 if (r != p) 00214 { 00215 if (input(r) == input(p) || (activity(r) && (data(r) < lambda))) // Equiv(r, p) 00216 // Either a flat zone or the component of r is still growing. 00217 { 00218 /* FIXME: Same remark as above concerning the 00219 initialization of data(p); instead of 00220 00221 data(p).take(data(r)); 00222 00223 we should (or could) have 00224 00225 unite_data(p, r); 00226 00227 so as to keep the generic aspect of this canvas 00228 (as long as the set of acceptable types for the 00229 template parameter A is not bound). */ 00230 00231 data(p).take(data(r)); 00232 parent(r) = p; 00233 if (activity(r) == false) 00234 activity(p) = false; 00235 } 00236 else 00237 { 00238 activity(p) = false; 00239 } 00240 } 00241 } 00242 deja_vu(p) = true; 00243 } 00244 } 00245 00246 // Second pass. 00247 { 00248 mln_bkd_piter(S) p(s); 00249 for_all(p) 00250 if (parent(p) == p) // p is root. 00251 output(p) = input(p); 00252 else 00253 output(p) = output(parent(p)); 00254 } 00255 00256 trace::exiting("canvas::morpho::impl::generic::attribute_filter"); 00257 return output; 00258 } 00259 00260 } // end of namespace mln::canvas::morpho::impl::generic 00261 00262 00266 00267 template <typename I> 00268 inline 00269 unsigned 00270 find_root_fastest(I& parent, unsigned x) 00271 { 00272 if (parent.element(x) == x) 00273 return x; 00274 else 00275 return parent.element(x) = find_root_fastest(parent, parent.element(x)); 00276 } 00277 00278 template <typename I, typename N, typename A> 00279 mln_concrete(I) 00280 attribute_filter_fastest(const Image<I>& input_, 00281 const Neighborhood<N>& nbh_, 00282 const util::array<unsigned>& s, 00283 const Accumulator<A>& a_, 00284 const mln_result(A)& lambda) 00285 { 00286 trace::entering("canvas::morpho::impl::attribute_filter_fastest"); 00287 // FIXME: Tests? 00288 00289 const I& input = exact(input_); 00290 const N& nbh = exact(nbh_); 00291 (void)a_; 00292 00293 // The border adaptation is performed in the calling scope since 00294 // we want offsets of 's' to match the image structure / dimensions. 00295 mln_precondition(border::get(input) >= nbh.delta()); 00296 00297 mln_concrete(I) output; 00298 initialize(output, input); 00299 00300 // Local type. 00301 typedef mln_psite(I) P; 00302 00303 // Auxiliary data. 00304 mln_ch_value(I, bool) deja_vu; 00305 mln_ch_value(I, bool) activity; 00306 mln_ch_value(I, unsigned) parent; 00307 mln_ch_value(I, A) data; 00308 00309 // Initialization. 00310 { 00311 initialize(deja_vu, input); 00312 data::fill(deja_vu, false); 00313 extension::fill(deja_vu, false); // So the border is neutral. 00314 00315 initialize(activity, input); 00316 data::fill(activity, true); 00317 initialize(parent, input); 00318 data::fill(parent, 0); 00319 initialize(data, input); 00320 } 00321 00322 util::array<int> dp = offsets_wrt(input, nbh); 00323 const unsigned n_nbhs = dp.nelements(); 00324 const unsigned n_points = s.nelements(); 00325 00326 // First pass. 00327 { 00328 for (unsigned i = 0; i < n_points; ++i) 00329 { 00330 unsigned p = s[i]; // An offset. 00331 00332 // Make set. 00333 parent.element(p) = p; 00334 00335 // Check accumulator trait to handle argument type (Value or None). 00336 take_as_init_fastest(data.element(p), input, p); 00337 00338 for (unsigned j = 0; j < n_nbhs; ++j) 00339 { 00340 unsigned n = p + dp[j]; 00341 if (! deja_vu.element(n)) 00342 continue; 00343 00344 unsigned r = find_root_fastest(parent, n); 00345 if (r != p) 00346 { 00347 if (input.element(r) == input.element(p) 00348 || (activity.element(r) 00349 && (data.element(r) < lambda))) 00350 { 00351 data.element(p).take(data.element(r)); 00352 parent.element(r) = p; 00353 if (activity.element(r) == false) 00354 activity.element(p) = false; 00355 } 00356 else 00357 activity.element(p) = false; 00358 } 00359 } 00360 00361 deja_vu.element(p) = true; 00362 } 00363 } 00364 00365 00366 // Second pass. 00367 { 00368 for (int i = n_points - 1; i >= 0 ; --i) 00369 { 00370 unsigned p = s[i]; 00371 if (parent.element(p) == p) // p is root. 00372 output.element(p) = input.element(p); 00373 else 00374 output.element(p) = output.element(parent.element(p)); 00375 } 00376 } 00377 00378 trace::exiting("canvas::morpho::impl::attribute_filter_fastest"); 00379 return output; 00380 } 00381 00382 } // end of namespace mln::canvas::morpho::impl 00383 00384 00385 00386 00387 // Dispatch. 00388 00389 00390 namespace internal 00391 { 00392 00393 // Dispatch to generic. 00394 00395 template <typename I, typename N, typename A> 00396 inline 00397 mln_concrete(I) 00398 attribute_filter_dispatch(metal::false_, 00399 const Image<I>& input, 00400 const Neighborhood<N>& nbh, 00401 const Accumulator<A>& a, 00402 const mln_result(A)& lambda, 00403 bool increasing) 00404 { 00405 p_array<mln_psite(I)> s = increasing ? 00406 data::sort_psites_increasing(input) : 00407 data::sort_psites_decreasing(input); 00408 00409 return impl::generic::attribute_filter(input, nbh, s, a, lambda); 00410 } 00411 00412 00413 // Dispatch to fastest. 00414 00415 template <typename I, typename N, typename A> 00416 inline 00417 mln_concrete(I) 00418 attribute_filter_dispatch(metal::true_, 00419 const Image<I>& input, 00420 const Neighborhood<N>& nbh, 00421 const Accumulator<A>& a, 00422 const mln_result(A)& lambda, 00423 bool increasing) 00424 { 00425 extension::adjust(input, nbh); 00426 00427 util::array<unsigned> s = 00428 increasing ? 00429 data::sort_offsets_increasing(input) : 00430 data::sort_offsets_decreasing(input); 00431 00432 return impl::attribute_filter_fastest(input, nbh, s, a, lambda); 00433 } 00434 00435 00436 00437 template <typename I, typename N, typename A> 00438 inline 00439 mln_concrete(I) 00440 attribute_filter_dispatch(const Image<I>& input, 00441 const Neighborhood<N>& nbh, 00442 const Accumulator<A>& a, 00443 const mln_result(A)& lambda, 00444 bool increasing) 00445 { 00446 enum { 00447 test = (mlc_equal(mln_trait_image_speed(I), 00448 trait::image::speed::fastest)::value && 00449 mln_is_simple_neighborhood(N)::value && 00450 (mlc_equal(mln_trait_accumulator_when_pix(A), 00451 trait::accumulator::when_pix::use_none)::value || 00452 mlc_equal(mln_trait_accumulator_when_pix(A), 00453 trait::accumulator::when_pix::use_v)::value)) 00454 }; 00455 return attribute_filter_dispatch(metal::bool_<test>(), input, nbh, a, lambda, increasing); 00456 } 00457 00458 } // end of namespace mln::canvas::morpho::internal 00459 00460 00461 00462 // Facade. 00463 00464 template <typename I, typename N, typename A> 00465 inline 00466 mln_concrete(I) 00467 attribute_filter(const Image<I>& input, 00468 const Neighborhood<N>& nbh, 00469 const Accumulator<A>& a, 00470 const mln_result(A)& lambda, 00471 bool increasing) 00472 { 00473 return internal::attribute_filter_dispatch(input, nbh, a, lambda, increasing); 00474 } 00475 00476 00477 # endif // ! MLN_INCLUDE_ONLY 00478 00479 } // end of namespace mln::canvas::morpho 00480 00481 } // end of namespace mln::canvas 00482 00483 } // end of namespace mln 00484 00485 00486 #endif // ! MLN_CANVAS_MORPHO_ATTRIBUTE_FILTER_HH