3

I am learning how to use ICP with PCL. As such I wrote a function that reads a series of .pcd files from a given folder.

//Reads all PCD files in a folder. Specify the path without the last '/' and the number on the last and first file: xxx.pcb.
//Returns null if something goes wrong. Otherwise returns a single global pointcloud with each subcloud colour coded.
pcl::PointCloud<pcl::PointXYZRGB>::Ptr LoadPCDFiles(std::string FolderPath, int FinalFile, int FirstFile)
{
    //Initialize some variables we need.
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>());
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr Global(new pcl::PointCloud<pcl::PointXYZRGB>());
    srand(time(NULL));
    int FileIter = FirstFile;
    std::string BasePathString = FolderPath + "/%.3d.pcd";
    Eigen::Matrix4f AccumulatedTransformationMatrix = Eigen::Matrix4f::Identity();

    while (FileIter <= FinalFile) {
        char buffer[260];
        std::sprintf(buffer, BasePathString.c_str(), FileIter);
        std::string path(buffer);
        cloud = ReadPCDFile(path, std::rand() % 256, std::rand() % 256, std::rand() % 256);
        if (cloud == NULL) return NULL;//Error
        //pcl::transformPointCloud<pcl::PointXYZRGB>(*cloud, *cloud, Eigen::Vector3f(cloud->sensor_origin_.x(), cloud->sensor_origin_.y(), cloud->sensor_origin_.z()), cloud->sensor_orientation_);
        //pcl::transformPointCloud<pcl::PointXYZRGB>(*cloud, *cloud, AccumulatedTransformationMatrix);

        int AlignmentIter = 0; //The number of alignment attemps we have made.
        int MaxAlignment = 25; //Maax number of attempts allowed.
        float LastFitness = VTK_FLOAT_MAX;
        bool hasConverged = false;
        std::cout << "Loaded PCD: " << path << std::endl;
        if (FileIter != FirstFile) {

            while (AlignmentIter < MaxAlignment && LastFitness > 0.001) {
                pcl::PointCloud<pcl::PointXYZRGB>::Ptr Temp(new pcl::PointCloud<pcl::PointXYZRGB>());
                pcl::IterativeClosestPoint<pcl::PointXYZRGB, pcl::PointXYZRGB> icp;
                icp.setInputSource(cloud);
                icp.setInputTarget(Global);

                icp.align(*Temp);

                float CurrentFitness = icp.getFitnessScore();
                hasConverged = icp.hasConverged();
                std::cout << "Alignment value: " << CurrentFitness << std::endl;

                if (abs(LastFitness - CurrentFitness) < 0.0001) { break; }

                cloud = Temp;
                LastFitness = CurrentFitness;
                AlignmentIter++;
            }


            //AccumulatedTransformationMatrix = AccumulatedTransformationMatrix * icp.getFinalTransformation();
            if (hasConverged) {
                *Global = *Global + *cloud;

                std::cout << "Updated global cloud: " << (*Global).size() << std::endl;
            } else {
                std::cout << "Unable to align the clouds." << std::endl;
            }
        } else {
            *Global = *cloud;
            std::cout << "First subcloud added." << std::endl;
        }



        FileIter++;
    }

    std::cout << "Merged clouds." << std::endl;
    return Global;
}

However, this produces some very messy clouds.

Two simple PCs of a corner

This had a fitness value of just over 0.052. An entire room of PCs

This had fitness values in the range 0.0030 - 0.0856. All values.

Each cloud I have given a random colour to highlight what cloud ended up where.

The ReadPCDFile() function simply reads the file specified and adds the random colour. The commented out lines of code is simply my desperate messing with some ideas, but ultimately they all failed.

This is an example of one of the PCD files.

# .PCD v.7 - Point Cloud Data file format
VERSION .7
FIELDS x y z
SIZE 4 4 4
TYPE F F F
COUNT 1 1 1
WIDTH 13509
HEIGHT 1
VIEWPOINT 7.9950223 0.60561943 0.4050533 - 0.3022367 0.019049812 0.95157933 0.052790195
POINTS 13509
DATA ascii
- 1.0610341 - 0.55464476 1.933659
- 1.0921015 - 0.5514014 1.9721884
- 1.0254035 - 0.55889213 1.922963
- 1.0736096 - 0.54884547 1.9840248
- 1.1002594 - 0.5510374 1.9640691
- 1.05391 - 0.556308 1.9436798
- 1.0801263 - 0.5577761 1.9309663
- 1.1306747 - 0.54748887 1.9968926
- 0.98958766 - 0.55052584 1.926852
.
.
.

I hope you can help. Do not hesitate to ask for any info that I can provide.

Thank you very much for your help.

Community
  • 1
  • 1
Noobs DeSroobs
  • 253
  • 1
  • 6
  • 24
  • How about starting with just two point clouds, preferably ones which are clearly align-able? When trying to get those two to align well it should be easier to grasp what's going wrong. And then go from there. – HenningJ Sep 03 '15 at 08:57
  • I did add just two point clouds. The first picture shows that. I had just two clouds of the same corner with a slightly different angle. – Noobs DeSroobs Sep 04 '15 at 17:31
  • What is the output of || std::cout << icp.getFinalTransformation() << std::endl; || if you get an identity matrix it didn't calculate the icp – Martijn van Wezel Sep 29 '15 at 15:23

1 Answers1

1

I am also learning how to use ICP with PCL. I found there are several parameters you can set, like

icp.setTransformationEpsilon(1e-6);
icp.setMaximumIterations(1e6);

After this, I found my fitness score better (0.005 to 2e-5).

Dawei Yang
  • 606
  • 1
  • 9
  • 19