Search code examples
c++mesh3d-reconstruction

Using PCL(point cloud library) to obtain an array of an object information


As an example, in a 2D space, a position of a square is presented by the set of '1's and a position of empty space is presented by the set of '0's like

00000000000000
00000111000000
00000111000000
00000111000000
00000000000000

It is found that pcl::OrganizedFastMesh class is a way to do this task. The website of http://docs.pointclouds.org/trunk/classpcl_1_1_organized_fast_mesh.html shows the details of the class, however, it is very difficult to understand to me. For example, if the input file name is 'example.stl', how to obtain the above '0's and '1's information to an array 'siteInfo[][]'?


Solution

  • In order to import from stl, you need to generate the points from vertices. Here is my function for importing stl into pcl point cloud:

    //generates an evenly distributed point cloud from stl file (assumed to be scaled in mm)
    //maxPPDist: desired max distance between points (all surfaces will be upsampled until this density is reached)
    //normalNeighborCount: how many points to include in NN normal resampling. (should match what is used on camera cloud)
    bool PCL_Util::importCAD_STL(pcl::PointCloud<pcl::PointNormal>::Ptr &objectCloud,
    std::string fileName,
    double maxPPDist,
    bool normResample,
    int normalNeighborCount,
    bool fastNormRecombination)
    {
    
    pcl::PolygonMesh mesh;
    int fileReadVal;
    try
    {
        fileReadVal = pcl::io::loadPolygonFileSTL(fileName, mesh);
    }
    catch (...)
    {
        return false;
    }
    
    if (fileReadVal == 0)
    {
        PCL_ERROR("Failed to load STL file\n");
        return false;
    }
    else
    {
        pcl::PointCloud<pcl::PointNormal>::Ptr outputCloud(new pcl::PointCloud<pcl::PointNormal>);
    
        pcl::PointCloud<pcl::PointXYZ> objCloud;
        pcl::PCLPointCloud2 ptCloud2 = mesh.cloud;
        pcl::fromPCLPointCloud2(ptCloud2, objCloud);
    
        for (int i = 0; i < mesh.polygons.size(); i++)
        {
            pcl::Vertices currentPoly = mesh.polygons[i];
    
            for (int ii = 0; ii < currentPoly.vertices.size(); ii++)
            {
                pcl::PointNormal currentPt = pcl::PointNormal();
                currentPt.x = objCloud[currentPoly.vertices[ii]].x;
                currentPt.y = objCloud[currentPoly.vertices[ii]].y;
                currentPt.z = objCloud[currentPoly.vertices[ii]].z;
                outputCloud->points.push_back(currentPt);//push in points without normals
            }
    
            //make the assumption that at least 3 verticies for last poly (standard stl... not sure how dirty this is)
            int index = outputCloud->points.size() - 1;
            pcl::PointXYZ pt3(outputCloud->points[index].x, outputCloud->points[index].y, outputCloud->points[index].z);
            pcl::PointXYZ pt2(outputCloud->points[index - 1].x, outputCloud->points[index - 1].y, outputCloud->points[index - 1].z);
            pcl::PointXYZ pt1(outputCloud->points[index - 2].x, outputCloud->points[index - 2].y, outputCloud->points[index - 2].z);
    
            Eigen::Vector3f vec12(pt2.x - pt1.x, pt2.y - pt1.y, pt2.z - pt1.z);
            Eigen::Vector3f vec23(pt3.x - pt2.x, pt3.y - pt2.y, pt3.z - pt2.z);
            Eigen::Vector3f vecNorm = vec12.cross(vec23);
            vecNorm.normalize();
    
            for (int ii = 0; ii < 3; ii++)
            {
                outputCloud->points[index - ii].normal_x = vecNorm[0];
                outputCloud->points[index - ii].normal_y = vecNorm[1];
                outputCloud->points[index - ii].normal_z = vecNorm[2];
            }
    
            //interpolate each triangular surface to fit desired resolution
            if (maxPPDist != -1)
            {
                interpolateTriangle(outputCloud, maxPPDist);
            }
        }
    
        if (fastNormRecombination)//faster by an order of magnitude, but less accurate normals stl surface join points
        {
            voxelPruneCloud<pcl::PointNormal>(outputCloud, maxPPDist / 2.0f, maxPPDist / 2.0f, maxPPDist / 2.0f);
        }
        else//very slow, but generates more accurate normals at joint points
        {
            combineColocatedPoints(outputCloud, maxPPDist / 2.0f);
        }
    
        if (normResample)//uses the current normals as hemisphere guides for newly calculated normals
        {
            resampleNormalCloud(outputCloud, normalNeighborCount);
        }
    
    
        copyPointCloud(*outputCloud, *objectCloud);
        printf("File imported successfully?!\n");
        return true;
    }
    }
    

    As far as generating a 2d array... I would look into raycasting to generate a structured point cloud/ surface. (http://www.pcl-users.org/From-3D-point-cloud-to-depth-map-td4027567.html) I personally wrote my own implementation to allow for threading, but I am sure pcl has some built in functions.