Пример #1
0
// If the mesh is a topological disk, extract its longest border,
// else compute a very simple cut to make it homeomorphic to a disk.
// Return the border of this region (empty on error)
//
// CAUTION: this cutting algorithm is very naive. Write your own!
static Seam cut_mesh(Parameterization_polyhedron_adaptor& mesh_adaptor)
{
    // Helper class to compute genus or extract borders
    typedef CGAL::Parameterization_mesh_feature_extractor<Parameterization_polyhedron_adaptor>
                                            Mesh_feature_extractor;

    Seam seam;              // returned list

    // Get reference to Polyhedron_3 mesh
    Polyhedron& mesh = mesh_adaptor.get_adapted_mesh();

    // Extract mesh borders and compute genus
    Mesh_feature_extractor feature_extractor(mesh_adaptor);
    int nb_borders = feature_extractor.get_nb_borders();
    int genus = feature_extractor.get_genus();

    // If mesh is a topological disk
    if (genus == 0 && nb_borders > 0)
    {
        // Pick the longest border
        seam = feature_extractor.get_longest_border();
    }
    else // if mesh is *not* a topological disk, create a virtual cut
    {
        const int CUT_LENGTH = 6;

        // Build consecutive halfedges array
        Polyhedron::Halfedge_handle seam_halfedges[CUT_LENGTH];
        seam_halfedges[0] = mesh.halfedges_begin();
        if (seam_halfedges[0] == NULL)
            return seam;                    // return empty list
        int i;
        for (i=1; i<CUT_LENGTH; i++)
        {
            seam_halfedges[i] = seam_halfedges[i-1]->next()->opposite()->next();
            if (seam_halfedges[i] == NULL)
                return seam;                // return empty list
        }

        // Convert halfedges array to two-ways vertices list
        for (i=0; i<CUT_LENGTH; i++)
            seam.push_back(seam_halfedges[i]->vertex());
        for (i=CUT_LENGTH-1; i>=0; i--)
            seam.push_back(seam_halfedges[i]->opposite()->vertex());
    }

    return seam;
}
Пример #2
0
Eigen::Matrix4f align(pcl::PointCloud<pcl::PointXYZRGB>::Ptr source, pcl::PointCloud<pcl::PointXYZRGB>::Ptr target, int keypoint_type, int descriptor_type) {
  // if (argc < 6) 
  // {
  //   pcl::console::print_info ("Syntax is: %s <source-pcd-file> <target-pcd-file> <keypoint-method> <descriptor-type> <surface-reconstruction-method>\n", argv[0]);
  //   pcl::console::print_info ("available <keypoint-methods>: 1 = Sift3D\n");
  //   pcl::console::print_info ("                              2 = Harris3D\n");
  //   pcl::console::print_info ("                              3 = Tomasi3D\n");
  //   pcl::console::print_info ("                              4 = Noble3D\n");
  //   pcl::console::print_info ("                              5 = Lowe3D\n");
  //   pcl::console::print_info ("                              6 = Curvature3D\n\n");
  //   pcl::console::print_info ("available <descriptor-types>: 1 = FPFH\n");
  //   pcl::console::print_info ("                              2 = SHOTRGB\n");
  //   pcl::console::print_info ("                              3 = PFH\n");
  //   pcl::console::print_info ("                              4 = PFHRGB\n\n");
  //   pcl::console::print_info ("available <surface-methods>:  1 = Greedy Projection\n");
  //   pcl::console::print_info ("                              2 = Marching Cubes\n");    
    
  //   return (1);
  // }
  // pcl::console::print_info ("== MENU ==\n");
  // pcl::console::print_info ("1 - show/hide source point cloud\n");
  // pcl::console::print_info ("2 - show/hide target point cloud\n");
  // pcl::console::print_info ("3 - show/hide segmented source point cloud\n");
  // pcl::console::print_info ("4 - show/hide segmented target point cloud\n");
  // pcl::console::print_info ("5 - show/hide source key points\n");
  // pcl::console::print_info ("6 - show/hide target key points\n");
  // pcl::console::print_info ("7 - show/hide source2target correspondences\n");
  // pcl::console::print_info ("8 - show/hide target2source correspondences\n");
  // pcl::console::print_info ("9 - show/hide consistent correspondences\n");
  // pcl::console::print_info ("i - show/hide initial alignment\n");
  // pcl::console::print_info ("r - show/hide final registration\n");
  // pcl::console::print_info ("t - show/hide triangulation (surface reconstruction)\n");
  // pcl::console::print_info ("h - show visualizer options\n");
  // pcl::console::print_info ("q - quit\n");
  
  // pcl::PointCloud<pcl::PointXYZRGB>::Ptr source (new pcl::PointCloud<pcl::PointXYZRGB>);
  // pcl::io::loadPCDFile (argv[1], *source);
  
  // pcl::PointCloud<pcl::PointXYZRGB>::Ptr target (new pcl::PointCloud<pcl::PointXYZRGB>);
  // pcl::io::loadPCDFile (argv[2], *target);
  
  // int keypoint_type   = atoi (argv[3]);
  // int descriptor_type = atoi (argv[4]);
  // int surface_type    = atoi (argv[5]);
  
  boost::shared_ptr<pcl::Keypoint<pcl::PointXYZRGB, pcl::PointXYZI> > keypoint_detector;
  
  if (keypoint_type == 1)
  {
    pcl::SIFTKeypoint<pcl::PointXYZRGB, pcl::PointXYZI>* sift3D = new pcl::SIFTKeypoint<pcl::PointXYZRGB, pcl::PointXYZI>;
    sift3D->setScales(0.01, 3, 2);
    sift3D->setMinimumContrast(0.0);
    keypoint_detector.reset(sift3D);
  }
  else
  {
    pcl::HarrisKeypoint3D<pcl::PointXYZRGB,pcl::PointXYZI>* harris3D = new pcl::HarrisKeypoint3D<pcl::PointXYZRGB,pcl::PointXYZI> (pcl::HarrisKeypoint3D<pcl::PointXYZRGB,pcl::PointXYZI>::HARRIS);
    harris3D->setNonMaxSupression(true);
    harris3D->setRadius (0.01);
    harris3D->setRadiusSearch (0.01);
    keypoint_detector.reset(harris3D);
    switch (keypoint_type)
    {
      case 2:
        harris3D->setMethod(pcl::HarrisKeypoint3D<pcl::PointXYZRGB,pcl::PointXYZI>::HARRIS);
      break;

      case 3:
        harris3D->setMethod(pcl::HarrisKeypoint3D<pcl::PointXYZRGB,pcl::PointXYZI>::TOMASI);
      break;

      case 4:
        harris3D->setMethod(pcl::HarrisKeypoint3D<pcl::PointXYZRGB,pcl::PointXYZI>::NOBLE);
      break;
      
      case 5:
        harris3D->setMethod(pcl::HarrisKeypoint3D<pcl::PointXYZRGB,pcl::PointXYZI>::LOWE);
      break;

      case 6:
        harris3D->setMethod(pcl::HarrisKeypoint3D<pcl::PointXYZRGB,pcl::PointXYZI>::CURVATURE);
      break;
      default:
        pcl::console::print_error("unknown key point detection method %d\n expecting values between 1 and 6", keypoint_type);
        exit (1);
        break;
    }
    
  }
  
  boost::shared_ptr<pcl::PCLSurfaceBase<pcl::PointXYZRGBNormal> > surface_reconstruction;
  
  // if (surface_type == 1)
  // {
  //   pcl::GreedyProjectionTriangulation<pcl::PointXYZRGBNormal>* gp3 = new pcl::GreedyProjectionTriangulation<pcl::PointXYZRGBNormal>;

  //   // Set the maximum distance between connected points (maximum edge length)
  //   gp3->setSearchRadius (0.025);

  //   // Set typical values for the parameters
  //   gp3->setMu (2.5);
  //   gp3->setMaximumNearestNeighbors (100);
  //   gp3->setMaximumSurfaceAngle(M_PI/4); // 45 degrees
  //   gp3->setMinimumAngle(M_PI/18); // 10 degrees
  //   gp3->setMaximumAngle(2*M_PI/3); // 120 degrees
  //   gp3->setNormalConsistency(false);
  //   surface_reconstruction.reset(gp3);
  // }
  // else if (surface_type == 2)
  // {
  //   pcl::MarchingCubes<pcl::PointXYZRGBNormal>* mc = new pcl::MarchingCubesHoppe<pcl::PointXYZRGBNormal>;
  //   mc->setIsoLevel(0.001);
  //   mc->setGridResolution(50, 50, 50);
  //   surface_reconstruction.reset(mc);
  // }
  // else
  // {
  //   pcl::console::print_error("unknown surface reconstruction method %d\n expecting values between 1 and 2", surface_type);
  //   exit (1);
  // }
  
  Eigen::Matrix4f tf;
  switch (descriptor_type)
  {
    case 1:
    {
      pcl::Feature<pcl::PointXYZRGB, pcl::FPFHSignature33>::Ptr feature_extractor (new pcl::FPFHEstimationOMP<pcl::PointXYZRGB, pcl::Normal, pcl::FPFHSignature33>); 
      feature_extractor->setSearchMethod (pcl::search::Search<pcl::PointXYZRGB>::Ptr (new pcl::search::KdTree<pcl::PointXYZRGB>));
      feature_extractor->setRadiusSearch (0.05);
      ICCVTutorial<pcl::FPFHSignature33> tutorial (keypoint_detector, feature_extractor, surface_reconstruction, source, target);
      tutorial.run ();
      tf = tutorial.transformation_matrix_ * tutorial.initial_transformation_matrix_;
    }
    break;
    
    case 2:
    {
      pcl::SHOTEstimationOMP<pcl::PointXYZRGB, pcl::Normal, pcl::SHOT>* shot = new pcl::SHOTEstimationOMP<pcl::PointXYZRGB, pcl::Normal, pcl::SHOT>;
      shot->setRadiusSearch (0.04);
      pcl::Feature<pcl::PointXYZRGB, pcl::SHOT>::Ptr feature_extractor (shot);
      ICCVTutorial<pcl::SHOT> tutorial (keypoint_detector, feature_extractor, surface_reconstruction, source, target);
      tutorial.run ();
      tf = tutorial.transformation_matrix_ * tutorial.initial_transformation_matrix_;
    }
    break;
    
    case 3:
    {
      pcl::Feature<pcl::PointXYZRGB, pcl::PFHSignature125>::Ptr feature_extractor (new pcl::PFHEstimation<pcl::PointXYZRGB, pcl::Normal, pcl::PFHSignature125>);
      feature_extractor->setKSearch(50);
      ICCVTutorial<pcl::PFHSignature125> tutorial (keypoint_detector, feature_extractor, surface_reconstruction, source, target);
      tutorial.run ();
      tf = tutorial.transformation_matrix_ * tutorial.initial_transformation_matrix_;
    }
    break;
    
    case 4:
    {
      pcl::Feature<pcl::PointXYZRGB, pcl::PFHRGBSignature250>::Ptr feature_extractor (new pcl::PFHRGBEstimation<pcl::PointXYZRGB, pcl::Normal, pcl::PFHRGBSignature250>);
      feature_extractor->setKSearch(50);
      ICCVTutorial<pcl::PFHRGBSignature250> tutorial (keypoint_detector, feature_extractor, surface_reconstruction, source, target);
      tutorial.run ();
      tf = tutorial.transformation_matrix_ * tutorial.initial_transformation_matrix_;
    }
    break;
    
    default:
      pcl::console::print_error("unknown descriptor type %d\n expecting values between 1 and 4", descriptor_type);
      exit (1);
      break;
  }  
  
  return tf;
}
// Cut the mesh to make it homeomorphic to a disk
// or extract a region homeomorphic to a disc.
// Return the border of this region (empty on error)
//
// CAUTION:
// This method is provided "as is". It is very buggy and simply part of this example.
// Developers using this package should implement a more robust cut algorithm!
static Seam cut_mesh(Parameterization_polyhedron_adaptor& mesh_adaptor)
{
    // Helper class to compute genus or extract borders
    typedef CGAL::Parameterization_mesh_feature_extractor<Parameterization_polyhedron_adaptor_ex>
                                            Mesh_feature_extractor;
    typedef Mesh_cutter::Backbone           Backbone;

    Seam seam;              // returned list

    // Get refererence to Polyhedron_3 mesh
    Polyhedron& mesh = mesh_adaptor.get_adapted_mesh();

    // Extract mesh borders and compute genus
    Mesh_feature_extractor feature_extractor(mesh_adaptor);
    int nb_borders = feature_extractor.get_nb_borders();
    int genus = feature_extractor.get_genus();

    // If mesh is a topological disk
    if (genus == 0 && nb_borders > 0)
    {
        // Pick the longest border
        seam = feature_extractor.get_longest_border();
    }
    else // if mesh is *not* a topological disk, create a virtual cut
    {
        Backbone seamingBackbone;           // result of cutting
        Backbone::iterator he;

        // Compute a cutting path that makes the mesh a "virtual" topological disk
        mesh.compute_facet_centers();
        Mesh_cutter cutter(mesh);
        if (genus == 0)
        {
            // no border, we need to cut the mesh
            assert (nb_borders == 0);
            cutter.cut(seamingBackbone);    // simple cut
        }
        else // genus > 0 -> cut the mesh
        {
            cutter.cut_genus(seamingBackbone);
        }

        // The Mesh_cutter class is quite buggy
        // => we check that seamingBackbone is valid
        //
        // 1) Check that seamingBackbone is not empty
        if (seamingBackbone.begin() == seamingBackbone.end())
            return seam;                    // return empty list
        //
        // 2) Check that seamingBackbone is a loop and
        //    count occurences of seam halfedges
        mesh.tag_halfedges(0);              // Reset counters
        for (he = seamingBackbone.begin(); he != seamingBackbone.end(); he++)
        {
            // Get next halfedge iterator (looping)
            Backbone::iterator next_he = he;
            next_he++;
            if (next_he == seamingBackbone.end())
                next_he = seamingBackbone.begin();

            // Check that seamingBackbone is a loop: check that
            // end of current HE == start of next one
            if ((*he)->vertex() != (*next_he)->opposite()->vertex())
                return seam;                // return empty list

            // Increment counter (in "tag" field) of seam halfedges
            (*he)->tag( (*he)->tag()+1 );
        }
        //
        // 3) check that the seamingBackbone is a two-way list
        for (he = seamingBackbone.begin(); he != seamingBackbone.end(); he++)
        {
            // Counter of halfedge and opposite halfedge must be 1
            if ((*he)->tag() != 1 || (*he)->opposite()->tag() != 1)
                return seam;                // return empty list
        }

        // Convert list of halfedges to a list of vertices
        for (he = seamingBackbone.begin(); he != seamingBackbone.end(); he++)
            seam.push_back((*he)->vertex());
    }

    return seam;
}