/** * Algorithms that computes the convex hull * of a point set */ void convexHull() { //Digitization of a disk of radius 6 Ball2D<Z2i::Space> ball(Z2i::Point(0,0), 6); Z2i::Domain domain(ball.getLowerBound(), ball.getUpperBound()); Z2i::DigitalSet pointSet(domain); Shapes<Z2i::Domain>::euclideanShaper(pointSet, ball); //! [Hull2D-Namespace] using namespace functions::Hull2D; //! [Hull2D-Namespace] //! [Hull2D-Functor] typedef InHalfPlaneBySimple3x3Matrix<Z2i::Point, DGtal::int64_t> Functor; Functor functor; //! [Hull2D-Functor] { //convex hull in counter-clockwise order vector<Z2i::Point> res; //! [Hull2D-StrictPredicateCCW] typedef PredicateFromOrientationFunctor2<Functor, false, false> StrictPredicate; StrictPredicate predicate( functor ); //! [Hull2D-StrictPredicateCCW] //according to the last two template arguments, neither strictly negative values, nor zeros are accepted: //the predicate returns 'true' only for strictly positive values returned by the underlying functor. //! [Hull2D-AndrewAlgo] andrewConvexHullAlgorithm( pointSet.begin(), pointSet.end(), back_inserter( res ), predicate ); //! [Hull2D-AndrewAlgo] //![Hull2D-Caliper-computeBasic] double th = DGtal::functions::Hull2D::computeHullThickness(res.begin(), res.end(), DGtal::functions::Hull2D::HorizontalVerticalThickness); //![Hull2D-Caliper-computeBasic] //![Hull2D-Caliper-computeAnti] Z2i::Point antipodalP, antipodalQ, antipodalS; th = DGtal::functions::Hull2D::computeHullThickness(res.begin(), res.end(), DGtal::functions::Hull2D::HorizontalVerticalThickness, antipodalP, antipodalQ, antipodalS); //![Hull2D-Caliper-computeAnti] trace.info() <<" ConvexHull HV thickness: " << th << std::endl; //display Board2D board; drawPolygon( res.begin(), res.end(), board ); //![Hull2D-Caliper-display] board.setPenColor(DGtal::Color::Red); board.drawCircle( antipodalS[0], antipodalS[1], 0.2) ; board.setPenColor(DGtal::Color::Blue); board.drawCircle(antipodalP[0], antipodalP[1], 0.2); board.drawCircle(antipodalQ[0], antipodalQ[1], 0.2); board.drawLine(antipodalP[0], antipodalP[1], antipodalQ[0], antipodalQ[1]); //![Hull2D-Caliper-display] board.saveSVG( "ConvexHullCCW.svg" ); #ifdef WITH_CAIRO board.saveCairo("ConvexHullCCW.png", Board2D::CairoPNG); #endif } { //convex hull in counter-clockwise order with all the points lying on the edges vector<Z2i::Point> res; //! [Hull2D-LargePredicateCCW] typedef PredicateFromOrientationFunctor2<Functor, false, true> LargePredicate; LargePredicate predicate( functor ); //! [Hull2D-LargePredicateCCW] //according to the last template argument, zeros are accepted so that //the predicate returns 'true' for all the positive values returned by the underlying functor. //andrew algorithm andrewConvexHullAlgorithm( pointSet.begin(), pointSet.end(), back_inserter( res ), predicate ); //display Board2D board; drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "ConvexHullCCWWithPointsOnEdges.svg" ); #ifdef WITH_CAIRO board.saveCairo("ConvexHullCCWWithPointsOnEdges.png", Board2D::CairoPNG); #endif } { //convex hull in clockwise order vector<Z2i::Point> res; //! [Hull2D-StrictPredicateCW] typedef PredicateFromOrientationFunctor2<Functor, true, false> StrictPredicate; StrictPredicate predicate( functor ); //! [Hull2D-StrictPredicateCW] //according to the last two argument template, //the predicate returns 'true' only for strictly negative values returned by the underlying functor. //andrew algorithm andrewConvexHullAlgorithm( pointSet.begin(), pointSet.end(), back_inserter( res ), predicate ); //display Board2D board; drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "ConvexHullCW.svg" ); #ifdef WITH_CAIRO board.saveCairo("ConvexHullCW.png", Board2D::CairoPNG); #endif } { //convex hull in counter-clockwise order vector<Z2i::Point> res; //geometric predicate typedef PredicateFromOrientationFunctor2<Functor, false, false> StrictPredicate; StrictPredicate predicate( functor ); //! [Hull2D-GrahamAlgo] grahamConvexHullAlgorithm( pointSet.begin(), pointSet.end(), back_inserter( res ), predicate ); //! [Hull2D-GrahamAlgo] //display Board2D board; drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "ConvexHullCCWbis.svg" ); #ifdef WITH_CAIRO board.saveCairo("ConvexHullCCWbis.png", Board2D::CairoPNG); #endif } { //convex hull of a simple polygonal line that is not weakly externally visible vector<Z2i::Point> polygonalLine; polygonalLine.push_back(Z2i::Point(0,0)); polygonalLine.push_back(Z2i::Point(0,4)); polygonalLine.push_back(Z2i::Point(1,4)); polygonalLine.push_back(Z2i::Point(1,1)); polygonalLine.push_back(Z2i::Point(3,1)); polygonalLine.push_back(Z2i::Point(2,2)); polygonalLine.push_back(Z2i::Point(3,4)); polygonalLine.push_back(Z2i::Point(4,4)); polygonalLine.push_back(Z2i::Point(4,0)); vector<Z2i::Point> resGraham, res; typedef PredicateFromOrientationFunctor2<Functor, false, false> StrictPredicate; StrictPredicate predicate( functor ); closedGrahamScanFromAnyPoint( polygonalLine.begin(), polygonalLine.end(), back_inserter( resGraham ), predicate ); //! [Hull2D-OnLineMelkmanAlgo] DGtal::MelkmanConvexHull<Z2i::Point, Functor> ch( functor ); for (std::vector<Z2i::Point>::const_iterator it = polygonalLine.begin(), itEnd = polygonalLine.end(); it != itEnd; ++it) ch.add( *it ); //! [Hull2D-OnLineMelkmanAlgo] //! [Hull2D-OffLineMelkmanAlgo] melkmanConvexHullAlgorithm( polygonalLine.begin(), polygonalLine.end(), back_inserter( res ), functor ); //! [Hull2D-OffLineMelkmanAlgo] //display Board2D board; drawPolygon( polygonalLine.begin(), polygonalLine.end(), board, true ); board.saveSVG( "SimplePolygonalLine.svg" ); #ifdef WITH_CAIRO board.saveCairo("SimplePolygonalLine.png", Board2D::CairoPNG); #endif board.clear(); drawPolygon( resGraham.begin(), resGraham.end(), board ); board.saveSVG( "SimplePolygonalLineGraham.svg" ); #ifdef WITH_CAIRO board.saveCairo("SimplePolygonalLineGraham.png", Board2D::CairoPNG); #endif board.clear(); drawPolygon( res.begin(), res.end(), board ); board.saveSVG( "SimplePolygonalLineMelkman.svg" ); #ifdef WITH_CAIRO board.saveCairo("SimplePolygonalLineMelkman.png", Board2D::CairoPNG); #endif board.clear(); drawPolygon( ch.begin(), ch.end(), board ); board.saveSVG( "SimplePolygonalLineMelkman2.svg" ); #ifdef WITH_CAIRO board.saveCairo("SimplePolygonalLineMelkman2.png", Board2D::CairoPNG); #endif } { //order of the points for andrew algorithm vector<Z2i::Point> res; std::copy( pointSet.begin(), pointSet.end(), back_inserter( res ) ); std::sort( res.begin(), res.end() ); //display Board2D board; drawPolygon( res.begin(), res.end(), board, false ); board.saveSVG( "AndrewWEVP.svg" ); #ifdef WITH_CAIRO board.saveCairo("AndrewWEVP.png", Board2D::CairoPNG); #endif } { //order of the points for graham algorithm vector<Z2i::Point> res; std::copy( pointSet.begin(), pointSet.end(), back_inserter( res ) ); //find an extremal point //NB: we choose the point of greatest x-coordinate //so that the sort step (by a polar comparator) //returns a weakly externally visible polygon std::vector<Z2i::Point>::iterator itMax = std::max_element( res.begin(), res.end() ); //sort around this point with a polar comparator functors::PolarPointComparatorBy2x2DetComputer<Z2i::Point> comparator; comparator.setPole( *itMax ); std::sort( res.begin(), res.end(), comparator ); //display Board2D board; drawPolygon( res.begin(), res.end(), board, false ); board.saveSVG( "GrahamWEVP.svg" ); #ifdef WITH_CAIRO board.saveCairo("GrahamWEVP.png", Board2D::CairoPNG); #endif } }
int main( int argc, char** argv ) { using namespace DGtal; using namespace DGtal::Z2i; typedef ImageContainerBySTLVector<Domain,unsigned char> GrayLevelImage2D; typedef ImageContainerBySTLVector<Domain,float> FloatImage2D; typedef DistanceToMeasure<FloatImage2D> Distance; if ( argc <= 3 ) return 1; GrayLevelImage2D img = GenericReader<GrayLevelImage2D>::import( argv[ 1 ] ); double mass = atof( argv[ 2 ] ); double rmax = atof( argv[ 3 ] ); FloatImage2D fimg( img.domain() ); FloatImage2D::Iterator outIt = fimg.begin(); for ( GrayLevelImage2D::ConstIterator it = img.begin(), itE = img.end(); it != itE; ++it ) { float v = ((float)*it) / 255.0; *outIt++ = v; } trace.beginBlock( "Computing delta-distance." ); Distance delta( mass, fimg, rmax ); const FloatImage2D& d2 = delta.myDistance2; trace.endBlock(); float m = 0.0f; for ( typename Domain::ConstIterator it = d2.domain().begin(), itE = d2.domain().end(); it != itE; ++it ) { Point p = *it; float v = sqrt( d2( p ) ); m = std::max( v, m ); } GradientColorMap<float> cmap_grad( 0, m ); cmap_grad.addColor( Color( 255, 255, 255 ) ); cmap_grad.addColor( Color( 255, 255, 0 ) ); cmap_grad.addColor( Color( 255, 0, 0 ) ); cmap_grad.addColor( Color( 0, 255, 0 ) ); cmap_grad.addColor( Color( 0, 0, 255 ) ); cmap_grad.addColor( Color( 0, 0, 0 ) ); Board2D board; board << SetMode( d2.domain().className(), "Paving" ); for ( typename Domain::ConstIterator it = d2.domain().begin(), itE = d2.domain().end(); it != itE; ++it ) { Point p = *it; float v = sqrt( d2( p ) ); v = std::min( (float)m, std::max( v, 0.0f ) ); board << CustomStyle( p.className(), new CustomColors( Color::Black, cmap_grad( v ) ) ) << p; RealVector grad = delta.projection( p ); board.drawLine( p[ 0 ], p[ 1 ], p[ 0 ] + grad[ 0 ], p[ 1 ] + grad[ 1 ], 0 ); } std::cout << endl; board.saveEPS("delta2.eps"); return 0; }
int main( int argc, char** argv ) { using namespace DGtal; using namespace DGtal::Z2i; typedef ImageContainerBySTLVector<Domain,unsigned char> GrayLevelImage2D; typedef ImageContainerBySTLVector<Domain,double> DoubleImage2D; typedef DistanceToMeasure<DoubleImage2D> Distance; if ( argc <= 3 ) return 1; GrayLevelImage2D img = GenericReader<GrayLevelImage2D>::import( argv[ 1 ] ); double mass = atof( argv[ 2 ] ); double rmax = atof( argv[ 3 ] ); double R = atof( argv[ 4 ] ); double r = atof( argv[ 5 ] ); double T1 = atof( argv[ 6 ] ); double T2 = atof( argv[ 7 ] ); DoubleImage2D fimg( img.domain() ); DoubleImage2D::Iterator outIt = fimg.begin(); for ( GrayLevelImage2D::ConstIterator it = img.begin(), itE = img.end(); it != itE; ++it ) { double v = ((double)*it) / 255.0; *outIt++ = v; } trace.beginBlock( "Computing delta-distance." ); Distance delta( mass, fimg, rmax ); const DoubleImage2D& d2 = delta.myDistance2; trace.endBlock(); double m = 0.0f; for ( typename Domain::ConstIterator it = d2.domain().begin(), itE = d2.domain().end(); it != itE; ++it ) { Point p = *it; double v = sqrt( d2( p ) ); m = std::max( v, m ); } GradientColorMap<double> cmap_grad( 0, m ); cmap_grad.addColor( Color( 255, 255, 255 ) ); cmap_grad.addColor( Color( 255, 255, 0 ) ); cmap_grad.addColor( Color( 255, 0, 0 ) ); cmap_grad.addColor( Color( 0, 255, 0 ) ); cmap_grad.addColor( Color( 0, 0, 255 ) ); cmap_grad.addColor( Color( 0, 0, 0 ) ); Board2D board; board << SetMode( d2.domain().className(), "Paving" ); for ( typename Domain::ConstIterator it = d2.domain().begin(), itE = d2.domain().end(); it != itE; ++it ) { Point p = *it; double v = sqrt( d2( p ) ); v = std::min( (double) m, std::max( v, 0.0 ) ); board << CustomStyle( p.className(), new CustomColors( Color::Black, cmap_grad( v ) ) ) << p; RealVector grad = delta.projection( p ); board.drawLine( p[ 0 ], p[ 1 ], p[ 0 ] + grad[ 0 ], p[ 1 ] + grad[ 1 ], 0 ); } std::cout << endl; board.saveEPS("dvcm-delta2.eps"); board.clear(); trace.beginBlock( "Computing delta-VCM." ); typedef DeltaVCM< Distance > DVCM; typedef DVCM::Matrix Matrix; DVCM dvcm( delta, R, r ); trace.endBlock(); { GrayLevelImage2D pm_img( dvcm.myProjectedMeasure.domain() ); DoubleImage2D::ConstIterator it = dvcm.myProjectedMeasure.begin(); DoubleImage2D::ConstIterator itE = dvcm.myProjectedMeasure.end(); GrayLevelImage2D::Iterator outIt = pm_img.begin(); for ( ; it != itE; ++it ) { double v = std::max( 0.0, std::min( (*it) * 255.0, 255.0 ) ); *outIt++ = v; } GenericWriter< GrayLevelImage2D >::exportFile( "dvcm-projmeasure.pgm", pm_img ); } typedef EigenDecomposition<2,double> LinearAlgebraTool; typedef functors::HatPointFunction<Point,double> KernelFunction; KernelFunction chi( 1.0, r ); // Flat zones are metallic blue, slightly curved zones are white, // more curved zones are yellow till red. double size = 1.0; GradientColorMap<double> colormap( 0.0, T2 ); colormap.addColor( Color( 128, 128, 255 ) ); colormap.addColor( Color( 255, 255, 255 ) ); colormap.addColor( Color( 255, 255, 0 ) ); colormap.addColor( Color( 255, 0, 0 ) ); Matrix vcm_r, evec, null; RealVector eval; for ( Domain::ConstIterator it = dvcm.domain().begin(), itE = dvcm.domain().end(); it != itE; ++it ) { // Compute VCM and diagonalize it. Point p = *it; vcm_r = dvcm.measure( chi, p ); if ( vcm_r == null ) continue; LinearAlgebraTool::getEigenDecomposition( vcm_r, evec, eval ); //double feature = eval[ 0 ] / ( eval[ 0 ] + eval[ 1 ] ); eval[ 0 ] = std::max( eval[ 0 ], 0.00001 ); double tubular = ( eval[ 1 ] <= 0.00001 ) // (R*R/4.0) ) ? 0 : ( eval[ 1 ] / ( eval[ 0 ] + eval[ 1 ] ) ); double bound = T1; double tubular2 = tubular * (eval[ 0 ] + eval[ 1 ]) / (R*R*r/12.0); double display = tubular2 <= bound ? 0.0 : ( tubular2 - bound ) / (1.0 - bound); //: eval[ 1 ] / ( 1.0 + eval[ 0 ] ) / ( 1.0 + delta( p )*delta( p ) ); //: eval[ 1 ] * eval[ 1 ] / ( 1.0 + eval[ 0 ] ) / ( 1.0 + delta( p ) ); trace.info() << "l0=" << eval[ 0 ] << " l1=" << eval[ 1 ] << " tub=" << tubular << " tub2=" << tubular2 << " disp=" << display << std::endl; board << CustomStyle( p.className(), new CustomColors( Color::Black, colormap( display > T2 ? T2 : display ) ) ) << p; // Display normal RealVector normal = evec.column( 0 ); RealPoint rp( p[ 0 ], p[ 1 ] ); Display2DFactory::draw( board, size*normal, rp ); Display2DFactory::draw( board, -size*normal, rp ); } board.saveEPS("dvcm-hat-r.eps"); board.clear(); return 0; }