Main Content

Extract On-Road and Off-Road Points from Point Cloud

This example shows how to extract on-road and off-road points from point cloud data.

Detecting road boundaries is an essential part of autonomous vehicle localization and decision-making. Road boundaries usually include curbs, walls, and berms.

In most scenarios, the boundary of a road is defined by the curb. A curb connects the roadway to the sidewalk. Curbs are important for safe driving, as they distinguish the drivable area from the restricted region.

To extract curb points, you must first process the point cloud data to distinguish on-road and off-road points. The on-road area consists of sidewalks, curbs, and road surfaces. The off-road area usually consists of trees, buildings, and other objects. You can extract on-road and off-road points using algorithms such as plane-fitting or ground segmentation, depending on your input data.

Plane-Fitting Method

Preprocess Point Cloud

Read the point cloud data into the workspace.

```inputPtCloud = pcread(fullfile(toolboxdir("lidar"),"lidardata", ... "sampleWPIPointClouds","pointClouds","005.pcd"));```

Extract a region of interest containing a road area from the point cloud.

```xLim = [0 25]; yLim = [-10 10]; roiIdx = findPointsInROI(inputPtCloud,[xLim yLim inputPtCloud.ZLimits]); ptCloud = select(inputPtCloud,roiIdx,OutputSize="full");```

Divide the point cloud into grids.

```gridSize = [1 1]; % in meters ptCloud = pointCloud(reshape(ptCloud.Location(:,:,:),[],3)); numGridsX = round(diff(ptCloud.XLimits)/gridSize(1)); numGridsY = round(diff(ptCloud.YLimits)/gridSize(2));```

Extract the point indices from each grid.

`indices = pcbin(ptCloud,[numGridsX numGridsY 1]);`

Extract Off-Road Points

Specify an off-road height threshold.

`offRoadHeightThreshold = 1.5; % in meters`

Extract the indices of the off-road points from the grids.

```offRoadPointsIdx = false(size(ptCloud.Location,1),1); for i=1:numGridsX*numGridsY if ~isempty(indices{i}) gridHeight = ptCloud.Location(indices{i},3); if (max(gridHeight) - min(gridHeight)) > offRoadHeightThreshold offRoadPointsIdx(indices{i}) = true; end end end```

Extract the off-road point cloud.

```offRoadPtCloud = select(inputPtCloud,offRoadPointsIdx); ```

Extract On-Road Points

Extract the on-road points from the remaining points in the point cloud by using the `pcfitplane` function. Alternatively, you can use the `segmentGroundFromLidarData` function.

```remainingPtCloud = select(inputPtCloud,~offRoadPointsIdx,OutputSize="full"); [~,inlierIdx,~] = pcfitplane(remainingPtCloud,1,[0 0 1]); onRoadPtCloud = select(remainingPtCloud,inlierIdx,OutputSize="full");```

Display the on-road and off-road points.

`pcshowpair(offRoadPtCloud,onRoadPtCloud)`

Ground Segmentation Method

Preprocess Point Cloud

Read point cloud data into the workspace.

`ptCloud = pcread("HDL64LidarData.pcd");`

Organize the point cloud.

`ptCloud = pcorganize(ptCloud,lidarParameters("HDL64E",1024));`

Extract a region of interest containing a road area from the point cloud.

```roi = [-25 25 -10 24 ptCloud.ZLimits]; indices = findPointsInROI(ptCloud,roi); ptCloud = select(ptCloud,indices,OutputSize="full");```

Extract On-Road and Off-Road Points

Segment the on-road and off-road points from the point cloud by using the `segmentGroundSMRF` function. Alternatively, you can use the `segmentGroundFromLidarData` function.

`[~,offRoadPtCloud,onRoadPtCloud] = segmentGroundSMRF(ptCloud);`

Display the on-road and off-road points.

`pcshowpair(offRoadPtCloud,onRoadPtCloud)`

Detecting Road Boundary

After extracting the on-road and off-road points, you can further process them by using the `detectRoadAngles` function, to identify the road directions. Then, use the `segmentCurbPoints` function to extract the curb points from the on-road point cloud.