---
kind: concept
slug: mathematical-morphology
title: Mathematical morphology
summary: >-
  Mathematical morphology uses grey-scale dilation, closing and masked fills, with a fixed kernel per step, to shape an image or depth map. One card: a classical chain that densifies sparse LIDAR depth with no training and about 90 Hz on a CPU. Its constants were tuned greedily on KITTI validation, so they may not transfer. All numbers are author-reported.
tags: [image-processing, depth, cpu-inference, no-training]
papers: ["1802.00036"]
related: [depth-completion, image-denoising, canny-edge-detection]
status: draft
updated_at: 2026-11-01
---

## Overview

Morphological operations change an image by looking at a small neighbourhood
around each pixel, called the kernel, and combining the values in it. The
paper's pipeline uses OpenCV's grey-scale operations, in which dilation keeps
the larger value in the neighbourhood, so a bright value spreads into its
neighbours [arxiv:1802.00036 §4]. Closing joins small gaps by combining dilation
with erosion, and a masked fill writes values only into pixels that were empty
[arxiv:1802.00036 §4].

The shared idea is that the operation is fixed by a kernel shape and size,
and that the order of the steps matters. The paper's central point is that
the order needs the values to be inverted first: otherwise the empty value
zero would overwrite real depths in a dilation [arxiv:1802.00036 §4]. The
variants below differ only in the kernel and in which optional steps run.
The one card for this concept is [Fast Depth Completion on the CPU](/papers/1802.00036),
which uses the operations to fill sparse LIDAR depth [arxiv:1802.00036 §3].

## Variants

### Inverted-depth dilation pipeline (paper's method)

Eight steps in fixed order: invert depth, dilate with a 5×5 diamond kernel,
close with a 5×5 full kernel, fill empty pixels from a 7×7 full dilation,
optionally extend the top of the frame and fill large holes from a 31×31 full
dilation, apply a median and a Gaussian blur, then invert back [arxiv:1802.00036
§4]. On the KITTI depth completion test set it reports 1288.46 mm RMSE and
302.60 mm MAE, with a runtime of 0.011 s on an Intel Core i7-7700K [arxiv:1802.00036
tab. 1]. Card: [Fast Depth Completion on the CPU](/papers/1802.00036).

### Optional extension and large-hole fill

The top-of-frame extension copies the highest valid value in each column
upward, and the 31×31 fill then closes the rest. The authors present both as
steps of the algorithm [arxiv:1802.00036 §4], but they also say the two steps
add many extrapolated points, and suggest turning them off for practical use
[arxiv:1802.00036 §5.2]. On the validation split, the paper's final median plus
Gaussian blur gives 1350.93 mm RMSE [arxiv:1802.00036 tab. 3]; the table does
not split out the effect of the extension alone. Card: [Fast Depth Completion on the CPU](/papers/1802.00036).

## When to use which

| Situation | Use | Why |
|---|---|---|
| Sparse depth, CPU only, no training data | Inverted-depth dilation pipeline | Runs at about 90 Hz on an i7-7700K and needs no GPU or training set [arxiv:1802.00036 §5.1] [arxiv:1802.00036 tab. 1] |
| Sensor or depth range far from KITTI | Re-tune every kernel and the 100 m constant | Constants were chosen greedily on KITTI validation: size, then shape, then blur [arxiv:1802.00036 §5.2] |
| Downstream use needs no invented geometry | Turn off the extension and the 31×31 fill | The authors say the extension adds extrapolated points and suggest disabling it [arxiv:1802.00036 §5.2] |
| Need the lowest iRMSE on KITTI | Not this method | The paper's nearest-neighbour plus CNN baseline has a lower iRMSE (3.25 vs 3.78 1/km), though a higher RMSE [arxiv:1802.00036 tab. 1] |
| Measuring the cost of each kernel choice | Validation split | The ablations use the validation split, not the test server [arxiv:1802.00036 §5] |

## Implementation sketch

Pseudocode of the paper's pipeline, in the style of the paper cards. Values are
in metres, and zero marks an empty pixel [arxiv:1802.00036 §4].

```pseudocode
# Inverted-depth morphology for sparse depth  [arxiv:1802.00036 §4]
# Input:  depth (H, W) in metres; 0 marks an empty pixel
# Output: depth (H, W) in metres

def complete(depth, max_depth=100.0, extend=False):
    # Invert so that the grey-scale max keeps real values  [arxiv:1802.00036 §4]
    valid = depth > 0
    depth = where(valid, max_depth - depth, depth)
    # Dilate with a 5x5 diamond kernel  [arxiv:1802.00036 §4] [arxiv:1802.00036 tab. 2]
    depth = dilate(depth, diamond_5x5)
    # Close small gaps with a 5x5 full kernel  [arxiv:1802.00036 §4]
    depth = close(depth, full_5x5)
    # Fill only the empty pixels from a 7x7 full dilation  [arxiv:1802.00036 §4]
    empty = depth == 0
    depth[empty] = dilate(depth, full_7x7)[empty]
    if extend:
        # Copy the highest valid value of each column upward  [arxiv:1802.00036 §4]
        depth = extend_to_top(depth)
        # Fill the rest of the empty pixels from a 31x31 full dilation  [arxiv:1802.00036 §4]
        empty = depth == 0
        depth[empty] = dilate(depth, full_31x31)[empty]
    # Remove outliers with a 5x5 median, then smooth with a 5x5 Gaussian  [arxiv:1802.00036 tab. 3]
    depth = gaussian(median(depth, 5), 5)
    # Undo the inversion  [arxiv:1802.00036 §4]
    valid = depth > 0
    return where(valid, max_depth - depth, depth)
```

Points to check when porting: the paper's own output formula subtracts from
100 m for every pixel, while the released code keeps empty pixels at zero
[arxiv:1802.00036 §4]. The card records this and other code-only details
[Fast Depth Completion on the CPU](/papers/1802.00036).

## Contradictions

Within the one paper, the authors describe the extension and large-hole fill
as steps of the algorithm [arxiv:1802.00036 §4], and later suggest turning them
off for practical use because they add extrapolated points [arxiv:1802.00036
§5.2]. Both statements are the paper's; the page does not resolve them.

No contradictions between papers are known, because only one card exists.

## Papers

- [Fast Depth Completion on the CPU](/papers/1802.00036): classical morphology and blur chain for sparse LIDAR depth, with no training, author-reported 1288.46 mm test RMSE on KITTI.
