31 #include <QGLViewer/qglviewer.h>
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"
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"
47 #include "DGtal/io/Color.h"
48 #include "DGtal/io/colormaps/GradientColorMap.h"
49 #include "DGtal/io/readers/GenericReader.h"
57 using namespace DGtal;
120 template <
typename Space = DGtal::Z3i::Space,
typename KSpace = DGtal::Z3i::KSpace>
121 struct ViewerSnap: DGtal::Viewer3D <Space, KSpace>
124 ViewerSnap(
const KSpace &KSEmb,
bool saveSnap): Viewer3D<Space, KSpace>(KSEmb), mySaveSnap(saveSnap){
129 DGtal::Viewer3D<>::init();
131 QObject::connect(
this, SIGNAL(drawFinished(
bool)),
this, SLOT(saveSnapshot(
bool)));
138 template <
typename Po
int>
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];
145 if(vectorPt.at(i)[1] < ptLower[1]){
146 ptLower[1] = vectorPt.at(i)[1];
148 if(vectorPt.at(i)[2] < ptLower[2]){
149 ptLower[2] =vectorPt.at(i)[2];
151 if(vectorPt.at(i)[0] < ptLower[0]){
152 ptLower[0] = vectorPt.at(i)[0];
154 if(vectorPt.at(i)[1] < ptLower[1]){
155 ptLower[1] = vectorPt.at(i)[1];
157 if(vectorPt.at(i)[2] < ptLower[2]){
158 ptLower[2] =vectorPt.at(i)[2];
164 int main(
int argc,
char** argv )
166 typedef PointVector<4, double> Point4D;
167 typedef PointVector<1, int> Point1D;
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};
179 unsigned int labelIndex {4};
180 std::vector<unsigned int> vectSDPindex;
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");
184 app.add_option(
"-i,--input,1", inputFileName,
"input file: sdpa (sequence of discrete points with attribute)" )
186 ->check(CLI::ExistingFile);
188 app.add_option(
"-r,--reference,2", referenceFileName,
"input file: sdpa (sequence of discrete points with attribute)" )
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. ");
195 app.add_flag(
"-n,--noWindows",
"Don't display Viewer windows." );
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).")
203 app.get_formatter()->column_width(40);
204 CLI11_PARSE(app, argc, argv);
213 std::vector<Point4D> surfelAndScalarInput;
214 std::vector<Point4D> surfelAndScalarReference;
215 std::vector<Point1D> vectLabelsInput;
216 std::vector<Point1D> vectLabelsReference;
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);
225 vectLabelsInput = PointListReader<Point1D>::getPointsFromFile(inputFileName);
226 vectLabelsReference = PointListReader<Point1D>::getPointsFromFile(referenceFileName);
231 if(vectSDPindex.size() == 4) {
232 surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFileName, vectSDPindex);
233 surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFileName, vectSDPindex);
235 surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFileName);
236 surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFileName);
240 Point4D ptLower = surfelAndScalarReference.at(0);
241 Point4D ptUpper = surfelAndScalarReference.at(0);
242 getBoundingUpperAndLowerPoint(surfelAndScalarReference, ptLower, ptUpper);
243 getBoundingUpperAndLowerPoint(surfelAndScalarInput, ptLower, ptUpper);
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);
249 std::vector<Cell> vectSurfelsReference;
250 std::vector<Cell> vectSurfelsInput;
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);
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);
271 CanonicCellEmbedder<KSpace> embeder(K);
272 std::vector<unsigned int> vectIndexMinToReference;
274 trace.info() <<
"Associating each input surfel to reference:" << std::endl;
275 trace.progressBar(0, surfelAndScalarInput.size());
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)){
286 Z3i::RealPoint ptCenterRef = embeder(vectSurfelsReference.at(j));
287 double distance = (ptCenterRef - ptCenterInput).norm();
288 if(distance < distanceMin){
289 distanceMin = distance;
290 indexDistanceMin = j;
293 vectIndexMinToReference.push_back(indexDistanceMin);
296 trace.progressBar(surfelAndScalarInput.size(), surfelAndScalarInput.size());
297 trace.info() << std::endl;
305 QApplication application(argc,argv);
306 typedef ViewerSnap<> Viewer;
309 Viewer viewer(K, snapShotName!=
"");
310 if(snapShotName!=
""){
311 viewer.setSnapshotFileName(snapShotName.c_str());
313 viewer.setWindowTitle(
"3dCompSurfel Viewer");
316 Statistic<double> statErrors(
true);
317 std::ofstream outputStatStream;
319 if(fileMeasureOutput !=
""){
320 outputStatStream.open(fileMeasureOutput.c_str(), ios::app );
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){
335 if (maxValSpe->count() == 0 )
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 ) );
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));
358 viewer << vectSurfelsInput.at(i);
359 if(drawSurfelAssociations){
360 viewer.addLine(embeder(vectSurfelsInput.at(i)),embeder(vectSurfelsReference.at(vectIndexMinToReference.at(i))));
364 statErrors.terminate();
365 if(fileMeasureOutput !=
""){
366 outputStatStream <<
"input= " << inputFileName <<
" reference=" << referenceFileName <<
" " ;
367 outputStatStream << statErrors << std::endl;
369 trace.info() << statErrors;
371 viewer << Viewer::updateDisplay;
373 if(snapShotName !=
""){
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++){
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());
385 s << basename <<
"-"<< setfill(
'0') << setw(4)<< viewer.snapshotCounter()-1 <<
"." << extension;
386 rename(s.str().c_str(), snapShotName.c_str());
393 return application.exec();