Milena (Olena)
User documentation 2.0a Id
|
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 }