# PCL learning notes -- segmentation algorithm based on minimum graph cut

Posted by wizzkid on Sun, 02 Jan 2022 18:09:49 +0100

1, Introduction

Based on the segmentation algorithm of minimum graph cut, by setting the radius of the target object, three-dimensional coordinates, center of gravity and other parameters, the algorithm divides the input point cloud set into two point sets, the front scenic spot set (target object) and the background point cloud (the rest). The idea of the algorithm is as follows:

1) construction graph: first define the source point and sink point. For the input point cloud, take each point as the vertex of the graph, and each vertex on the way is connected with the source point and sink point to form an edge, corresponding to the above t-links. In addition, each vertex (except the source point and sink point) is connected with its adjacent points, corresponding to the above n-links.

2) according to different types of connection points, edges are divided into the following three cases. In different cases, edges are given different weights:

(1) connect the edges between the points of the input point cloud, and the weight given to the above edges becomes the smoothing cost, which is calculated by the following formula:

Where dist is the distance between points. The greater the distance between two points, the greater the possibility that the edge between the two points will be cut off.

(2) the edge connecting the point in the input point cloud and the source point. The weight given by the edge is called foreground penalty. The value is input by the user as the input parameter of the algorithm;

(3) the edge connecting the point in the input point cloud and the sink point, and the weight given to the above edge is called background penalty, which is calculated by the following formula:

Where, distanceToCenter is the horizontal distance from the point to the expected center of the foreground point cloud (target object), which is calculated by the following formula:

Where, Radius is the input parameter of the algorithm, which can be roughly regarded as the horizontal Radius of the foreground point cloud (target object), the points less than the Radius are regarded as the foreground point cloud (target object), and the points greater than the Radius are regarded as the background point cloud (other objects).

3) after the preparation of the minimum graph cut algorithm is completed, the minimum graph cut is calculated for the above constructed graph, and the point cloud can be divided into foreground point cloud (target object) and background point cloud (other objects).

2, Code analysis

1) first, set the point cloud file and parameter input method, and define the default input parameters:

```	if(argc<2)
{
std::cout<<".exe xx.pcd -bc 1 -fc 1.0 -nc 0 -cx 68.97 -cy -18.55 -cz 0.57 -s 0.25 -r 3.0433856 -non 14 -sw 0.5"<<endl;

return 0;
}//If the input parameter is less than 1, the prompt information will be output
time_t start,end,diff[5],option;
start = time(0);
int NumberOfNeighbours=14;//Set default parameters
bool Bool_Cuting=false;//Set default parameters
float far_cuting=1,near_cuting=0,C_x=0.071753,C_y= -0.309913,C_z=1.603000,Sigma=0.25,Radius=0.8,SourceWeight=0.5;//Set default input parameters
pcl::PointCloud <pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud <pcl::PointXYZ>);// Create a pointcloud < PCL:: pointxyzrgb > shared pointer and instantiate it
if ( pcl::io::loadPCDFile <pcl::PointXYZ> (argv[1], *cloud) == -1 )// Load point cloud data
{
std::cout << "Cloud reading failed." << std::endl;
return (-1);
}

parse_argument (argc, argv, "-bc", Bool_Cuting);
parse_argument (argc, argv, "-fc", far_cuting);
parse_argument (argc, argv, "-nc", near_cuting);

parse_argument (argc, argv, "-cx", C_x);
parse_argument (argc, argv, "-cy", C_y);
parse_argument (argc, argv, "-cz", C_z);

parse_argument (argc, argv, "-s", Sigma);
parse_argument (argc, argv, "-non", NumberOfNeighbours);
parse_argument (argc, argv, "-sw", SourceWeight);//Set input parameter mode
```

2) next, the point cloud is selectively filtered through by inputting parameters to extract the filtered point set and save it in the index:

```	pcl::IndicesPtr indices (new std::vector <int>);//Create a set of indexes
if(Bool_Cuting)//Determine whether direct filtering is required
{
pcl::PassThrough<pcl::PointXYZ> pass;//Set pass through filter object
pass.setInputCloud (cloud);//Set input point cloud
pass.setFilterFieldName ("z");//Sets the dimension of the specified filter
pass.setFilterLimits (near_cuting, far_cuting);//Sets the range of the specified latitude filter
pass.filter (*indices);//Perform filtering and save the filtering results in the above index

}
```

3) instantiate a pcl::MinCutSegmentation class, and then determine the input point cloud overall or point cloud index by entering parameters:

```	pcl::MinCutSegmentation<pcl::PointXYZ> seg;//Create a PointXYZRGB type area growth segmentation object
seg.setInputCloud (cloud);//Set input point cloud
if(Bool_Cuting)seg.setIndices (indices);//Sets the index of the input point cloud
```

4) then, the center of the foreground point cloud, which is the coordinate of the center of gravity of the target object assumed by the user in advance, has the greatest impact on the segmentation result. Set the Sigma value required for the smoothing cost and the radius of the background penalty. The smaller the Sigma value, the smoothing cost will decrease rapidly with the increase of the distance between the two vertices, but the sigma change in the test has little impact on the segmentation result:

```	foreground_points->points.push_back(point);
seg.setForegroundPoints (foreground_points);//Enter the center point of the foreground point cloud (target object)

seg.setSigma (Sigma);//Set Sigma value for smoothing cost
```

5) set the number of adjacent points to be found when the algorithm constructs the graph. The larger the setting is, the more n-links are included in the way, which increases the calculation events and improves the difficulty of segmentation; Set the foreground penalty weight. The more you set, the greater the probability of segmentation into foreground:

```	seg.setNumberOfNeighbours (NumberOfNeighbours);//Set the number of adjacent points
seg.setSourceWeight (SourceWeight);//Set foreground penalty weight
```

6) the overall code is as follows:

```#include <iostream>
#include <vector>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/passthrough.h>
#include <pcl/segmentation/min_cut_segmentation.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <pcl/console/time.h>
using namespace pcl::console;
int main (int argc, char** argv)
{
if(argc<2)
{
std::cout<<".exe xx.pcd -bc 1 -fc 1.0 -nc 0 -cx 68.97 -cy -18.55 -cz 0.57 -s 0.25 -r 3.0433856 -non 14 -sw 0.5"<<endl;

return 0;
}//If the input parameter is less than 1, the prompt information will be output
time_t start,end,diff[5],option;
start = time(0);
int NumberOfNeighbours=14;//Set default parameters
bool Bool_Cuting=false;//Set default parameters
float far_cuting=1,near_cuting=0,C_x=0.071753,C_y= -0.309913,C_z=1.603000,Sigma=0.25,Radius=0.8,SourceWeight=0.5;//Set default input parameters
pcl::PointCloud <pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud <pcl::PointXYZ>);// Create a pointcloud < PCL:: pointxyzrgb > shared pointer and instantiate it
if ( pcl::io::loadPCDFile <pcl::PointXYZ> (argv[1], *cloud) == -1 )// Load point cloud data
{
std::cout << "Cloud reading failed." << std::endl;
return (-1);
}

parse_argument (argc, argv, "-bc", Bool_Cuting);
parse_argument (argc, argv, "-fc", far_cuting);
parse_argument (argc, argv, "-nc", near_cuting);

parse_argument (argc, argv, "-cx", C_x);
parse_argument (argc, argv, "-cy", C_y);
parse_argument (argc, argv, "-cz", C_z);

parse_argument (argc, argv, "-s", Sigma);
parse_argument (argc, argv, "-non", NumberOfNeighbours);
parse_argument (argc, argv, "-sw", SourceWeight);//Set input parameter mode

pcl::IndicesPtr indices (new std::vector <int>);//Create a set of indexes
if(Bool_Cuting)//Determine whether direct filtering is required
{
pcl::PassThrough<pcl::PointXYZ> pass;//Set pass through filter object
pass.setInputCloud (cloud);//Set input point cloud
pass.setFilterFieldName ("z");//Sets the dimension of the specified filter
pass.setFilterLimits (near_cuting, far_cuting);//Sets the range of the specified latitude filter
pass.filter (*indices);//Perform filtering and save the filtering results in the above index

}
pcl::MinCutSegmentation<pcl::PointXYZ> seg;//Create a PointXYZRGB type area growth segmentation object
seg.setInputCloud (cloud);//Set input point cloud
if(Bool_Cuting)seg.setIndices (indices);//Sets the index of the input point cloud

pcl::PointCloud<pcl::PointXYZ>::Ptr foreground_points(new pcl::PointCloud<pcl::PointXYZ> ());//Create a pointcloud < PCL:: pointxyzrgb > shared pointer and instantiate it
pcl::PointXYZ point;//Define the center point and assign a value

point.x =C_x;
point.y = C_y;
point.z = C_z;
foreground_points->points.push_back(point);
seg.setForegroundPoints (foreground_points);//Enter the center point of the foreground point cloud (target object)

seg.setSigma (Sigma);//Set Sigma value for smoothing cost
seg.setNumberOfNeighbours (NumberOfNeighbours);//Set the number of adjacent points
seg.setSourceWeight (SourceWeight);//Set foreground penalty weight

std::vector <pcl::PointIndices> clusters;
seg.extract (clusters);//Obtain the segmentation result, which is saved in the vector of the point cloud index.

std::cout << "Maximum flow is " << seg.getMaxFlow () << std::endl;//Calculate and output the flow value calculated during segmentation

pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = seg.getColoredCloud ();//Give red to the front scenic spot and white to the background point.
pcl::visualization::PCLVisualizer viewer ("Point cloud Library PCL Learning tutorial Second Edition-Minimum cut segmentation method");