34#include "DGtal/base/Common.h"
35#include "DGtal/helpers/StdDefs.h"
36#include "DGtal/io/viewers/PolyscopeViewer.h"
37#include "DGtal/io/readers/PointListReader.h"
38#include "DGtal/io/readers/MeshReader.h"
40#include "DGtal/topology/helpers/Surfaces.h"
41#include "DGtal/topology/SurfelAdjacency.h"
42#include "DGtal/topology/CanonicCellEmbedder.h"
43#include "DGtal/math/Statistic.h"
45#include "DGtal/io/Color.h"
46#include "DGtal/io/colormaps/GradientColorMap.h"
47#include "DGtal/io/readers/GenericReader.h"
116template <
typename Po
int>
118getBoundingUpperAndLowerPoint(
const std::vector<Point> &vectorPt, Point &ptLower, Point &ptUpper){
119 for(
unsigned int i =1; i<vectorPt.size(); i++){
120 if(vectorPt.at(i)[0] < ptLower[0]){
121 ptLower[0] = vectorPt.at(i)[0];
123 if(vectorPt.at(i)[1] < ptLower[1]){
124 ptLower[1] = vectorPt.at(i)[1];
126 if(vectorPt.at(i)[2] < ptLower[2]){
127 ptLower[2] =vectorPt.at(i)[2];
129 if(vectorPt.at(i)[0] < ptLower[0]){
130 ptLower[0] = vectorPt.at(i)[0];
132 if(vectorPt.at(i)[1] < ptLower[1]){
133 ptLower[1] = vectorPt.at(i)[1];
135 if(vectorPt.at(i)[2] < ptLower[2]){
136 ptLower[2] =vectorPt.at(i)[2];
142int main(
int argc,
char** argv )
144 typedef PointVector<4, double> Point4D;
145 typedef PointVector<1, int> Point1D;
149 std::string inputFileName;
150 std::string referenceFileName;
151 std::string fileMeasureOutput;
152 std::string snapShotName;
153 bool useLabels {
false};
154 bool drawSurfelAssociations {
false};
155 unsigned int labelIndex {4};
156 std::vector<unsigned int> vectSDPindex;
158 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 app.add_option(
"-i,--input,1", inputFileName,
"input file: sdpa (sequence of discrete points with attribute)" )
162 ->check(CLI::ExistingFile);
164 app.add_option(
"-r,--reference,2", referenceFileName,
"input file: sdpa (sequence of discrete points with attribute)" )
166 ->check(CLI::ExistingFile);
167 app.add_flag(
"-l,--compAccordingLabels", useLabels,
"apply the comparisos only on points with same labels (by default fifth colomn)" );
168 app.add_flag(
"-a,--drawSurfelAssociations", drawSurfelAssociations,
"Draw the surfel association.");
169 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 auto labOptio = app.add_option(
"--labelIndex", labelIndex,
"set the index of the label (by default set to 4) " );
172 app.add_option(
"--SDPindex",vectSDPindex,
"specify the sdp index (by default 0,1,2,3).")
175 app.get_formatter()->column_width(40);
176 CLI11_PARSE(app, argc, argv);
184 std::vector<Point4D> surfelAndScalarInput;
185 std::vector<Point4D> surfelAndScalarReference;
186 std::vector<Point1D> vectLabelsInput;
187 std::vector<Point1D> vectLabelsReference;
190 if(labOptio->count() > 0){
191 std::vector<unsigned int > vectIndex;
192 vectIndex.push_back(labelIndex);
193 vectLabelsInput = PointListReader<Point1D>::getPointsFromFile(inputFileName, vectIndex);
194 vectLabelsReference = PointListReader<Point1D>::getPointsFromFile(referenceFileName, vectIndex);
196 vectLabelsInput = PointListReader<Point1D>::getPointsFromFile(inputFileName);
197 vectLabelsReference = PointListReader<Point1D>::getPointsFromFile(referenceFileName);
202 if(vectSDPindex.size() == 4) {
203 surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFileName, vectSDPindex);
204 surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFileName, vectSDPindex);
206 surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFileName);
207 surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFileName);
211 Point4D ptLower = surfelAndScalarReference.at(0);
212 Point4D ptUpper = surfelAndScalarReference.at(0);
213 getBoundingUpperAndLowerPoint(surfelAndScalarReference, ptLower, ptUpper);
214 getBoundingUpperAndLowerPoint(surfelAndScalarInput, ptLower, ptUpper);
216 K.init(Z3i::Point(2*ptLower[0]+1, 2*ptLower[1]+1, 2*ptLower[2]+1),
217 Z3i::Point(2*ptUpper[0]+1, 2*ptUpper[1]+1, 2*ptUpper[2]+1),
true);
220 std::vector<Cell> vectSurfelsReference;
221 std::vector<Cell> vectSurfelsInput;
224 for(
unsigned int i =0; i<surfelAndScalarReference.size(); i++){
225 Point4D pt4d = surfelAndScalarReference.at(i);
226 Cell c = K.uCell(Z3i::Point(pt4d[0], pt4d[1], pt4d[2]));
227 vectSurfelsReference.push_back(c);
230 for(
unsigned int i =0; i<surfelAndScalarInput.size(); i++){
231 Point4D pt4d = surfelAndScalarInput.at(i);
232 Cell c = K.uCell(Z3i::Point(pt4d[0], pt4d[1], pt4d[2]));
233 vectSurfelsInput.push_back(c);
242 CanonicCellEmbedder<KSpace> embeder(K);
243 std::vector<unsigned int> vectIndexMinToReference;
245 trace.info() <<
"Associating each input surfel to reference:" << std::endl;
246 trace.progressBar(0, surfelAndScalarInput.size());
248 for(
unsigned int i=0;i <vectSurfelsInput.size(); i++){
249 trace.progressBar(i, vectSurfelsInput.size());
250 Z3i::RealPoint ptCenterInput = embeder(vectSurfelsInput.at(i));
251 unsigned int indexDistanceMin = 0;
252 double distanceMin = std::numeric_limits<int>::max() ;
253 for(
unsigned int j=0; j <vectSurfelsReference.size(); j++){
254 if(useLabels && vectLabelsReference.at(j) != vectLabelsInput.at(i)){
257 Z3i::RealPoint ptCenterRef = embeder(vectSurfelsReference.at(j));
258 double distance = (ptCenterRef - ptCenterInput).norm();
259 if(distance < distanceMin){
260 distanceMin = distance;
261 indexDistanceMin = j;
264 vectIndexMinToReference.push_back(indexDistanceMin);
267 trace.progressBar(surfelAndScalarInput.size(), surfelAndScalarInput.size());
268 trace.info() << std::endl;
276 typedef PolyscopeViewer<> Viewer;
278 viewer.allowReuseList =
true;
280 Statistic<double> statErrors(
true);
281 std::ofstream outputStatStream;
283 if(fileMeasureOutput !=
""){
284 outputStatStream.open(fileMeasureOutput.c_str(), ios::app );
288 for(
unsigned int i=0;i <surfelAndScalarInput.size(); i++){
289 double scalarInput = surfelAndScalarInput.at(i)[3];
290 double scalarRef = surfelAndScalarReference.at(vectIndexMinToReference.at(i))[3];
291 double sqError = (scalarRef-scalarInput)*(scalarRef-scalarInput);
292 statErrors.addValue(sqError);
293 if(sqError> maxSqError){
298 trace.info() <<
"Maximal error:" << maxSqError << std::endl;
299 for(
unsigned int i=0; i <surfelAndScalarInput.size(); i++){
300 double scalarInput = surfelAndScalarInput.at(i)[3];
301 double scalarRef = surfelAndScalarReference.at(vectIndexMinToReference.at(i))[3];
302 double sqError = (scalarRef-scalarInput)*(scalarRef-scalarInput);
304 viewer << WithQuantity(vectSurfelsInput.at(i),
"Squared Error", sqError);
307 if(drawSurfelAssociations){
310 for(
unsigned int i=0; i <surfelAndScalarInput.size(); i++){
311 viewer.drawLine(embeder(vectSurfelsInput.at(i)),embeder(vectSurfelsReference.at(vectIndexMinToReference.at(i))));
315 statErrors.terminate();
316 if(fileMeasureOutput !=
""){
317 outputStatStream <<
"input= " << inputFileName <<
" reference=" << referenceFileName <<
" " ;
318 outputStatStream << statErrors << std::endl;
320 trace.info() << statErrors;