DGtalTools  0.9.4
volSurfaceRegularization.cpp
1 
84 #include <DGtal/base/Common.h>
85 #include <DGtal/helpers/StdDefs.h>
86 #include <boost/program_options/options_description.hpp>
87 #include <boost/program_options/positional_options.hpp>
88 #include <boost/program_options/variables_map.hpp>
89 #include <boost/program_options/parsers.hpp>
90 #include <boost/program_options/errors.hpp>
91 #include <DGtal/images/ImageSelector.h>
92 #include <DGtal/io/readers/GenericReader.h>
93 #include <random>
94 #include <iomanip>
95 #include <regex>
96 #include "volSurfaceRegularization-details/surface_approx.h"
97 #include "volSurfaceRegularization-details/surface_extract.h"
98 #include "volSurfaceRegularization-details/shape.h"
99 
100 
101 struct Options
102 {
103  double noise_level;
104  std::string image_filename;
105  double normal_radius;
106  double regularization_position;
107  double regularization_center;
108  double align;
109  double fairness;
110  double barycenter;
111  std::string regularized_obj_filename;
112  std::string cubical_obj_filename;
113 };
114 
115 Options
116 parse_options(int argc, char* argv[])
117 {
118  namespace po = boost::program_options;
119 
120  using DGtal::trace;
121  using std::endl;
122 
123  Options options;
124  po::options_description po_shape("File options");
125  po_shape.add_options()
126  ("image-filename,i", po::value<std::string>(&options.image_filename)->default_value(""), "input vol filename for image shape (object voxels have values > 0) or input cvs filename for surfels and normals")
127  ("regularized-obj-filename,o", po::value<std::string>(&options.regularized_obj_filename)->default_value(""), "output regularized obj")
128  ("cubical-obj-filename,n", po::value<std::string>(&options.cubical_obj_filename)->default_value(""), "output cubical obj")
129  ("shape-noise,k", po::value<double>(&options.noise_level)->default_value(0), "noise shape parameter")
130  ;
131 
132  po::options_description po_normal("Normal field estimator options");
133  po_normal.add_options()
134  ("normal-radius,r", po::value<double>(&options.normal_radius)->default_value(4), "radius of normal estimator")
135  ;
136 
137  po::options_description po_approx("Surface approximation options");
138  po_approx.add_options()
139  ("regularization-position,p", po::value<double>(&options.regularization_position)->default_value(1e-3, "1e-3"), "vertex position regularization coeff")
140  ("regularization-center,c", po::value<double>(&options.regularization_center)->default_value(1e-2, "1e-2"), "face center regularization coeff")
141  ("align,a", po::value<double>(&options.align)->default_value(1), "normal alignment coeff")
142  ("fairness,f", po::value<double>(&options.fairness)->default_value(0), "face fairness coeff")
143  ("barycenter,b", po::value<double>(&options.barycenter)->default_value(1e-1, "1e-1"), "barycenter fairness coeff")
144  ;
145 
146  po::options_description po_options("surfaceApprox [options]");
147  po_options.add(po_shape).add(po_normal).add(po_approx).add_options()
148  ("help,h", "display this message")
149  ;
150 
151  po::positional_options_description positional;
152  positional.add("image-filename",1);
153  positional.add("regularized-obj-filename",1);
154 
155  try
156  {
157  po::variables_map vm;
158  po::store(po::command_line_parser(argc, argv).options(po_options).positional(positional).run(), vm);
159  po::notify(vm);
160 
161  if (vm.count("help"))
162  {
163  trace.info() << po_options;
164  std::exit(0);
165  }
166 
167  if (options.image_filename.empty()) throw po::validation_error(po::validation_error::invalid_option_value);
168  if (options.regularized_obj_filename.empty()) throw po::validation_error(po::validation_error::invalid_option_value);
169  }
170  catch (std::exception& ex)
171  {
172  trace.error() << ex.what() << endl;
173  trace.info() << po_options;
174  std::exit(1);
175  }
176 
177  return options;
178 }
179 
180 
181 int main(int argc, char* argv[])
182 {
183  using DGtal::trace;
184  using std::endl;
185  using DGtal::PRIMAL;
186  using DGtal::DUAL;
187 
188  const Options options = parse_options(argc, argv);
189 
190  const KSpace kspace;
191 
192  const Calculus calculus;
193  const FlatVector original_face_normals;
194 
195  if (!ends_with(options.image_filename, ".csv"))
196  {
197  ASSERT( !options.image_filename.empty() );
198  typedef DGtal::Z3i::Domain Domain;
200  trace.info() << "image_filename=" << options.image_filename << endl;
201  ImageUChar image_uchar = DGtal::GenericReader<ImageUChar>::import(options.image_filename);
202  const Domain domain = image_uchar.domain();
203  trace.info() << "domain=" << domain << endl;
204  const Point center = (domain.upperBound()+domain.lowerBound())/2;
205  trace.info() << "center=" << center << endl;
206  const ImageShape<ImageUChar> shape(&image_uchar, center);
207 
208  const_cast<KSpace&>(kspace).init(domain.lowerBound()-center-Point::diagonal(1), domain.upperBound()-center+Point::diagonal(1), true);
209 
210  std::tie(const_cast<Calculus&>(calculus), const_cast<FlatVector&>(original_face_normals)) =
211  initCalculusAndNormalsWithNoise(kspace, shape, options.normal_radius, options.noise_level);
212  }
213 
214  if (ends_with(options.image_filename, ".csv"))
215  {
216  ASSERT( !options.image_filename.empty() );
217  trace.info() << "csv_filename=" << options.image_filename << endl;
218  std::tie(const_cast<Calculus&>(calculus), const_cast<FlatVector&>(original_face_normals)) =
219  initCalculusAndNormalsFromSurfelNormalsCSV(options.image_filename);
220  }
221 
222  const FlatVector original_vertex_normals = vertexNormals(calculus, original_face_normals);
223 
224  const FlatVector original_positions;
225  const FlatVector regularized_positions;
226  const FlatVector original_centers;
227  const FlatVector regularized_centers;
228  std::tie(const_cast<FlatVector&>(original_positions),
229  const_cast<FlatVector&>(regularized_positions),
230  const_cast<FlatVector&>(original_centers),
231  const_cast<FlatVector&>(regularized_centers)) =
232  approximateSurface(calculus, original_face_normals,
233  ApproxParams({options.regularization_position, options.regularization_center, options.align, options.fairness, options.barycenter}));
234  ASSERT( original_positions.size() == 3*calculus.kFormLength(0, PRIMAL) );
235  ASSERT( regularized_positions.size() == 3*calculus.kFormLength(0, PRIMAL) );
236  ASSERT( original_centers.size() == 3*calculus.kFormLength(2, PRIMAL) );
237  ASSERT( regularized_centers.size() == 3*calculus.kFormLength(2, PRIMAL) );
238 
239  {
240  trace.beginBlock( "computing energies" );
241 
242  {
243  double position_energy = 0;
244  double align_energy = 0;
245  std::tie( position_energy, align_energy ) = approximateSurfaceEnergies(
246  calculus, original_face_normals, original_positions );
247  align_energy *= options.align;
248  position_energy *= options.regularization_position;
249  trace.info() << "original_energies=" << position_energy << " "
250  << align_energy << " " << position_energy + align_energy
251  << endl;
252  }
253 
254  {
255  double position_energy = 0;
256  double align_energy = 0;
257  std::tie(position_energy, align_energy) = approximateSurfaceEnergies(calculus, original_face_normals, regularized_positions);
258  align_energy *= options.align;
259  position_energy *= options.regularization_position;
260  trace.info() << "regularized_energies=" << position_energy << " " << align_energy << " " << position_energy+align_energy << endl;
261  }
262 
263  trace.endBlock();
264  }
265 
266  {
267  ASSERT( !options.regularized_obj_filename.empty() );
268  trace.info() << "regularized_obj_filename=" << options.regularized_obj_filename << endl;
269  exportOBJ(calculus, regularized_positions, options.regularized_obj_filename);
270  }
271 
272  if (!options.cubical_obj_filename.empty())
273  {
274  ASSERT( !options.cubical_obj_filename.empty() );
275  trace.info() << "cubical_obj_filename=" << options.cubical_obj_filename << endl;
276  exportOBJ(calculus, original_positions, options.cubical_obj_filename);
277  }
278 
279  return 0;
280 }
281 
282 
void beginBlock(const std::string &keyword="")
double endBlock()
static TContainer import(const std::string &filename, std::vector< unsigned int > dimSpace=std::vector< unsigned int >())
Trace trace(traceWriterTerm)
std::ostream & info()
typename Self::Point Point
std::ostream & error()
Index kFormLength(const Order &order, const Duality &duality) const
typename Self::Domain Domain