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"
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"
46#include "DGtal/io/Color.h"
47#include "DGtal/io/colormaps/GradientColorMap.h"
48#include "DGtal/io/readers/GenericReader.h"
117template <
typename Po
int>
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];
124 if(vectorPt.at(i)[1] < ptLower[1]){
125 ptLower[1] = vectorPt.at(i)[1];
127 if(vectorPt.at(i)[2] < ptLower[2]){
128 ptLower[2] =vectorPt.at(i)[2];
130 if(vectorPt.at(i)[0] > ptUpper[0]){
131 ptUpper[0] = vectorPt.at(i)[0];
133 if(vectorPt.at(i)[1] > ptUpper[1]){
134 ptUpper[1] = vectorPt.at(i)[1];
136 if(vectorPt.at(i)[2] > ptUpper[2]){
137 ptUpper[2] =vectorPt.at(i)[2];
143int main(
int argc,
char** argv )
145 typedef PointVector<4, double> Point4D;
146 typedef PointVector<1, int> Point1D;
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;
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");
161 app.add_option(
"-i,--input,1", inputFileName,
"input file: sdpa (sequence of discrete points with attribute)" )
163 ->check(CLI::ExistingFile);
165 app.add_option(
"-r,--reference,2", referenceFileName,
"input file: sdpa (sequence of discrete points with attribute)" )
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. ");
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).")
176 app.get_formatter()->column_width(40);
177 CLI11_PARSE(app, argc, argv);
185 std::vector<Point4D> surfelAndScalarInput;
186 std::vector<Point4D> surfelAndScalarReference;
187 std::vector<Point1D> vectLabelsInput;
188 std::vector<Point1D> vectLabelsReference;
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);
197 vectLabelsInput = PointListReader<Point1D>::getPointsFromFile(inputFileName);
198 vectLabelsReference = PointListReader<Point1D>::getPointsFromFile(referenceFileName);
203 if(vectSDPindex.size() == 4) {
204 surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFileName, vectSDPindex);
205 surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFileName, vectSDPindex);
207 surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFileName);
208 surfelAndScalarReference = PointListReader<Point4D>::getPointsFromFile(referenceFileName);
212 Point4D ptLower = surfelAndScalarReference.at(0);
213 Point4D ptUpper = surfelAndScalarReference.at(0);
214 getBoundingUpperAndLowerPoint(surfelAndScalarReference, ptLower, ptUpper);
215 getBoundingUpperAndLowerPoint(surfelAndScalarInput, ptLower, ptUpper);
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);
221 std::vector<Cell> vectSurfelsReference;
222 std::vector<Cell> vectSurfelsInput;
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);
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);
243 CanonicCellEmbedder<KSpace> embeder(K);
244 std::vector<unsigned int> vectIndexMinToReference;
246 trace.info() <<
"Associating each input surfel to reference:" << std::endl;
247 trace.progressBar(0, surfelAndScalarInput.size());
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)){
258 Z3i::RealPoint ptCenterRef = embeder(vectSurfelsReference.at(j));
259 double distance = (ptCenterRef - ptCenterInput).norm();
260 if(distance < distanceMin){
261 distanceMin = distance;
262 indexDistanceMin = j;
265 vectIndexMinToReference.push_back(indexDistanceMin);
268 trace.progressBar(surfelAndScalarInput.size(), surfelAndScalarInput.size());
269 trace.info() << std::endl;
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);
283 typedef PolyscopeViewer<> Viewer;
285 viewer.allowReuseList =
true;
287 Statistic<double> statErrors(
true);
288 std::ofstream outputStatStream;
290 if(fileMeasureOutput !=
""){
291 outputStatStream.open(fileMeasureOutput.c_str(), ios::app );
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){
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);
311 viewer << WithQuantity(vectSurfelsInput.at(i),
"Squared Error", sqError);
314 if(drawSurfelAssociations){
317 for(
unsigned int i=0; i <surfelAndScalarInput.size(); i++){
318 viewer.drawLine(embeder(vectSurfelsInput.at(i)),embeder(vectSurfelsReference.at(vectIndexMinToReference.at(i))));
322 statErrors.terminate();
323 if(fileMeasureOutput !=
""){
324 outputStatStream <<
"input= " << inputFileName <<
" reference=" << referenceFileName <<
" " ;
325 outputStatStream << statErrors << std::endl;
327 trace.info() << statErrors;