DGtalTools  1.5.beta
3dCompSurfelData.cpp
1 
29 
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 "CLI11.hpp"
52 
53 
54 #include <limits>
55 
56 using namespace std;
57 using namespace DGtal;
58 using namespace Z3i;
59 
60 
61 
120 template < typename Space = DGtal::Z3i::Space, typename KSpace = DGtal::Z3i::KSpace>
121 struct ViewerSnap: DGtal::Viewer3D <Space, KSpace>
122 {
123 
124  ViewerSnap(const KSpace &KSEmb, bool saveSnap): Viewer3D<Space, KSpace>(KSEmb), mySaveSnap(saveSnap){
125  };
126 
127  virtual void
128  init(){
130  if(mySaveSnap){
131  QObject::connect(this, SIGNAL(drawFinished(bool)), this, SLOT(saveSnapshot(bool)));
132  }
133  };
134  bool mySaveSnap;
135 };
136 
137 
138 template < typename Point>
139 void
140 getBoundingUpperAndLowerPoint(const std::vector<Point> &vectorPt, Point &ptLower, Point &ptUpper){
141  for(unsigned int i =1; i<vectorPt.size(); i++){
142  if(vectorPt.at(i)[0] < ptLower[0]){
143  ptLower[0] = vectorPt.at(i)[0];
144  }
145  if(vectorPt.at(i)[1] < ptLower[1]){
146  ptLower[1] = vectorPt.at(i)[1];
147  }
148  if(vectorPt.at(i)[2] < ptLower[2]){
149  ptLower[2] =vectorPt.at(i)[2];
150  }
151  if(vectorPt.at(i)[0] < ptLower[0]){
152  ptLower[0] = vectorPt.at(i)[0];
153  }
154  if(vectorPt.at(i)[1] < ptLower[1]){
155  ptLower[1] = vectorPt.at(i)[1];
156  }
157  if(vectorPt.at(i)[2] < ptLower[2]){
158  ptLower[2] =vectorPt.at(i)[2];
159  }
160  }
161 }
162 
163 
164 int main( int argc, char** argv )
165 {
166  typedef PointVector<4, double> Point4D;
167  typedef PointVector<1, int> Point1D;
168 
169  // parse command line using CLI ----------------------------------------------
170  CLI::App app;
171  std::string inputFileName;
172  std::string referenceFileName;
173  std::string fileMeasureOutput;
174  std::string snapShotName;
175  bool useLabels {false};
176  bool drawSurfelAssociations {false};
177  bool noWindows {false};
178  double maxVal;
179  unsigned int labelIndex {4};
180  std::vector<unsigned int> vectSDPindex;
181 
182  app.description("Computes generic scalar surfel data comparisons (squared error) (given from an input data file and from a reference one).\n Each surfels are associated to the nearest one of the reference surfels (computed by a 'brut force' search). This association can also be limited to surfel of same label (if available in the data and by using the --compAccordingLabels option). The comparison and surfel association can be displayed and result statistics are saved on output file (--fileMeasureOutput). You can also remove the interactive 3d view by just doing a snapshot and exit with option --doSnapShotAndExit.\n \t Example of use: \n \t \t 3dCompSurfelData -i surfelCurvatureInput.dat -r surfelCurvatureRef.dat --fixMaxColorValue 0.8 -d visuSEcurvature.png -o statMeasures.dat \n \n \t \t => From the two compared files you should obtain the result of the comparison (statMeasures.dat) with the associated visualisation (visuSEcurvature.png).\n");
183 
184  app.add_option("-i,--input,1", inputFileName, "input file: sdpa (sequence of discrete points with attribute)" )
185  ->required()
186  ->check(CLI::ExistingFile);
187 
188  app.add_option("-r,--reference,2", referenceFileName, "input file: sdpa (sequence of discrete points with attribute)" )
189  ->required()
190  ->check(CLI::ExistingFile);
191  app.add_flag("-l,--compAccordingLabels", useLabels, "apply the comparisos only on points with same labels (by default fifth colomn)" );
192  app.add_flag("-a,--drawSurfelAssociations", drawSurfelAssociations, "Draw the surfel association.");
193  app.add_option("-o,--fileMeasureOutput",fileMeasureOutput, "specify the output file to store (append) the error stats else the result is given to std output. ");
194 
195  app.add_flag("-n,--noWindows", noWindows, "Don't display Viewer windows." );
196 
197  app.add_option("-d,--doSnapShotAndExit", snapShotName, "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).");
198  auto maxValSpe = app.add_option("--fixMaxColorValue", maxVal, "fix the maximal color value for the scale error display (else the scale is set from the maximal value)");
199  auto labOptio = app.add_option("--labelIndex", labelIndex,"set the index of the label (by default set to 4) " );
200  app.add_option("--SDPindex",vectSDPindex, "specify the sdp index (by default 0,1,2,3).")
201  ->expected(4);
202 
203  app.get_formatter()->column_width(40);
204  CLI11_PARSE(app, argc, argv);
205  // END parse command line using CLI ----------------------------------------------
206 
207 
208 
209 
210  Z3i::KSpace K;
211 
212 
213  std::vector<Point4D> surfelAndScalarInput;
214  std::vector<Point4D> surfelAndScalarReference;
215  std::vector<Point1D> vectLabelsInput;
216  std::vector<Point1D> vectLabelsReference;
217 
218  if(useLabels){
219  if(labOptio->count() > 0){
220  std::vector<unsigned int > vectIndex;
221  vectIndex.push_back(labelIndex);
222  vectLabelsInput = PointListReader<Point1D>::getPointsFromFile(inputFileName, vectIndex);
223  vectLabelsReference = PointListReader<Point1D>::getPointsFromFile(referenceFileName, vectIndex);
224  }else{
225  vectLabelsInput = PointListReader<Point1D>::getPointsFromFile(inputFileName);
226  vectLabelsReference = PointListReader<Point1D>::getPointsFromFile(referenceFileName);
227  }
228  }
229 
230 
231  if(vectSDPindex.size() == 4) {
232  surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFileName, vectSDPindex);
233  surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFileName, vectSDPindex);
234  }else{
235  surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFileName);
236  surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFileName);
237  }
238 
239 
240  Point4D ptLower = surfelAndScalarReference.at(0);
241  Point4D ptUpper = surfelAndScalarReference.at(0);
242  getBoundingUpperAndLowerPoint(surfelAndScalarReference, ptLower, ptUpper);
243  getBoundingUpperAndLowerPoint(surfelAndScalarInput, ptLower, ptUpper);
244 
245  K.init(Z3i::Point(2*ptLower[0]+1, 2*ptLower[1]+1, 2*ptLower[2]+1),
246  Z3i::Point(2*ptUpper[0]+1, 2*ptUpper[1]+1, 2*ptUpper[2]+1), true);
247 
248 
249  std::vector<Cell> vectSurfelsReference;
250  std::vector<Cell> vectSurfelsInput;
251 
252  // Construction of the set of surfels
253  for(unsigned int i =0; i<surfelAndScalarReference.size(); i++){
254  Point4D pt4d = surfelAndScalarReference.at(i);
255  Cell c = K.uCell(Z3i::Point(pt4d[0], pt4d[1], pt4d[2]));
256  vectSurfelsReference.push_back(c);
257  }
258  // Construction of the set of surfels
259  for(unsigned int i =0; i<surfelAndScalarInput.size(); i++){
260  Point4D pt4d = surfelAndScalarInput.at(i);
261  Cell c = K.uCell(Z3i::Point(pt4d[0], pt4d[1], pt4d[2]));
262  vectSurfelsInput.push_back(c);
263  }
264 
265 
266  // Brut force association of each surfel of the input to the reference with the minimal distance.
267  // For each surfel of the input we associate an index to the nearest surfel of the reference.
268  // if the option --compAccordingLabels is selected then we search only surfel of same label (more precise comparisons in some cases)
269 
270 
271  CanonicCellEmbedder<KSpace> embeder(K);
272  std::vector<unsigned int> vectIndexMinToReference;
273 
274  trace.info() << "Associating each input surfel to reference:" << std::endl;
275  trace.progressBar(0, surfelAndScalarInput.size());
276 
277  for(unsigned int i=0;i <vectSurfelsInput.size(); i++){
278  trace.progressBar(i, vectSurfelsInput.size());
279  Z3i::RealPoint ptCenterInput = embeder(vectSurfelsInput.at(i));
280  unsigned int indexDistanceMin = 0;
281  double distanceMin = std::numeric_limits<int>::max() ;
282  for(unsigned int j=0; j <vectSurfelsReference.size(); j++){
283  if(useLabels && vectLabelsReference.at(j) != vectLabelsInput.at(i)){
284  continue;
285  }
286  Z3i::RealPoint ptCenterRef = embeder(vectSurfelsReference.at(j));
287  double distance = (ptCenterRef - ptCenterInput).norm();
288  if(distance < distanceMin){
289  distanceMin = distance;
290  indexDistanceMin = j;
291  }
292  }
293  vectIndexMinToReference.push_back(indexDistanceMin);
294 
295  }
296  trace.progressBar(surfelAndScalarInput.size(), surfelAndScalarInput.size());
297  trace.info() << std::endl;
298 
299 
300 
301  //-------------------------
302  // Displaying input with error and computing statistics
303 
304 
305  QApplication application(argc,argv);
306  typedef ViewerSnap<> Viewer;
307 
308 
309  Viewer viewer(K, snapShotName!="");
310  if(snapShotName!=""){
311  viewer.setSnapshotFileName(snapShotName.c_str());
312  }
313  viewer.setWindowTitle("3dCompSurfel Viewer");
314  viewer.show();
315 
316  Statistic<double> statErrors(true);
317  std::ofstream outputStatStream;
318 
319  if(fileMeasureOutput != ""){
320  outputStatStream.open(fileMeasureOutput.c_str(), ios::app );
321  }
322 
323 
324 
325  double maxSqError=0;
326  for(unsigned int i=0;i <surfelAndScalarInput.size(); i++){
327  double scalarInput = surfelAndScalarInput.at(i)[3];
328  double scalarRef = surfelAndScalarReference.at(vectIndexMinToReference.at(i))[3];
329  double sqError = (scalarRef-scalarInput)*(scalarRef-scalarInput);
330  statErrors.addValue(sqError);
331  if(sqError> maxSqError){
332  maxSqError =sqError;
333  }
334  }
335  if (maxValSpe->count() == 0 )
336  {
337  maxVal = maxSqError;
338  }
339 
340 
341  GradientColorMap<double> gradientColorMap( 0, maxVal );
342  gradientColorMap.addColor( Color(255,255,255,100 ));
343  gradientColorMap.addColor( Color(255,0,0,100 ) );
344  gradientColorMap.addColor( Color(0,0,255,100 ) );
345 
346 
347  //trace.info() << "Maximal error:" << maxSqError << std::endl;
348  // Hack waiting issue #899 if maxSqError =0, don't use gradientColorMap
349  //bool useGrad = maxSqError!=0.0;
350 
351  viewer << SetMode3D(vectSurfelsInput.at(0).className(), "Basic");
352  for(unsigned int i=0; i <surfelAndScalarInput.size(); i++){
353  double scalarInput = surfelAndScalarInput.at(i)[3];
354  double scalarRef = surfelAndScalarReference.at(vectIndexMinToReference.at(i))[3];
355  double sqError = (scalarRef-scalarInput)*(scalarRef-scalarInput);
356  viewer.setFillColor(gradientColorMap(sqError));
357 
358  viewer << vectSurfelsInput.at(i);
359  if(drawSurfelAssociations){
360  viewer.addLine(embeder(vectSurfelsInput.at(i)),embeder(vectSurfelsReference.at(vectIndexMinToReference.at(i))));
361  }
362  }
363 
364  statErrors.terminate();
365  if(fileMeasureOutput != ""){
366  outputStatStream << "input= " << inputFileName << " reference=" << referenceFileName << " " ;
367  outputStatStream << statErrors << std::endl;
368  }else{
369  trace.info() << statErrors;
370  }
371  viewer << Viewer::updateDisplay;
372 
373  if(snapShotName != ""){
374  // Appy cleaning just save the last snap
375  viewer.restoreStateFromFile();
376  std::string extension = snapShotName.substr(snapShotName.find_last_of(".") + 1);
377  std::string basename = snapShotName.substr(0, snapShotName.find_last_of("."));
378  for(int i=0; i< viewer.snapshotCounter()-1; i++){
379  std::stringstream s;
380  s << basename << "-"<< setfill('0') << setw(4)<< i << "." << extension;
381  trace.info() << "erase temp file: " << s.str() << std::endl;
382  remove(s.str().c_str());
383  }
384  std::stringstream s;
385  s << basename << "-"<< setfill('0') << setw(4)<< viewer.snapshotCounter()-1 << "." << extension;
386  rename(s.str().c_str(), snapShotName.c_str());
387  return 0;
388  }
389 
390  if(noWindows){
391  return 0;
392  }else{
393  return application.exec();
394  }
395 }
int main(int argc, char **argv)
typename Self::Point Point
bool init(const Point &lower, const Point &upper, bool isClosed)
Cell uCell(const PreCell &c) const
std::ostream & info()
void progressBar(const double currentValue, const double maximalValue)
virtual void init()
Trace trace(traceWriterTerm)