DGtalTools 2.1.0
Loading...
Searching...
No Matches
3dCompSurfelData.cpp
1
30
31#include <iostream>
32#include <sstream>
33#include <stdio.h>
34
35#include "DGtal/base/Common.h"
36#include "DGtal/helpers/StdDefs.h"
37#include "DGtal/io/viewers/PolyscopeViewer.h"
38#include "DGtal/io/readers/PointListReader.h"
39#include "DGtal/io/readers/MeshReader.h"
40
41#include "DGtal/topology/helpers/Surfaces.h"
42#include "DGtal/topology/SurfelAdjacency.h"
43#include "DGtal/topology/CanonicCellEmbedder.h"
44#include "DGtal/math/Statistic.h"
45
46#include "DGtal/io/Color.h"
47#include "DGtal/io/colormaps/GradientColorMap.h"
48#include "DGtal/io/readers/GenericReader.h"
49
50#include "CLI11.hpp"
51
52
53#include <limits>
54
55using namespace std;
56using namespace DGtal;
57using namespace Z3i;
58
59
60
117template < typename Point>
118void
119getBoundingUpperAndLowerPoint(const std::vector<Point> &vectorPt, Point &ptLower, Point &ptUpper){
120 for(unsigned int i =1; i<vectorPt.size(); i++){
121 if(vectorPt.at(i)[0] < ptLower[0]){
122 ptLower[0] = vectorPt.at(i)[0];
123 }
124 if(vectorPt.at(i)[1] < ptLower[1]){
125 ptLower[1] = vectorPt.at(i)[1];
126 }
127 if(vectorPt.at(i)[2] < ptLower[2]){
128 ptLower[2] =vectorPt.at(i)[2];
129 }
130 if(vectorPt.at(i)[0] > ptUpper[0]){
131 ptUpper[0] = vectorPt.at(i)[0];
132 }
133 if(vectorPt.at(i)[1] > ptUpper[1]){
134 ptUpper[1] = vectorPt.at(i)[1];
135 }
136 if(vectorPt.at(i)[2] > ptUpper[2]){
137 ptUpper[2] =vectorPt.at(i)[2];
138 }
139 }
140}
141
142
143int main( int argc, char** argv )
144{
145 typedef PointVector<4, double> Point4D;
146 typedef PointVector<1, int> Point1D;
147
148 // parse command line using CLI ----------------------------------------------
149 CLI::App app;
150 std::string inputFileName;
151 std::string referenceFileName;
152 std::string fileMeasureOutput;
153 std::string snapShotName;
154 bool useLabels {false};
155 bool drawSurfelAssociations {false};
156 unsigned int labelIndex {4};
157 std::vector<unsigned int> vectSDPindex;
158
159 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");
160
161 app.add_option("-i,--input,1", inputFileName, "input file: sdpa (sequence of discrete points with attribute)" )
162 ->required()
163 ->check(CLI::ExistingFile);
164
165 app.add_option("-r,--reference,2", referenceFileName, "input file: sdpa (sequence of discrete points with attribute)" )
166 ->required()
167 ->check(CLI::ExistingFile);
168 app.add_flag("-l,--compAccordingLabels", useLabels, "apply the comparisos only on points with same labels (by default fifth colomn)" );
169 app.add_flag("-a,--drawSurfelAssociations", drawSurfelAssociations, "Draw the surfel association.");
170 app.add_option("-o,--fileMeasureOutput",fileMeasureOutput, "specify the output file to store (append) the error stats else the result is given to std output. ");
171
172 auto labOptio = app.add_option("--labelIndex", labelIndex,"set the index of the label (by default set to 4) " );
173 app.add_option("--SDPindex",vectSDPindex, "specify the sdp index (by default 0,1,2,3).")
174 ->expected(4);
175
176 app.get_formatter()->column_width(40);
177 CLI11_PARSE(app, argc, argv);
178 // END parse command line using CLI ----------------------------------------------
179
180
181
182
183 Z3i::KSpace K;
184
185 std::vector<Point4D> surfelAndScalarInput;
186 std::vector<Point4D> surfelAndScalarReference;
187 std::vector<Point1D> vectLabelsInput;
188 std::vector<Point1D> vectLabelsReference;
189
190 if(useLabels){
191 if(labOptio->count() > 0){
192 std::vector<unsigned int > vectIndex;
193 vectIndex.push_back(labelIndex);
194 vectLabelsInput = PointListReader<Point1D>::getPointsFromFile(inputFileName, vectIndex);
195 vectLabelsReference = PointListReader<Point1D>::getPointsFromFile(referenceFileName, vectIndex);
196 }else{
197 vectLabelsInput = PointListReader<Point1D>::getPointsFromFile(inputFileName);
198 vectLabelsReference = PointListReader<Point1D>::getPointsFromFile(referenceFileName);
199 }
200 }
201
202
203 if(vectSDPindex.size() == 4) {
204 surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFileName, vectSDPindex);
205 surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFileName, vectSDPindex);
206 }else{
207 surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFileName);
208 surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFileName);
209 }
210
211
212 Point4D ptLower = surfelAndScalarReference.at(0);
213 Point4D ptUpper = surfelAndScalarReference.at(0);
214 getBoundingUpperAndLowerPoint(surfelAndScalarReference, ptLower, ptUpper);
215 getBoundingUpperAndLowerPoint(surfelAndScalarInput, ptLower, ptUpper);
216
217 K.init(Z3i::Point(2*(ptLower[0]-1)+1, 2*(ptLower[1]-1)+1, 2*(ptLower[2]-1)+1),
218 Z3i::Point(2*(ptUpper[0]+1)+1, 2*(ptUpper[1]+1)+1, 2*(ptUpper[2]+1)+1), true);
219
220
221 std::vector<Cell> vectSurfelsReference;
222 std::vector<Cell> vectSurfelsInput;
223
224 // Construction of the set of surfels
225 for(unsigned int i =0; i<surfelAndScalarReference.size(); i++){
226 Point4D pt4d = surfelAndScalarReference.at(i);
227 Cell c = K.uCell(Z3i::Point(pt4d[0], pt4d[1], pt4d[2]));
228 vectSurfelsReference.push_back(c);
229 }
230 // Construction of the set of surfels
231 for(unsigned int i =0; i<surfelAndScalarInput.size(); i++){
232 Point4D pt4d = surfelAndScalarInput.at(i);
233 Cell c = K.uCell(Z3i::Point(pt4d[0], pt4d[1], pt4d[2]));
234 vectSurfelsInput.push_back(c);
235 }
236
237
238 // Brut force association of each surfel of the input to the reference with the minimal distance.
239 // For each surfel of the input we associate an index to the nearest surfel of the reference.
240 // if the option --compAccordingLabels is selected then we search only surfel of same label (more precise comparisons in some cases)
241
242
243 CanonicCellEmbedder<KSpace> embeder(K);
244 std::vector<unsigned int> vectIndexMinToReference;
245
246 trace.info() << "Associating each input surfel to reference:" << std::endl;
247 trace.progressBar(0, surfelAndScalarInput.size());
248
249 for(unsigned int i=0;i <vectSurfelsInput.size(); i++){
250 trace.progressBar(i, vectSurfelsInput.size());
251 Z3i::RealPoint ptCenterInput = embeder(vectSurfelsInput.at(i));
252 unsigned int indexDistanceMin = 0;
253 double distanceMin = std::numeric_limits<int>::max() ;
254 for(unsigned int j=0; j <vectSurfelsReference.size(); j++){
255 if(useLabels && vectLabelsReference.at(j) != vectLabelsInput.at(i)){
256 continue;
257 }
258 Z3i::RealPoint ptCenterRef = embeder(vectSurfelsReference.at(j));
259 double distance = (ptCenterRef - ptCenterInput).norm();
260 if(distance < distanceMin){
261 distanceMin = distance;
262 indexDistanceMin = j;
263 }
264 }
265 vectIndexMinToReference.push_back(indexDistanceMin);
266
267 }
268 trace.progressBar(surfelAndScalarInput.size(), surfelAndScalarInput.size());
269 trace.info() << std::endl;
270
271
272
273 //-------------------------
274 // Displaying input with error and computing statistics
275 stringstream s;
276 s << "3dCompSurfelData - DGtalTools: ";
277 string name = inputFileName.substr(inputFileName.find_last_of("/")+1,inputFileName.size()) ;
278 s << " " << name << " (W key to display settings)";
279 polyscope::options::programName = s.str();
280 polyscope::view::setNavigateStyle(polyscope::NavigateStyle::Free);
281
282
283 typedef PolyscopeViewer<> Viewer;
284 Viewer viewer(K);
285 viewer.allowReuseList = true;
286
287 Statistic<double> statErrors(true);
288 std::ofstream outputStatStream;
289
290 if(fileMeasureOutput != ""){
291 outputStatStream.open(fileMeasureOutput.c_str(), ios::app );
292 }
293
294 double maxSqError=0;
295 for(unsigned int i=0;i <surfelAndScalarInput.size(); i++){
296 double scalarInput = surfelAndScalarInput.at(i)[3];
297 double scalarRef = surfelAndScalarReference.at(vectIndexMinToReference.at(i))[3];
298 double sqError = (scalarRef-scalarInput)*(scalarRef-scalarInput);
299 statErrors.addValue(sqError);
300 if(sqError> maxSqError){
301 maxSqError =sqError;
302 }
303 }
304
305 trace.info() << "Maximal error:" << maxSqError << std::endl;
306 for(unsigned int i=0; i <surfelAndScalarInput.size(); i++){
307 double scalarInput = surfelAndScalarInput.at(i)[3];
308 double scalarRef = surfelAndScalarReference.at(vectIndexMinToReference.at(i))[3];
309 double sqError = (scalarRef-scalarInput)*(scalarRef-scalarInput);
310
311 viewer << WithQuantity(vectSurfelsInput.at(i), "Squared Error", sqError);
312 }
313
314 if(drawSurfelAssociations){
315 // Second loop to draw associations
316 // Allow for easier groupping with viewer
317 for(unsigned int i=0; i <surfelAndScalarInput.size(); i++){
318 viewer.drawLine(embeder(vectSurfelsInput.at(i)),embeder(vectSurfelsReference.at(vectIndexMinToReference.at(i))));
319 }
320 }
321
322 statErrors.terminate();
323 if(fileMeasureOutput != ""){
324 outputStatStream << "input= " << inputFileName << " reference=" << referenceFileName << " " ;
325 outputStatStream << statErrors << std::endl;
326 }else{
327 trace.info() << statErrors;
328 }
329
330 viewer.show();
331 return 0;
332}
Definition ATu0v1.h:57