# Identifying ground returns using ProgressiveMorphologicalFilter segmentation

Author: | Bradley Chambers
Contact: | brad.chambers@gmail.com
Date: | 10/28/2015

Implements the Progressive Morphological Filter for segmentation of ground points.

Note

`filters.ground` required PCL and has since been replaced by filters.pmf, which is a native PDAL filter. ground has been retained, but now calls filters.pmf under the hood as opposed to `filters.ground` and is installed as a native PDAL kernel independent of the PCL plugin. As such, the outputs shown in this tutorial may vary slightly, but the underlying algorithm is identical.

## Background

A complete description of the algorithm can be found in the article “A Progressive Morphological Filter for Removing Nonground Measurements from Airborne LIDAR Data” by K. Zhang, S. Chen, D. Whitman, M. Shyu, J. Yan, and C. Zhang.

For more information on how to invoke this PCL-based filter programmatically, see the ProgressiveMorphologicalFilter tutorial on the PCL website.

We have chosen to demonstrate the algorithm using data from the 2003 report “ISPRS Comparison of Filters.” For more on the data and the study itself, please see http://www.itc.nl/isprswgIII-3/filtertest/ as well as “Experimental comparison of filter algorithms for bare-earth extraction from airborne laser scanning point clouds” by G. Sithole and G. Vosselman.

First, download the dataset CSite1_orig-utm.laz and save it somewhere to disk.

## Using the Ground kernel

The pdal ground kernel can be used to filter ground returns, allowing the user to tweak filtering parameters at the command-line.

Let’s start by running `pdal ground` with the default parameters.

    $ pdal ground -i CSite1_orig-utm.laz -o CSite1_orig-utm-ground.laz

To get an idea of what’s happening during each iteration, you can optionally increase the verbosity of the output. We’ll try `-v4`. Here we see a summary of the parameters, along with height threshold, window size, and number of remaining ground points.

    $ pdal ground -i CSite1_orig-utm.laz -o CSite1_orig-utm-ground.laz -v4

    --------------------------------------------------------------------------------
    NAME:    ()
    HELP:
    AUTHOR:
    --------------------------------------------------------------------------------
    process tile 0 through the pipeline

       Step 1) ProgressiveMorphologicalFilter

          max window size: 33
          slope: 1.000000
          max distance: 2.500000
          initial distance: 0.150000
          cell size: 1.000000
          base: 2.000000
          exponential: true
          negative: false
          Iteration 0 (height threshold = 0.150000, window size = 3.000000)...ground now has 872413  points
          Iteration 1 (height threshold = 2.150000, window size = 5.000000)...ground now has 833883 points
          Iteration 2 (height threshold = 2.500000, window size = 9.000000)...ground now has 757030 points
          Iteration 3 (height threshold = 2.500000, window size = 17.000000)...ground now has 625333 points
          Iteration 4 (height threshold = 2.500000, window size = 33.000000)...ground now has 580852 points
          1366408 points filtered to 580852 following progressive morphological filter

The resulting filtered cloud can be seen in this top-down and front view. When viewed from the side, it is apparent that there are a number of low noise points that have fooled the PMF filter.

To address, we introduce an alternate way to call PMF, as part of a PCL pipeline, where we preprocess with an outlier removal step. The command is nearly identical, replacing `ground` with `pcl` and adding a pipeline JSON specified with `-p`.

    {
      "pipeline": {
        "name": "Progressive Morphological Filter with Outlier Removal",
        "version": 1.0,
        "filters": [{
            "name": "StatisticalOutlierRemoval",
            "setMeanK": 8,
            "setStddevMulThresh": 3.0
          }, {
            "name": "ProgressiveMorphologicalFilter"
        }]
      }
    }

    $ pdal pcl -i CSite1_orig-utm.laz -o CSite1_orig-utm-ground.laz -p sor-pmf.json -v4

    --------------------------------------------------------------------------------
    NAME:   Progressive Morphological Filter with Outlier Removal (1.0)
    HELP:
    AUTHOR:
    --------------------------------------------------------------------------------
    process tile 0 through the pipeline

       Step 1) StatisticalOutlierRemoval

          8 neighbors and 3.000000 multiplier
          1366408 points filtered to 1356744 following outlier removal

       Step 2) ProgressiveMorphologicalFilter

          max window size: 33
          slope: 1.000000
          max distance: 2.500000
          initial distance: 0.150000
          cell size: 1.000000
          base: 2.000000
          exponential: true
          negative: false
          Iteration 0 (height threshold = 0.150000, window size = 3.000000)...ground now has 874094 points
          Iteration 1 (height threshold = 2.150000, window size = 5.000000)...ground now has 837141 points
          Iteration 2 (height threshold = 2.500000, window size = 9.000000)...ground now has 762213 points
          Iteration 3 (height threshold = 2.500000, window size = 17.000000)...ground now has 632827 points
          Iteration 4 (height threshold = 2.500000, window size = 33.000000)...ground now has 596620 points
          1356744 points filtered to 596620 following progressive morphological filter

The result is noticeably cleaner in both the top-down and front views.

Unfortunately, you may notice that we still have a rather large building in the lower right of the image. By tweaking the parameters slightly, in this case, increasing the cell size, we can do a better job of removing such features.

    {
      "pipeline": {
        "name": "Progressive Morphological Filter with Outlier Removal",
        "version": 1.0,
        "filters": [{
            "name": "StatisticalOutlierRemoval",
            "setMeanK": 8,
            "setStddevMulThresh": 3.0
          }, {
            "name": "ProgressiveMorphologicalFilter",
            "setCellSize": 1.5
        }]
      }
    }

    $ pdal pcl -i CSite1_orig-utm.laz -o CSite1_orig-utm-ground.laz -p sor-pmf2.json -v4

    --------------------------------------------------------------------------------
    NAME:   Progressive Morphological Filter with Outlier Removal (1.0)
    HELP:
    AUTHOR:
    --------------------------------------------------------------------------------
    process tile 0 through the pipeline

       Step 1) StatisticalOutlierRemoval

          8 neighbors and 3.000000 multiplier
          1366408 points filtered to 1356744 following outlier removal

       Step 2) ProgressiveMorphologicalFilter

          max window size: 33
          slope: 1.000000
          max distance: 2.500000
          initial distance: 0.150000
          cell size: 1.500000
          base: 2.000000
          exponential: true
          negative: false
          Iteration 0 (height threshold = 0.150000, window size = 4.500000)...ground now has 785496 points
          Iteration 1 (height threshold = 2.500000, window size = 7.500000)...ground now has 728738 points
          Iteration 2 (height threshold = 2.500000, window size = 13.500000)...ground now has 623385 points
          Iteration 3 (height threshold = 2.500000, window size = 25.500000)...ground now has 581679 points
          Iteration 4 (height threshold = 2.500000, window size = 49.500000)...ground now has 551006 points
          1356744 points filtered to 551006 following progressive morphological filter

Once again, the result is noticeably cleaner in both the top-down and front views.