50#include "DGtal/base/Common.h"
51#include "DGtal/base/Exceptions.h"
52#include "DGtal/kernel/SpaceND.h"
53#include "DGtal/kernel/domains/HyperRectDomain.h"
54#include "DGtal/kernel/BasicPointPredicates.h"
55#include "DGtal/math/linalg/EigenDecomposition.h"
56#include "DGtal/topology/KhalimskySpaceND.h"
57#include "DGtal/geometry/curves/GridCurve.h"
58#include "DGtal/geometry/curves/Naive3DDSSComputer.h"
59#include "DGtal/geometry/curves/StandardDSS6Computer.h"
60#include "DGtal/geometry/curves/SaturatedSegmentation.h"
61#include "DGtal/geometry/volumes/distance/ExactPredicateLpSeparableMetric.h"
62#include "DGtal/geometry/volumes/estimation/VoronoiCovarianceMeasure.h"
63#include "DGtal/geometry/curves/estimation/LambdaMST3D.h"
64#include "DGtal/geometry/curves/estimation/FunctorsLambdaMST.h"
65#include "DGtal/io/viewers/PolyscopeViewer.h"
66#include "DGtal/io/readers/PointListReader.h"
67#include "DGtal/io/colormaps/HueShadeColorMap.h"
139const Color AXIS_COLOR( 0, 0, 0, 255 );
140const Color XY_COLOR( 0, 0, 255, 50 );
141const Color XZ_COLOR( 0, 255, 0, 50 );
142const Color YZ_COLOR( 255, 0, 0, 50 );
143const Color CURVE3D_COLOR( 100, 100, 140, 128 );
144const Color CURVE2D_COLOR( 200, 200, 200, 100 );
145const double MS3D_LINESIZE = 0.05;
150template <
typename Po
int,
typename RealPo
int,
typename space,
typename kspace >
151void displayAxes( PolyscopeViewer<space, kspace> & viewer,
152 const Point & lowerBound,
const Point & upperBound,
153 const std::string & mode )
155 RealPoint p0( (
double)lowerBound[ 0 ]-0.5,
156 (
double)lowerBound[ 1 ]-0.5,
157 (
double)lowerBound[ 2 ]-0.5 );
158 RealPoint p1( (
double)upperBound[ 0 ]-0.5,
159 (
double)upperBound[ 1 ]-0.5,
160 (
double)upperBound[ 2 ]-0.5 );
161 if ( ( mode ==
"WIRED" ) || ( mode ==
"COLORED" ) )
163 viewer.drawColor(AXIS_COLOR);
164 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p0[ 2 ]),
165 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]) );
166 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p0[ 2 ]),
167 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]) );
168 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p0[ 2 ]),
169 DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]) );
170 viewer.drawLine( DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]),
171 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]) );
172 viewer.drawLine( DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]),
173 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]) );
174 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]),
175 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]) );
176 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]),
177 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]) );
178 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]),
179 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]) );
180 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]),
181 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]) );
182 viewer.drawLine( DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]),
183 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]) );
184 viewer.drawLine( DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]),
185 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]) );
186 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]),
187 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]) );
189 if ( mode ==
"COLORED" )
191 viewer.drawColor(XY_COLOR);
192 viewer.drawQuad(DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]),
193 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]),
194 DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]),
195 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]) );
196 viewer.drawColor(XZ_COLOR);
197 viewer.drawQuad(DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]),
198 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]),
199 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]),
200 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]));
201 viewer.drawColor(YZ_COLOR);
202 viewer.drawQuad(DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]),
203 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]),
204 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]),
205 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]));
209template <
typename KSpace,
typename Naive3DDSSComputer,
typename space,
typename kspace >
210void displayDSS3d( PolyscopeViewer<space, kspace> & viewer,
211 const KSpace & ks,
const Naive3DDSSComputer & dss3d,
212 const DGtal::Color & color3d )
214 viewer << color3d << dss3d;
217template <
typename Po
int1,
typename Po
int2>
218void assign( Point1 & p1,
const Point2 & p2 )
225template <
typename KSpace,
typename Naive3DDSSComputer,
typename space,
typename kspace >
226void displayDSS3dTangent( PolyscopeViewer<space, kspace> & viewer,
227 const KSpace & ks,
const Naive3DDSSComputer & dss3d,
228 const DGtal::Color & color3d )
230 typedef typename Naive3DDSSComputer::Point3d Point;
231 typedef typename Naive3DDSSComputer::Integer Integer;
232 typedef typename Naive3DDSSComputer::PointR3d PointR3d;
234 PointR3d interceptR, thicknessR;
235 Z3i::RealPoint P1, P2, direction, intercept, thickness;
236 dss3d.getParameters( directionZ3, interceptR, thicknessR );
238 intercept[0] = (double) NumberTraits<Integer>::castToDouble ( interceptR[0].first ) / (double) NumberTraits<Integer>::castToDouble ( interceptR[0].second );
239 intercept[1] = (double) NumberTraits<Integer>::castToDouble ( interceptR[1].first ) / (double) NumberTraits<Integer>::castToDouble ( interceptR[1].second );
240 intercept[2] = (double) NumberTraits<Integer>::castToDouble ( interceptR[2].first ) / (double) NumberTraits<Integer>::castToDouble ( interceptR[2].second );
241 thickness[0] = (double) NumberTraits<Integer>::castToDouble ( thicknessR[0].first ) / (double) NumberTraits<Integer>::castToDouble ( thicknessR[0].second );
242 thickness[1] = (double) NumberTraits<Integer>::castToDouble ( thicknessR[1].first ) / (double) NumberTraits<Integer>::castToDouble ( thicknessR[1].second );
243 thickness[2] = (double) NumberTraits<Integer>::castToDouble ( thicknessR[2].first ) / (double) NumberTraits<Integer>::castToDouble ( thicknessR[2].second );
245 assign( direction, directionZ3 );
246 direction /= direction.norm();
247 assign( P1, *dss3d.begin() );
248 assign( P2, *(dss3d.end()-1) );
249 double t1 = (P1 - intercept).dot( direction );
250 double t2 = (P2 - intercept).dot( direction );
252 Z3i::RealPoint Q1 = intercept + t1 * direction;
253 Z3i::RealPoint Q2 = intercept + t2 * direction;
254 viewer.drawColor(color3d);
255 viewer.drawLine( Z3i::RealPoint(Q1[ 0 ]-0.5, Q1[ 1 ]-0.5, Q1[ 2 ]-0.5),
256 Z3i::RealPoint(Q2[ 0 ]-0.5, Q2[ 1 ]-0.5, Q2[ 2 ]-0.5));
259template <
typename KSpace,
typename StandardDSS6Computer,
typename space,
typename kspace >
260void displayProj2d6( PolyscopeViewer<space, kspace> & viewer,
261 const KSpace & ks,
const StandardDSS6Computer & dss3d,
262 const DGtal::Color & color2d )
264 typedef typename StandardDSS6Computer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
265 typedef typename ArithmeticalDSSComputer2d::ConstIterator ConstIterator2d;
266 typedef typename ArithmeticalDSSComputer2d::Point Point2d;
267 typedef typename KSpace::Cell Cell;
268 typedef typename KSpace::Point Point3d;
269 Point3d b = ks.lowerBound();
270 for ( DGtal::Dimension i = 0; i < 3; ++i )
272 const ArithmeticalDSSComputer2d & dss2d = dss3d.arithmeticalDSS2d( i );
273 for ( ConstIterator2d itP = dss2d.begin(), itPEnd = dss2d.end(); itP != itPEnd; ++itP )
279 case 0: q = Point3d( 2*b[ i ] , 2*p[ 0 ]+1, 2*p[ 1 ]+1 );
break;
280 case 1: q = Point3d( 2*p[ 0 ]+1, 2*b[ i ] , 2*p[ 1 ]+1 );
break;
281 case 2: q = Point3d( 2*p[ 0 ]+1, 2*p[ 1 ]+1, 2*b[ i ] );
break;
283 Cell c = ks.uCell( q );
284 viewer << color2d << c;
289template <
typename KSpace,
typename StandardDSS6Computer,
typename space,
typename kspace >
290void displayDSS2d6( PolyscopeViewer<space, kspace> & viewer,
291 const KSpace & ks,
const StandardDSS6Computer & dss3d,
292 const DGtal::Color & color2d )
294 typedef typename StandardDSS6Computer::ConstIterator ConstIterator3d;
295 typedef typename StandardDSS6Computer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
296 typedef typename ArithmeticalDSSComputer2d::ConstIterator ConstIterator2d;
297 typedef typename ArithmeticalDSSComputer2d::Point Point2d;
298 typedef typename KSpace::Cell Cell;
299 typedef typename KSpace::Point Point3d;
300 typedef DGtal::PointVector<2,double> PointD2d;
301 typedef typename DGtal::PointVector<3,double> PointD3D;
302 Point3d b = ks.lowerBound();
303 for ( DGtal::Dimension i = 0; i < 3; ++i )
305 const typename ArithmeticalDSSComputer2d::Primitive & dss2d
306 = dss3d.arithmeticalDSS2d( i ).primitive();
308 std::vector<PointD2d> pts2d;
309 pts2d.push_back( dss2d.project(dss2d.back(), dss2d.Uf()) );
310 pts2d.push_back( dss2d.project(dss2d.back(), dss2d.Lf()) );
311 pts2d.push_back( dss2d.project(dss2d.front(), dss2d.Lf()) );
312 pts2d.push_back( dss2d.project(dss2d.front(), dss2d.Uf()) );
313 std::vector<PointD3D> bb;
315 for (
unsigned int j = 0; j < pts2d.size(); ++j )
319 case 0: p3[0] = (double) b[ i ]-0.5; p3[1] = pts2d[ j ][ 0 ]; p3[2] = pts2d[ j ][ 1 ];
break;
320 case 1: p3[0] = pts2d[ j ][ 0 ]; p3[1] = (double) b[ i ]-0.5; p3[2] = pts2d[ j ][ 1 ];
break;
321 case 2: p3[0] = pts2d[ j ][ 0 ]; p3[1] = pts2d[ j ][ 1 ]; p3[2] = (double) b[ i ]-0.5;
break;
325 for (
unsigned int j = 0; j < pts2d.size(); ++j ){
326 viewer.drawColor(color2d);
327 viewer.drawLine( DGtal::Z3i::RealPoint(bb[ j ][0], bb[ j ][1], bb[ j ][2]),
328 DGtal::Z3i::RealPoint(bb[ (j+1)%4 ][0], bb[ (j+1)%4 ][1], bb[ (j+1)%4 ][2]));
335template <
typename KSpace,
typename Naive3DDSSComputer,
typename space,
typename kspace >
336void displayProj2d26( PolyscopeViewer<space, kspace> & viewer,
337 const KSpace & ks,
const Naive3DDSSComputer & dss3d,
338 const DGtal::Color & color2d )
340 typedef typename Naive3DDSSComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
341 typedef typename ArithmeticalDSSComputer2d::ConstIterator ConstIterator2d;
342 typedef typename ArithmeticalDSSComputer2d::Point Point2d;
343 typedef typename KSpace::Cell Cell;
344 typedef typename KSpace::Point Point3d;
345 Point3d b = ks.lowerBound();
347 const ArithmeticalDSSComputer2d & dssXY = dss3d.arithmeticalDSS2dXY();
348 const ArithmeticalDSSComputer2d & dssXZ = dss3d.arithmeticalDSS2dXZ();
349 const ArithmeticalDSSComputer2d & dssYZ = dss3d.arithmeticalDSS2dYZ();
351 bool validXY = dss3d.validArithmeticalDSS2d ( 2 );
352 bool validXZ = dss3d.validArithmeticalDSS2d ( 1 );
353 bool validYZ = dss3d.validArithmeticalDSS2d ( 0 );
355 if ( validXY && validXZ )
357 for ( ConstIterator2d itXY = dssXY.begin(), itXZ = dssXZ.begin(), itPEnd = dssXY.end(); itXY != itPEnd; ++itXY, ++itXZ )
359 Point2d p1 = *itXY, p2 = *itXZ;
361 q1 = Point3d ( 2*b[ 0 ], 2*p1[ 1 ]+1, 2*p2[ 1 ]+1 );
362 q2 = Point3d ( 2*p2[ 0 ]+1, 2*b[ 1 ], 2*p2[ 1 ]+1 );
363 q3 = Point3d ( 2*p1[ 0 ]+1, 2*p1[ 1 ]+1, 2*b[ 2 ] );
364 Cell c1 = ks.uCell( q1 ); Cell c2 = ks.uCell( q2 ); Cell c3 = ks.uCell( q3 );
365 viewer << color2d << c1;
366 viewer << color2d << c2;
367 viewer << color2d << c3;
372 if ( validYZ && validXY )
374 for ( ConstIterator2d itYZ = dssYZ.begin(), itXY = dssXY.begin(), itPEnd = dssXY.end(); itXY != itPEnd; ++itXY, ++itYZ )
376 Point2d p1 = *itYZ, p2 = *itXY;
378 q1 = Point3d ( 2*b[ 0 ], 2*p1[ 0 ]+1, 2*p1[ 1 ]+1 );
379 q2 = Point3d ( 2*p2[ 0 ]+1, 2*b[ 1 ], 2*p1[ 1 ]+1 );
380 q3 = Point3d ( 2*p2[ 0 ]+1, 2*p2[ 1 ]+1, 2*b[ 2 ] );
381 Cell c1 = ks.uCell( q1 ); Cell c2 = ks.uCell( q2 ); Cell c3 = ks.uCell( q3 );
382 viewer << color2d << c1;
383 viewer << color2d << c2;
384 viewer << color2d << c3;
389 for ( ConstIterator2d itYZ = dssYZ.begin(), itXZ = dssXZ.begin(), itPEnd = dssXZ.end(); itXZ != itPEnd; ++itXZ, ++itYZ )
391 Point2d p1 = *itYZ, p2 = *itXZ;
393 q1 = Point3d ( 2*b[ 0 ], 2*p1[ 0 ]+1, 2*p1[ 1 ]+1 );
394 q2 = Point3d ( 2*p2[ 0 ]+1, 2*b[ 1 ], 2*p2[ 1 ]+1 );
395 q3 = Point3d ( 2*p2[ 0 ]+1, 2*p1[ 0 ]+1, 2*b[ 2 ] );
396 Cell c1 = ks.uCell( q1 ); Cell c2 = ks.uCell( q2 );Cell c3 = ks.uCell( q3 );
397 viewer << color2d << c1;
398 viewer << color2d << c2;
399 viewer << color2d << c3;
406template <
typename KSpace,
typename Naive3DDSSComputer,
typename space,
typename kspace >
407void displayDSS2d26( PolyscopeViewer<space, kspace> & viewer,
408 const KSpace & ks,
const Naive3DDSSComputer & dss3d,
409 const DGtal::Color & color2d )
411 typedef typename Naive3DDSSComputer::ConstIterator ConstIterator3d;
412 typedef typename Naive3DDSSComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
413 typedef typename ArithmeticalDSSComputer2d::ConstIterator ConstIterator2d;
414 typedef typename ArithmeticalDSSComputer2d::Point Point2d;
415 typedef typename KSpace::Cell Cell;
416 typedef typename KSpace::Point Point3d;
417 typedef DGtal::PointVector<2,double> PointD2d;
418 typedef DGtal::PointVector<2,double> PointD3D;
419 Point3d b = ks.lowerBound();
420 for ( DGtal::Dimension i = 0; i < 3; ++i )
422 if ( !dss3d.validArithmeticalDSS2d ( i ) )
425 const typename ArithmeticalDSSComputer2d::Primitive & dss2d
426 = dss3d.arithmeticalDSS2d( i ).primitive();
428 std::vector<PointD2d> pts2d;
429 pts2d.push_back( dss2d.project(dss2d.back(), dss2d.Uf()) );
430 pts2d.push_back( dss2d.project(dss2d.back(), dss2d.Lf()) );
431 pts2d.push_back( dss2d.project(dss2d.front(), dss2d.Lf()) );
432 pts2d.push_back( dss2d.project(dss2d.front(), dss2d.Uf()) );
433 std::vector<PointD3D> bb;
435 for (
unsigned int j = 0; j < pts2d.size(); ++j )
439 case 0: p3[0] = (double) b[ i ]-0.5; p3[1] = pts2d[ j ][ 0 ]; p3[2] = pts2d[ j ][ 1 ];
break;
440 case 1: p3[0] = pts2d[ j ][ 0 ]; p3[1] = (double) b[ i ]-0.5; p3[2] = pts2d[ j ][ 1 ];
break;
441 case 2: p3[0] = pts2d[ j ][ 0 ]; p3[1] = pts2d[ j ][ 1 ]; p3[2] = (double) b[ i ]-0.5;
break;
445 for (
unsigned int j = 0; j < pts2d.size(); ++j ){
446 viewer.drawColor(color2d);
447 viewer.drawLine( DGtal::Z3i::RealPoint(bb[ j ][0], bb[ j ][1], bb[ j ][2]),
448 DGtal::Z3i::RealPoint(bb[ (j+1)%4 ][0], bb[ (j+1)%4 ][1], bb[ (j+1)%4 ][2])
457template <
typename KSpace,
typename Po
intIterator,
typename space,
typename kspace >
458bool displayCover6( PolyscopeViewer<space, kspace> & viewer,
459 const KSpace & ks, PointIterator b, PointIterator e,
460 bool dss3d,
bool proj2d,
bool dss2d,
bool tangent,
463 typedef typename PointIterator::value_type Point;
464 typedef StandardDSS6Computer<PointIterator,int,4> SegmentComputer;
465 typedef SaturatedSegmentation<SegmentComputer> Decomposition;
466 typedef typename Decomposition::SegmentComputerIterator SegmentComputerIterator;
467 typedef typename SegmentComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
468 SegmentComputer algo;
469 Decomposition theDecomposition(b, e, algo);
471 HueShadeColorMap<int> cmap_hue( 0, nbColors, 1 );
474 for ( SegmentComputerIterator i = theDecomposition.begin();
475 i != theDecomposition.end(); ++i)
477 SegmentComputer ms3d(*i);
478 const ArithmeticalDSSComputer2d & dssXY = ms3d.arithmeticalDSS2dXY();
479 const ArithmeticalDSSComputer2d & dssXZ = ms3d.arithmeticalDSS2dXZ();
480 const ArithmeticalDSSComputer2d & dssYZ = ms3d.arithmeticalDSS2dYZ();
481 Point f = *ms3d.begin();
482 Point l = *(ms3d.end() - 1);
483 trace.info() <<
"- " << c
485 <<
" [" << f[ 0 ] <<
"," << f[ 1 ] <<
","<< f[ 2 ] <<
"]"
486 <<
"->[" << l[ 0 ] <<
"," << l[ 1 ] <<
","<< l[ 2 ] <<
"]"
488 << dssXY.a() <<
"," << dssXY.b() <<
"," << dssXY.mu()
490 << dssXZ.a() <<
"," << dssXZ.b() <<
"," << dssXZ.mu()
492 << dssYZ.a() <<
"," << dssYZ.b() <<
"," << dssYZ.mu()
494 Color color = cmap_hue( c );
495 if ( tangent ) displayDSS3dTangent( viewer, ks, ms3d, color );
496 if ( dss3d ) displayDSS3d( viewer, ks, ms3d, color );
497 if ( dss2d ) displayDSS2d6( viewer, ks, ms3d, color );
498 if ( proj2d ) displayProj2d6( viewer, ks, ms3d, CURVE2D_COLOR );
508template <
typename KSpace,
typename Po
intIterator,
typename space,
typename kspace >
509bool displayCover26( PolyscopeViewer<space, kspace> & viewer,
510 const KSpace & ks, PointIterator b, PointIterator e,
511 bool dss3d,
bool proj2d,
bool dss2d,
bool tangent,
514 typedef typename PointIterator::value_type Point;
515 typedef Naive3DDSSComputer<PointIterator,int, 8 > SegmentComputer;
516 typedef SaturatedSegmentation<SegmentComputer> Decomposition;
517 typedef typename Decomposition::SegmentComputerIterator SegmentComputerIterator;
518 typedef typename SegmentComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
519 SegmentComputer algo;
520 Decomposition theDecomposition(b, e, algo);
522 HueShadeColorMap<int> cmap_hue( 0, nbColors, 1 );
525 for ( SegmentComputerIterator i = theDecomposition.begin();
526 i != theDecomposition.end(); ++i)
528 SegmentComputer ms3d(*i);
529 const ArithmeticalDSSComputer2d & dssXY = ms3d.arithmeticalDSS2dXY();
530 const ArithmeticalDSSComputer2d & dssXZ = ms3d.arithmeticalDSS2dXZ();
531 const ArithmeticalDSSComputer2d & dssYZ = ms3d.arithmeticalDSS2dYZ();
532 Point f = *ms3d.begin();
533 Point l = *(ms3d.end() - 1);
534 trace.info() <<
"- " << c
536 <<
" [" << f[ 0 ] <<
"," << f[ 1 ] <<
","<< f[ 2 ] <<
"]"
537 <<
"->[" << l[ 0 ] <<
"," << l[ 1 ] <<
","<< l[ 2 ] <<
"]"
539 << dssXY.a() <<
"," << dssXY.b() <<
"," << dssXY.mu()
541 << dssXZ.a() <<
"," << dssXZ.b() <<
"," << dssXZ.mu()
543 << dssYZ.a() <<
"," << dssYZ.b() <<
"," << dssYZ.mu()
547 Color color = cmap_hue( c );
548 if ( tangent ) displayDSS3dTangent( viewer, ks, ms3d, color );
549 if ( dss3d ) displayDSS3d( viewer, ks, ms3d, color );
550 if ( dss2d ) displayDSS2d26( viewer, ks, ms3d, color );
551 if ( proj2d ) displayProj2d26( viewer, ks, ms3d, CURVE2D_COLOR );
557template <
typename Po
intIterator,
typename Space,
typename TangentSequence >
558void ComputeVCM (
const double & R,
const double & r,
559 const PointIterator & begin,
const PointIterator & end, TangentSequence & tangents,
const std::string & output )
561 using namespace DGtal;
562 typedef ExactPredicateLpSeparableMetric < Space, 2 > Metric;
563 typedef VoronoiCovarianceMeasure < Space, Metric > VCM;
564 typedef HyperRectDomain < Space > Domain;
565 typedef functors::HatPointFunction < typename Space::Point, double > KernelFunction;
566 typedef EigenDecomposition < 3, double > LinearAlgebraTool;
567 typedef LinearAlgebraTool::Matrix Matrix;
569 fstream outputStream;
570 outputStream.open ( ( output +
".vcm" ).c_str(), std::ios::out );
571 outputStream <<
"# VCM estimation R=" << R <<
" r=" << r <<
" chi=hat" << endl;
574 VCM vcm ( R, ceil( r ), l2,
true );
575 vcm.init( begin, end );
576 KernelFunction chi( 1.0, r );
578 typename Space::RealVector eval;
579 for ( PointIterator it = begin; it != end; ++it )
582 vcm_r = vcm.measure( chi, *it );
583 LinearAlgebraTool::getEigenDecomposition ( vcm_r, evec, eval );
584 typename Space::RealVector tangent = evec.column( 0 );
585 tangents.push_back ( tangent );
586 outputStream << (*it)[0] <<
" " << (*it)[1] <<
" " << (*it)[2] <<
" "
587 << tangent[0] <<
" " << tangent[1] <<
" " << tangent[2] << endl;
589 outputStream.close();
592template <
typename Po
intIterator,
typename Space,
typename TangentSequence >
593void ComputeLMST6 (
const PointIterator & begin,
const PointIterator & end, TangentSequence & tangents,
const std::string & output )
595 typedef typename PointIterator::value_type Point;
596 typedef StandardDSS6Computer<PointIterator,int, 4 > SegmentComputer;
597 typedef SaturatedSegmentation<SegmentComputer> Decomposition;
598 typedef typename Decomposition::SegmentComputerIterator SegmentComputerIterator;
599 typedef typename SegmentComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
600 SegmentComputer algo;
601 Decomposition theDecomposition ( begin, end, algo );
603 fstream outputStream;
604 outputStream.open ( ( output +
".lmst" ).c_str(), std::ios::out );
605 outputStream <<
"X Y Z X Y Z" << endl;
607 LambdaMST3D < Decomposition > lmst64;
608 lmst64.attach ( theDecomposition );
609 lmst64.init ( begin, end );
610 lmst64.eval ( begin, end, std::back_inserter ( tangents ) );
611 typename TangentSequence::iterator itt = tangents.begin();
612 for ( PointIterator it = begin; it != end; ++it, ++itt )
614 typename Space::RealVector & tangent = (*itt);
615 if ( tangent.norm() != 0. )
616 tangent = tangent.getNormalized();
617 outputStream << (*it)[0] <<
" " << (*it)[1] <<
" " << (*it)[2] <<
" "
618 << tangent[0] <<
" " << tangent[1] <<
" " << tangent[2] << endl;
622template <
typename Po
intIterator,
typename Space,
typename TangentSequence >
623void ComputeLMST26 (
const PointIterator & begin,
const PointIterator & end, TangentSequence & tangents,
const std::string & output )
625 typedef typename PointIterator::value_type Point;
626 typedef Naive3DDSSComputer<PointIterator,int, 8 > SegmentComputer;
627 typedef SaturatedSegmentation<SegmentComputer> Decomposition;
628 typedef typename Decomposition::SegmentComputerIterator SegmentComputerIterator;
629 typedef typename SegmentComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
630 SegmentComputer algo;
631 Decomposition theDecomposition ( begin, end, algo );
633 fstream outputStream;
634 outputStream.open ( ( output +
".lmst" ).c_str(), std::ios::out );
635 outputStream <<
"X Y Z X Y Z" << endl;
637 LambdaMST3D < Decomposition > lmst64;
638 lmst64.attach ( theDecomposition );
639 lmst64.init ( begin, end );
640 lmst64.eval ( begin, end, std::back_inserter ( tangents ) );
641 typename TangentSequence::iterator itt = tangents.begin();
642 for ( PointIterator it = begin; it != end; ++it, ++itt )
644 typename Space::RealVector & tangent = (*itt);
645 if ( tangent.norm() != 0. )
646 tangent = tangent.getNormalized();
647 outputStream << (*it)[0] <<
" " << (*it)[1] <<
" " << (*it)[2] <<
" "
648 << tangent[0] <<
" " << tangent[1] <<
" " << tangent[2] << endl;
652template <
typename Po
intIterator,
typename Space,
int CONNECT = 8 >
653void find_main_axes ( PointIterator begin, PointIterator end, multimap < typename Space::Point, string > & axes )
655 typedef Naive3DDSSComputer < PointIterator, int, CONNECT > SegmentComputer;
656 typedef SaturatedSegmentation < SegmentComputer > Segmentation;
658 Segmentation segmenter ( begin, end, SegmentComputer ( ) );
660 for (
auto it = begin; it != end; ++it )
662 unsigned int cX = 0, cY = 0, cZ = 0;
663 for (
typename Segmentation::SegmentComputerIterator idss = segmenter.begin ( ); idss != segmenter.end ( ); ++idss )
665 if ( idss->isInDSS ( *it ) )
667 const typename SegmentComputer::ArithmeticalDSSComputer2d & dssXY = (*idss).arithmeticalDSS2dXY();
668 const typename SegmentComputer::ArithmeticalDSSComputer2d & dssXZ = (*idss).arithmeticalDSS2dXZ();
669 const typename SegmentComputer::ArithmeticalDSSComputer2d & dssYZ = (*idss).arithmeticalDSS2dYZ();
670 unsigned int lenXY = distance ( dssXY.begin(), dssXY.end() );
671 unsigned int lenXZ = distance ( dssXZ.begin(), dssXZ.end() );
672 unsigned int lenYZ = distance ( dssYZ.begin(), dssYZ.end() );
674 if ( lenXY >= lenYZ && lenXZ >= lenYZ )
676 else if ( lenXY >= lenXZ && lenYZ >= lenXZ )
683 axes.insert ( pair <typename Space::Point, string > ( *it,
string (
"X" ) ) );
685 axes.insert ( pair <typename Space::Point, string > ( *it,
string (
"Y" ) ) );
687 axes.insert ( pair <typename Space::Point, string > ( *it,
string (
"Z" ) ) );
692template <
typename Po
intIterator,
typename Space >
693void print_main_axes ( PointIterator begin, PointIterator end, multimap < typename Space::Point, string > & axes )
695 for ( PointIterator itt = begin; itt != end; ++itt )
697 typename std::multimap<typename Space::Point, string>::const_iterator it = axes.lower_bound(*itt);
698 typename std::multimap<typename Space::Point, string>::const_iterator it2 = axes.upper_bound(*itt);
699 cout <<
"(" << it->first[0] <<
", " << it->first[1] <<
", " << it->first[2] <<
"); MAIN_AXES = (";
700 for (; it != it2; it++ )
702 if ( distance( it, it2 ) > 1 )
703 cout << it->second <<
", ";
705 cout << it->second <<
")";
719int main(
int argc,
char **argv)
722 using namespace DGtal;
723 typedef SpaceND<3,int> Z3;
724 typedef KhalimskySpaceND<3,int> K3;
725 typedef Z3::Point Point;
726 typedef Z3::RealPoint RealPoint;
727 typedef Z3::RealVector RealVector;
728 typedef HyperRectDomain<Z3> Domain;
729 typedef typename vector<Point>::const_iterator PointIterator;
733 std::string inputFileName;
734 std::string viewFlag {
"OFF"};
735 std::string viewBox {
"WIRED"};
736 std::string connectivity {
"6"};
737 std::string method {
"VCM"};
738 std::string axesFlag {
"OFF"};
739 std::string outputFileName {
"3d-curve-tangent-estimations"};
740 bool curve3d {
false};
741 bool curve2d {
false};
742 bool cover3d {
false};
743 bool cover2d {
false};
744 bool displayTangent {
false};
745 double bigRad {10.0};
746 double smallRad {3.0};
748 unsigned int nbColors {3};
749 app.description(
"This program estimates the tangent vector to a set of 3D integer points, which are supposed to approximate a 3D curve. This set of points is given as a list of points in file <input>.\n The tangent estimator uses either the digital Voronoi Covariance Measure (VCM) or the 3D lambda-Maximal Segment Tangent (L-MST).\n This program can also displays the curve and tangent estimations, and it can also extract maximal digital straight segments (2D and 3D).\n Note: It is not compulsory for the points to be ordered in sequence, except if you wish to compute maximal digital straight segments. In this case, you can select the connectivity of your curve between 6 (standard) or 26 (naive).\n Example:\n 3dCurveTangentEstimator -i ${DGtal}/examples/samples/sinus.dat -V ON -c -R 20 -r 3 -T 6\n" );
750 app.add_option(
"-i,--input,1", inputFileName,
"the name of the text file containing the list of 3D points: (x y z) per line." )
752 ->check(CLI::ExistingFile);
754 app.add_option(
"--view,-V", viewFlag,
"toggles display ON/OFF");
755 app.add_option(
"--box,-b", box,
"specifies the tightness of the bounding box around the curve with a given integer displacement <arg> to enlarge it (0 is tight)");
756 app.add_option(
"--viewBox,-v", viewBox,
"displays the bounding box, <arg>=WIRED means that only edges are displayed, <arg>=COLORED adds colors for planes (XY is red, XZ green, YZ, blue).")
757 -> check(CLI::IsMember({
"WIRED" ,
"COLORED"}));
758 app.add_option(
"--connectivity,-T",connectivity,
"specifies whether it is a 6-connected curve or a 26-connected curve: arg=6 | 26." )
759 -> check(CLI::IsMember({
"6",
"26"}));
760 app.add_flag(
"--curve3d,-C", curve3d,
"displays the 3D curve" );
761 app.add_flag(
"--curve2d,-c", curve2d,
"displays the 2D projections of the 3D curve on the bounding box" );
762 app.add_flag(
"--cover3d,-3", cover3d,
"displays the 3D tangential cover of the curve");
763 app.add_flag(
"--cover2d,-2", cover2d,
"displays the 2D projections of the 3D tangential cover of the curve");
764 app.add_flag(
"--tangent,-t", displayTangent,
"displays the tangents to the curve.");
765 app.add_option(
"--nbColors,-n", nbColors,
"sets the number of successive colors used for displaying 2d and 3d maximal segments (default is 3: red, green, blue)");
767 app.add_option(
"--big-radius,-R",bigRad,
"the radius parameter R in the VCM estimator.");
768 app.add_option(
"--small-radius,-r",smallRad,
"the radius parameter r in the VCM estimator.");
769 app.add_option(
"--method,-m", method,
"the method of tangent computation: VCM (default), L-MST.")
770 -> check(CLI::IsMember({
"VCM",
"L-MST"}));
771 app.add_option(
"--axes,-a", axesFlag,
"show main axes - prints list of axes for each point and color points color = (if X => 255, if Y => 255, if Z => 255)")
772 -> check(CLI::IsMember({
"ON",
"OFF"}));
773 app.add_option(
"--output,-o",outputFileName,
"the basename of the output text file which will contain points and tangent vectors: (x y z tx ty tz) per line");
777 app.get_formatter()->column_width(40);
778 CLI11_PARSE(app, argc, argv);
784 vector<Point> sequence;
786 inputStream.open ( inputFileName.c_str(), ios::in);
789 sequence = PointListReader<Point>::getPointsFromInputStream( inputStream );
790 if ( sequence.size() == 0)
throw IOException();
792 catch (DGtal::IOException & ioe)
794 trace.error() <<
"Size is null." << endl;
799 bool view = viewFlag ==
"ON";
802 bool axes = axesFlag ==
"ON";
803 multimap < Z3i::Point, string > mainAxes;
805 if ( axes && connectivity ==
"26" )
807 find_main_axes<PointIterator, Z3i::Space>(sequence.begin(), sequence.end(), mainAxes);
808 print_main_axes<PointIterator, Z3i::Space>(sequence.begin(), sequence.end(), mainAxes);
810 else if ( axes && connectivity ==
"6" )
812 find_main_axes < PointIterator, Z3i::Space, 4 > ( sequence.begin ( ), sequence.end ( ), mainAxes );
813 print_main_axes<PointIterator, Z3i::Space>(sequence.begin(), sequence.end(), mainAxes);
818 Point lowerBound = sequence[ 0 ];
819 Point upperBound = sequence[ 0 ];
820 for (
unsigned int j = 1; j < sequence.size(); ++j )
822 lowerBound = lowerBound.inf( sequence[ j ] );
823 upperBound = upperBound.sup( sequence[ j ] );
825 lowerBound -= Point::diagonal( box );
826 upperBound += Point::diagonal( box + 1 );
827 K3 ks; ks.init( lowerBound, upperBound,
true );
828 PolyscopeViewer<Z3,K3> viewer( ks );
829 viewer.allowReuseList =
true;
830 trace.beginBlock (
"Tool 3dCurveTangentEstimator" );
832 std::vector< RealVector > tangents;
834 if ( method ==
"VCM" )
837 const double R = bigRad;
838 trace.info() <<
"Big radius R = " << R << endl;
839 const double r = smallRad;
840 trace.info() <<
"Small radius r = " << r << endl;
842 ComputeVCM < PointIterator, Z3, std::vector< RealVector > > ( R, r, sequence.begin(), sequence.end(), tangents, outputFileName );
844 else if ( method ==
"L-MST" )
846 if (connectivity ==
"6")
847 ComputeLMST6 < PointIterator, Z3, std::vector< RealVector > > ( sequence.begin(), sequence.end(), tangents, outputFileName );
849 ComputeLMST26 < PointIterator, Z3, std::vector< RealVector > > ( sequence.begin(), sequence.end(), tangents, outputFileName );
853 trace.info() <<
"Wrong method! Try: VCM or L-MST" << endl;
859 for (
unsigned int i = 0; i < tangents.size(); i++ )
862 RealPoint p = sequence[i];
863 RealVector tangent = tangents[i];
864 viewer.drawColor( Color ( 255, 0, 0, 255 ) );
865 viewer.drawLine( p + 2.0 * tangent, p - 2.0 * tangent);
866 viewer.drawColor( Color ( 100, 100, 140, 255 ) );
867 viewer.drawBall( p );
871 GridCurve<K3> gc( ks );
874 gc.initFromPointsVector( sequence );
876 catch (DGtal::ConnectivityException& )
879 trace.warning() <<
"[ConnectivityException] GridCurve only accepts a sequence of face adjacent points. Try connectivity=6 instead." << endl;
889 displayAxes<Point,RealPoint, Z3i::Space, Z3i::KSpace>( viewer, lowerBound, upperBound, viewBox );
891 res = connectivity ==
"6"
892 ? displayCover6( viewer, ks, sequence.begin(), sequence.end(),
898 : displayCover26( viewer, ks, sequence.begin(), sequence.end(),
905 if ( curve3d && ! axes )
907 viewer << CURVE3D_COLOR;
908 for ( vector<Point>::const_iterator it = sequence.begin(); it != sequence.end(); ++it )
911 else if ( curve3d && axes )
913 for ( vector<Point>::const_iterator itt = sequence.begin(); itt != sequence.end(); ++itt ) {
915 typename std::multimap<typename Z3i::Point, string>::const_iterator it = mainAxes.lower_bound(*itt);
916 typename std::multimap<typename Z3i::Point, string>::const_iterator it2 = mainAxes.upper_bound(*itt);
918 for (; it != it2; it++ )
920 if (it->second ==
"X")
922 if (it->second ==
"Y")
924 if (it->second ==
"Z")
928 Color c ( pColor[0], pColor[1], pColor[2], 255 );
937 trace.emphase() << ( res ?
"Passed." :
"Error." ) << endl;