• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List

mesh-complex-skel.cc

00001 // Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
00002 //
00003 // This file is part of Olena.
00004 //
00005 // Olena is free software: you can redistribute it and/or modify it under
00006 // the terms of the GNU General Public License as published by the Free
00007 // Software Foundation, version 2 of the License.
00008 //
00009 // Olena is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Olena.  If not, see <http://www.gnu.org/licenses/>.
00016 //
00017 // As a special exception, you may use this file as part of a free
00018 // software project without restriction.  Specifically, if other files
00019 // instantiate templates or use macros or inline functions from this
00020 // file, or you compile this file and link it with other files to produce
00021 // an executable, this file does not by itself cause the resulting
00022 // executable to be covered by the GNU General Public License.  This
00023 // exception does not however invalidate any other reasons why the
00024 // executable file might be covered by the GNU General Public License.
00025 
00030 
00031 #include <iostream>
00032 
00033 #include <mln/core/image/complex_image.hh>
00034 #include <mln/core/image/complex_neighborhoods.hh>
00035 
00036 #include <mln/core/site_set/p_set.hh>
00037 
00038 #include <mln/value/label_16.hh>
00039 
00040 #include <mln/labeling/regional_minima.hh>
00041 #include <mln/morpho/closing/area.hh>
00042 
00043 #include <mln/topo/is_n_face.hh>
00044 #include <mln/topo/is_simple_cell.hh>
00045 #include <mln/topo/detach.hh>
00046 #include <mln/topo/skeleton/breadth_first_thinning.hh>
00047 
00048 #include <mln/io/off/load.hh>
00049 /* FIXME: Remove as soon as mln::io::off::save is able to save a
00050    morphed mln::complex_image (i.e., seen through image_if).  */
00051 #include "save_bin_alt.hh"
00052 
00053 
00054 int
00055 main(int argc, char* argv[])
00056 {
00057   if (argc != 4)
00058     {
00059       std::cerr << "usage: " << argv[0] << " input.off lambda output.off"
00060                 << std::endl;
00061       std::exit(1);
00062     }
00063 
00064   std::string input_filename = argv[1];
00065   unsigned lambda = atoi(argv[2]);
00066   std::string output_filename = argv[3];
00067 
00068   /*----------------.
00069   | Complex image.  |
00070   `----------------*/
00071 
00072   // Image type.
00073   typedef mln::float_2complex_image3df ima_t;
00074   // Dimension of the image (and therefore of the complex).
00075   static const unsigned D = ima_t::dim;
00076   // Geometry of the image.
00077   typedef mln_geom_(ima_t) G;
00078 
00079   ima_t input;
00080   mln::io::off::load(input, input_filename);
00081 
00082   /* FIXME: Workaround: Set maximal values on vertices and edges to
00083      exclude them from the set of minimal values.  */
00084   mln::p_n_faces_fwd_piter<D, G> v(input.domain(), 0);
00085   for_all(v)
00086     input(v) = mln_max(float);
00087   mln::p_n_faces_fwd_piter<D, G> e(input.domain(), 1);
00088   for_all(e)
00089     input(e) = mln_max(float);
00090 
00091   /*-----------------.
00092   | Simplification.  |
00093   `-----------------*/
00094 
00096   typedef mln::complex_lower_dim_connected_n_face_neighborhood<D, G> nbh_t;
00097   nbh_t nbh;
00098 
00099   ima_t closed_input = mln::morpho::closing::area(input, nbh, lambda);
00100 
00101   /*---------------.
00102   | Local minima.  |
00103   `---------------*/
00104 
00105   typedef mln::value::label_16 label_t;
00106   label_t nminima;
00107 
00108   /* FIXME: We should use something like `ima_t | p_n_faces(2)' instead
00109      of `ima_t' here.  Or better: `input' should only associate data
00110      to 2-faces.  */
00111   typedef mln_ch_value_(ima_t, label_t) label_ima_t;
00112   label_ima_t minima =
00113     mln::labeling::regional_minima(closed_input, nbh, nminima);
00114 
00115   typedef mln::complex_higher_neighborhood<D, G> higher_nbh_t;
00116   higher_nbh_t higher_nbh;
00117 
00118   // Propagate minima values from triangles to edges.
00119   // FIXME: Factor this inside a function.
00120   mln_niter_(higher_nbh_t) adj_t(higher_nbh, e);
00121   for_all(e)
00122   {
00123     label_t ref_adj_minimum = mln::literal::zero;
00124     for_all(adj_t)
00125       if (minima(adj_t) == mln::literal::zero)
00126         {
00127           // If E is adjcent to a non-minimal triangle, then it must
00128           // not belong to a minima.
00129           ref_adj_minimum = mln::literal::zero;
00130           break;
00131         }
00132       else
00133         {
00134           if (ref_adj_minimum == mln::literal::zero)
00135             // If this is the first minimum seen, use it as a reference.
00136             ref_adj_minimum = minima(adj_t);
00137           else
00138             // If this is not the first time a minimum is encountered,
00139             // ensure it is REF_ADJ_MINIMUM.
00140             mln_assertion(minima(adj_t) == ref_adj_minimum);
00141         }
00142     minima(e) = ref_adj_minimum;
00143   }
00144 
00145   // Likewise from edges to edges to vertices.
00146   mln_niter_(higher_nbh_t) adj_e(higher_nbh, v);
00147   for_all(v)
00148   {
00149     label_t ref_adj_minimum = mln::literal::zero;
00150     for_all(adj_e)
00151       if (minima(adj_e) == mln::literal::zero)
00152         {
00153           // If V is adjcent to a non-minimal triangle, then it must
00154           // not belong to a minima.
00155           ref_adj_minimum = mln::literal::zero;
00156           break;
00157         }
00158       else
00159         {
00160           if (ref_adj_minimum == mln::literal::zero)
00161             // If this is the first minimum seen, use it as a reference.
00162             ref_adj_minimum = minima(adj_e);
00163           else
00164             // If this is not the first time a minimum is encountered,
00165             // ensure it is REF_ADJ_MINIMUM.
00166             mln_assertion(minima(adj_e) == ref_adj_minimum);
00167         }
00168     minima(v) = ref_adj_minimum;
00169   }
00170 
00171   /*-----------------------.
00172   | Initial binary image.  |
00173   `-----------------------*/
00174 
00175   typedef mln_ch_value_(ima_t, bool) bin_ima_t;
00176   bin_ima_t surface(minima.domain());
00177   mln::data::fill(surface, true);
00178   // Dig ``holes'' in the surface surface by setting minima faces to false.
00179   // FIXME: Use fill with an image_if instead, when available/working.
00180   mln_piter_(bin_ima_t) f(minima.domain());
00181   for_all(f)
00182     if (minima(f) != mln::literal::zero)
00183       surface(f) = false;  
00184 
00185   /*-----------.
00186   | Skeleton.  |
00187   `-----------*/
00188 
00189   mln::topo::is_simple_cell<bin_ima_t> is_simple_p;
00190     /* FIXME: Cheat!  We'd like to iterate on cells of highest
00191        dimension (2-cells) only, but we cannot constrain the domain of
00192        the input using image_if (yet) like this
00193 
00194          breadth_first_thinning(surface | is_n_face<2>, nbh, is_simple_p);
00195 
00196        As a workaround, we use the constraint predicate of the
00197        skeleton routine to restrict the iteration to 2-cells.  */
00198   mln::topo::is_n_face<bin_ima_t::dim> constraint_p;
00199   bin_ima_t skel =
00200     mln::topo::skeleton::breadth_first_thinning(surface, nbh,
00201                                                 is_simple_p,
00202                                                 mln::topo::detach<D, G>,
00203                                                 constraint_p);
00204 
00205   /*---------.
00206   | Output.  |
00207   `---------*/
00208 
00209   /* FIXME: This does not work (yet).
00210      Use workaround mln::io::off::save_bin_salt instead (bad!)  */
00211 #if 0
00212   mln::io::off::save(skel | mln::pw::value(skel) == mln::pw::cst(true),
00213                      output_filename);
00214 #endif
00215   mln::io::off::save_bin_alt(skel, output_filename);
00216 }

Generated on Tue Oct 4 2011 15:24:05 for Milena (Olena) by  doxygen 1.7.1