DGtalTools  0.9.4
3dCompSurfelData.cpp
1 
28 
30 #include <iostream>
31 #include <QGLViewer/qglviewer.h>
32 #include <stdio.h>
33 
34 #include "DGtal/base/Common.h"
35 #include "DGtal/helpers/StdDefs.h"
36 #include "DGtal/io/viewers/Viewer3D.h"
37 #include "DGtal/io/DrawWithDisplay3DModifier.h"
38 #include "DGtal/io/readers/PointListReader.h"
39 #include "DGtal/io/readers/MeshReader.h"
40 #include "DGtal/io/colormaps/GradientColorMap.h"
41 
42 #include "DGtal/topology/helpers/Surfaces.h"
43 #include "DGtal/topology/SurfelAdjacency.h"
44 #include "DGtal/topology/CanonicCellEmbedder.h"
45 #include "DGtal/math/Statistic.h"
46 
47 #include "DGtal/io/Color.h"
48 #include "DGtal/io/colormaps/GradientColorMap.h"
49 #include "DGtal/io/readers/GenericReader.h"
50 
51 #include <boost/program_options/options_description.hpp>
52 #include <boost/program_options/parsers.hpp>
53 #include <boost/program_options/variables_map.hpp>
54 
55 #include <limits>
56 
57 using namespace std;
58 using namespace DGtal;
59 using namespace Z3i;
60 
62 namespace po = boost::program_options;
63 
64 
65 
130 template < typename Space = DGtal::Z3i::Space, typename KSpace = DGtal::Z3i::KSpace>
131 struct ViewerSnap: DGtal::Viewer3D <Space, KSpace>
132 {
133 
134  ViewerSnap(const KSpace &KSEmb, bool saveSnap): Viewer3D<Space, KSpace>(KSEmb), mySaveSnap(saveSnap){
135  };
136 
137  virtual void
138  init(){
140  if(mySaveSnap){
141  QObject::connect(this, SIGNAL(drawFinished(bool)), this, SLOT(saveSnapshot(bool)));
142  }
143  };
144  bool mySaveSnap;
145 };
146 
147 
148 template < typename Point>
149 void
150 getBoundingUpperAndLowerPoint(const std::vector<Point> &vectorPt, Point &ptLower, Point &ptUpper){
151  for(unsigned int i =1; i<vectorPt.size(); i++){
152  if(vectorPt.at(i)[0] < ptLower[0]){
153  ptLower[0] = vectorPt.at(i)[0];
154  }
155  if(vectorPt.at(i)[1] < ptLower[1]){
156  ptLower[1] = vectorPt.at(i)[1];
157  }
158  if(vectorPt.at(i)[2] < ptLower[2]){
159  ptLower[2] =vectorPt.at(i)[2];
160  }
161  if(vectorPt.at(i)[0] < ptLower[0]){
162  ptLower[0] = vectorPt.at(i)[0];
163  }
164  if(vectorPt.at(i)[1] < ptLower[1]){
165  ptLower[1] = vectorPt.at(i)[1];
166  }
167  if(vectorPt.at(i)[2] < ptLower[2]){
168  ptLower[2] =vectorPt.at(i)[2];
169  }
170  }
171 }
172 
173 
174 int main( int argc, char** argv )
175 {
176 
177  typedef PointVector<4, double> Point4D;
178  typedef PointVector<1, int> Point1D;
179 
180  // parse command line ----------------------------------------------
181  po::options_description general_opt("Allowed options are: ");
182  general_opt.add_options()
183  ("help,h", "display this message")
184  ("input,i", po::value<std::string>(), "input file: sdpa (sequence of discrete points with attribute)" )
185  ("reference,r", po::value<std::string>(), "input reference file: sdpa (sequence of discrete points with attribute)" )
186  ("compAccordingLabels,l", "apply the comparisos only on points with same labels (by default fifth colomn)" )
187  ("drawSurfelAssociations,a", "Draw the surfel association." )
188  ("fileMeasureOutput,o", po::value<std::string>(), "specify the output file to store (append) the error stats else the result is given to std output. " )
189  ("noWindows,n", "Don't display Viewer windows." )
190  ("doSnapShotAndExit,d", po::value<std::string>(), "save display snapshot into file. Notes that the camera setting is set by default according the last saved configuration (use SHIFT+Key_M to save current camera setting in the Viewer3D)." )
191  ("fixMaxColorValue", po::value<double>(), "fix the maximal color value for the scale error display (else the scale is set from the maximal value)" )
192  ("labelIndex", po::value<unsigned int>(), "set the index of the label (by default set to 4) " )
193  ("SDPindex", po::value<std::vector <unsigned int> >()->multitoken(), "specify the sdp index (by default 0,1,2,3).");
194 
195 
196  bool parseOK=true;
197  bool cannotStart= false;
198  po::variables_map vm;
199 
200 
201  try{
202  po::store(po::parse_command_line(argc, argv, general_opt), vm);
203  }catch(const std::exception& ex){
204  parseOK=false;
205  trace.error()<< "Error checking program options: "<< ex.what()<< endl;
206  }
207  po::notify(vm);
208  if(parseOK && ! vm.count("input"))
209  {
210  trace.error() << " The input file name was not defined" << endl;
211  cannotStart = true;
212  }
213 
214 
215  if( !parseOK || cannotStart || vm.count("help")||argc<=1)
216  {
217  trace.info() << "Usage: " << argv[0] << " [input]\n"
218  << "It computes generic scalar surfel data comparisons (squared error) ( given from an input data file and from a reference one). \n \n"
219  << "Each surfels are associated to the nearest one of the reference surfels (computed by a 'brut force' search) "
220  << "This association can also be limited to surfel of same label (if available in the data and by using the --compAccordingLabels option )."
221  << "The comparison and surfel association can be displayed and result statistics are saved on output file (--fileMeasureOutput)."
222  << "You can also remove the interactive 3d view by just doing a snapshot and exit with option --doSnapShotAndExit. \n \n"
223  << "Example of use: \n \n"
224  << "3dCompSurfelData -i surfelCurvatureInput.dat -r surfelCurvatureRef.dat --fixMaxColorValue 0.8 -d visuSEcurvature.png -o statMeasures.dat \n \n "
225  << "=> From the two compared files you should obtain the result of the comparison (statMeasures.dat) with the associated visualisation (visuSEcurvature.png). \n \n \n "
226  << general_opt << "\n";
227  return 0;
228  }
229 
230  Z3i::KSpace K;
231  string inputFilename = vm["input"].as<std::string>();
232  string referenceFilename = vm["reference"].as<std::string>();
233 
234  std::vector<Point4D> surfelAndScalarInput;
235  std::vector<Point4D> surfelAndScalarReference;
236  std::vector<Point1D> vectLabelsInput;
237  std::vector<Point1D> vectLabelsReference;
238  bool useLabels = vm.count("compAccordingLabels");
239 
240  if(useLabels){
241  if(vm.count("labelIndex")){
242  std::vector<unsigned int > vectIndex;
243  vectIndex.push_back(vm["lSDPindex"].as<unsigned int >());
244  vectLabelsInput = PointListReader<Point1D>::getPointsFromFile(inputFilename, vectIndex);
245  vectLabelsReference = PointListReader<Point1D>::getPointsFromFile(referenceFilename, vectIndex);
246  }else{
247  vectLabelsInput = PointListReader<Point1D>::getPointsFromFile(inputFilename);
248  vectLabelsReference = PointListReader<Point1D>::getPointsFromFile(referenceFilename);
249  }
250  }
251 
252 
253 
254  if(vm.count("SDPindex")) {
255  std::vector<unsigned int > vectIndex = vm["SDPindex"].as<std::vector<unsigned int > >();
256  if(vectIndex.size()!=4){
257  trace.error() << "you need to specify the three indexes of vertex." << std::endl;
258  return 0;
259  }
260  surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFilename, vectIndex);
261  surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFilename, vectIndex);
262  }else{
263  surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFilename);
264  surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFilename);
265  }
266 
267 
268  Point4D ptLower = surfelAndScalarReference.at(0);
269  Point4D ptUpper = surfelAndScalarReference.at(0);
270  getBoundingUpperAndLowerPoint(surfelAndScalarReference, ptLower, ptUpper);
271  getBoundingUpperAndLowerPoint(surfelAndScalarInput, ptLower, ptUpper);
272 
273  K.init(Z3i::Point(2*ptLower[0]+1, 2*ptLower[1]+1, 2*ptLower[2]+1),
274  Z3i::Point(2*ptUpper[0]+1, 2*ptUpper[1]+1, 2*ptUpper[2]+1), true);
275 
276 
277  std::vector<Cell> vectSurfelsReference;
278  std::vector<Cell> vectSurfelsInput;
279 
280  // Construction of the set of surfels
281  for(unsigned int i =0; i<surfelAndScalarReference.size(); i++){
282  Point4D pt4d = surfelAndScalarReference.at(i);
283  Cell c = K.uCell(Z3i::Point(pt4d[0], pt4d[1], pt4d[2]));
284  vectSurfelsReference.push_back(c);
285  }
286  // Construction of the set of surfels
287  for(unsigned int i =0; i<surfelAndScalarInput.size(); i++){
288  Point4D pt4d = surfelAndScalarInput.at(i);
289  Cell c = K.uCell(Z3i::Point(pt4d[0], pt4d[1], pt4d[2]));
290  vectSurfelsInput.push_back(c);
291  }
292 
293 
294  // Brut force association of each surfel of the input to the reference with the minimal distance.
295  // For each surfel of the input we associate an index to the nearest surfel of the reference.
296  // if the option --compAccordingLabels is selected then we search only surfel of same label (more precise comparisons in some cases)
297 
298 
299  CanonicCellEmbedder<KSpace> embeder(K);
300  std::vector<unsigned int> vectIndexMinToReference;
301 
302  trace.info() << "Associating each input surfel to reference:" << std::endl;
303  trace.progressBar(0, surfelAndScalarInput.size());
304 
305  for(unsigned int i=0;i <vectSurfelsInput.size(); i++){
306  trace.progressBar(i, vectSurfelsInput.size());
307  Z3i::RealPoint ptCenterInput = embeder(vectSurfelsInput.at(i));
308  unsigned int indexDistanceMin = 0;
309  double distanceMin = std::numeric_limits<int>::max() ;
310  for(unsigned int j=0; j <vectSurfelsReference.size(); j++){
311  if(useLabels && vectLabelsReference.at(j) != vectLabelsInput.at(i)){
312  continue;
313  }
314  Z3i::RealPoint ptCenterRef = embeder(vectSurfelsReference.at(j));
315  double distance = (ptCenterRef - ptCenterInput).norm();
316  if(distance < distanceMin){
317  distanceMin = distance;
318  indexDistanceMin = j;
319  }
320  }
321  vectIndexMinToReference.push_back(indexDistanceMin);
322 
323  }
324  trace.progressBar(surfelAndScalarInput.size(), surfelAndScalarInput.size());
325  trace.info() << std::endl;
326 
327 
328 
329  //-------------------------
330  // Displaying input with error and computing statistics
331 
332 
333  QApplication application(argc,argv);
334  typedef ViewerSnap<> Viewer;
335 
336 
337  Viewer viewer(K, vm.count("doSnapShotAndExit"));
338  if(vm.count("doSnapShotAndExit")){
339  viewer.setSnapshotFileName(QString(vm["doSnapShotAndExit"].as<std::string>().c_str()));
340  }
341  viewer.setWindowTitle("3dCompSurfel Viewer");
342  viewer.show();
343 
344  Statistic<double> statErrors(true);
345  std::ofstream outputStatStream;
346  if(vm.count("fileMeasureOutput")){
347  outputStatStream.open(vm["fileMeasureOutput"].as<std::string>().c_str(), ios::app );
348  }
349 
350 
351 
352  double maxSqError=0;
353  for(unsigned int i=0;i <surfelAndScalarInput.size(); i++){
354  double scalarInput = surfelAndScalarInput.at(i)[3];
355  double scalarRef = surfelAndScalarReference.at(vectIndexMinToReference.at(i))[3];
356  double sqError = (scalarRef-scalarInput)*(scalarRef-scalarInput);
357  statErrors.addValue(sqError);
358  if(sqError> maxSqError){
359  maxSqError =sqError;
360  }
361  }
362  double maxVal = vm.count("fixMaxColorValue")? vm["fixMaxColorValue"].as<double>(): maxSqError;
363 
364  GradientColorMap<double> gradientColorMap( 0, maxVal );
365  gradientColorMap.addColor( Color(255,255,255,100 ));
366  gradientColorMap.addColor( Color(255,0,0,100 ) );
367  gradientColorMap.addColor( Color(0,0,255,100 ) );
368 
369 
370  //trace.info() << "Maximal error:" << maxSqError << std::endl;
371  // Hack waiting issue #899 if maxSqError =0, don't use gradientColorMap
372  //bool useGrad = maxSqError!=0.0;
373 
374  viewer << SetMode3D(vectSurfelsInput.at(0).className(), "Basic");
375  for(unsigned int i=0; i <surfelAndScalarInput.size(); i++){
376  double scalarInput = surfelAndScalarInput.at(i)[3];
377  double scalarRef = surfelAndScalarReference.at(vectIndexMinToReference.at(i))[3];
378  double sqError = (scalarRef-scalarInput)*(scalarRef-scalarInput);
379  viewer.setFillColor(gradientColorMap(sqError));
380 
381  viewer << vectSurfelsInput.at(i);
382  if(vm.count("drawSurfelAssociations")){
383  viewer.addLine(embeder(vectSurfelsInput.at(i)),embeder(vectSurfelsReference.at(vectIndexMinToReference.at(i))));
384  }
385  }
386 
387  statErrors.terminate();
388  if(vm.count("fileMeasureOutput")){
389  outputStatStream << "input= " << inputFilename << " reference=" << referenceFilename << " " ;
390  outputStatStream << statErrors << std::endl;
391  }else{
392  trace.info() << statErrors;
393  }
394  viewer << Viewer::updateDisplay;
395 
396  if(vm.count("doSnapShotAndExit")){
397  // Appy cleaning just save the last snap
398  viewer.restoreStateFromFile();
399  std::string name = vm["doSnapShotAndExit"].as<std::string>();
400  std::string extension = name.substr(name.find_last_of(".") + 1);
401  std::string basename = name.substr(0, name.find_last_of("."));
402  for(int i=0; i< viewer.snapshotCounter()-1; i++){
403  std::stringstream s;
404  s << basename << "-"<< setfill('0') << setw(4)<< i << "." << extension;
405  trace.info() << "erase temp file: " << s.str() << std::endl;
406  remove(s.str().c_str());
407  }
408  std::stringstream s;
409  s << basename << "-"<< setfill('0') << setw(4)<< viewer.snapshotCounter()-1 << "." << extension;
410  rename(s.str().c_str(), name.c_str());
411  return 0;
412  }
413 
414  if(vm.count("noWindows")){
415  return 0;
416  }else{
417  return application.exec();
418  }
419 }
void progressBar(const double currentValue, const double maximalValue)
virtual void show()
STL namespace.
Cell uCell(const PreCell &c) const
bool init(const Point &lower, const Point &upper, bool isClosed)
Trace trace(traceWriterTerm)
std::ostream & info()
typename Self::Point Point
std::ostream & error()
virtual void init()