All 4 tools share a common raster-to-vector pipeline (phases 0-3, 5-6, 8) implemented in _postproc_common.py. Each tool adds domain-specific phases (4 and 7) via its own core module. The UI and parameter logic live in PostProcessing.pyt.
Spatial Analyst + 3D Analyst extensions. ArcGIS Pro 3.6+.
Optional (Road centerlines)
shapely, scipy, networkx, numpy — for Voronoi medial axis. Falls back to Thin if missing.
V
Vehicle analysis
Detect and classify vehicle features by area and length/width ratio
Ph 0-3 Shared
→
Ph 4 Simplify
→
Ph 5-6 Geom+Enrich
→
Ph 7 Classify
→
Ph 8 Export
Phase 4 — Simplify
SimplifyPolygon with POINT_REMOVE algorithm. Removes the pixel-staircase effect from raw vectorized polygons. The tolerance (default 0.10 m) controls how aggressively vertices are removed. Collapsed polygons (too small to survive simplification) are counted but not kept.
Phase 7 — Classification
Three criteria, applied in order:
Area below min (default 1.5 m²) — too small for a vehicle
Area above max (default 12 m²) — likely a building or merged blob
L/W ratio below min (default 1.5) — too square, not vehicle-shaped
Reference sizes: motorcycle 1.5-2.5 m², car 5-9 m², SUV 9-12 m².
Output fields
Field
Type
Description
VehicleID
Long
Sequential identifier
Area_m2
Double
Polygon area in square meters
LW_Ratio
Double
MBR length / width ratio
MEAN_nDSM
Double
Mean height above ground (m)
Class
Text
Vehicle or Rejected possible vehicle
Reason
Text
Area_below_min, Area_above_max, LW_below_min, or empty
B
Building analysis
Extract and regularize building footprints with height-based classification
Ph 0-3 Shared
→
Ph 4 Regularize
→
Ph 5-6 Geom+Enrich
→
Ph 7 Classify
→
Ph 8 Export
Phase 4 — Regularize footprint
RegularizeBuildingFootprint from ArcGIS 3D Analyst enforces architectural geometry. Three methods available:
RIGHT_ANGLES — orthogonal edges (default, most buildings)
Tolerance (default 0.20 m) controls edge straightening aggressiveness.
Phase 7 — Classification
Four criteria with minimum nDSM height (floor logic — buildings must be elevated):
Area below min (default 5 m²) — too small for a building
Area above max (default 1000 m²) — likely a merged block
nDSM is NULL — reject or keep with warning (configurable)
nDSM below min (default 1.0 m) — too flat, not a building
T
Tree analysis
Crown detection with optional watershed or grid-based separation
Ph 0-3 Shared
→
Ph 4 Smooth
→
Ph 4.5 Crown sep.
→
Ph 5-7 Classify
→
Ph 8 Export
Phase 4 — Smooth polygons
SmoothPolygon with the PAEK algorithm produces organic, naturally curved crown shapes — unlike the angular SimplifyPolygon used for vehicles. The tolerance (default 0.30 m) controls curve tightness. Tree crowns are round in nature, so PAEK smoothing matches their actual shape better than point-removal.
Phase 4.5 — Crown separation (optional)
Splitting merged canopy polygons into individual trees
When trees grow close together, their crowns merge into large polygons in the classified raster. Three options are available (mutually exclusive):
Option 1: None (default)
No crown separation. Each polygon = one tree or merged group. Best for sparse canopy.
Option 2: Watershed
nDSM-based individual tree crown detection (ITCD). Uses local maxima as seed points.
Option 3: Grid
Simple fishnet overlay + Intersect. Deterministic, no nDSM needed. Good for uniform canopy.
Watershed crown separation — how it works
This is a marker-controlled watershed segmentation using the nDSM to find individual tree peaks. It runs only on large polygons (above a configurable area threshold, default 120 m²) because small polygons are likely individual trees already.
Mask nDSM to large polygons
→
Smooth nDSM focal mean
→
Invert (Negate)
→
Local maxima + prominence
Label seeds RegionGroup
→
FlowDirection + Watershed
→
Vectorize zones
→
Intersect clip to original
Key design decisions
Prominence filter: A peak must rise at least 2 m above the local minimum within the search radius. This prevents false peaks from minor nDSM undulations.
Minimum 3 peaks to split: If a large polygon has fewer than 3 detected peaks, it stays intact — splitting into 2 would create halves, not meaningful crowns.
Area preservation: Split pieces are clipped to the original polygon boundary, so the total canopy area is exactly preserved.
Parameter
Default
Purpose
Min area for watershed
120 m²
Only polygons larger than this are processed
Search radius
6.0 m
Local maxima detection neighborhood radius
Smooth radius
2.5 m
Focal mean smoothing before peak detection (hardcoded)
Prominence min
2.0 m
Peak must rise this much above local min (hardcoded)
Grid splitting — how it works
The simplest approach: a regular fishnet grid (default 5 m cell) is overlaid on all tree polygons, and Intersect splits them at grid boundaries. This is completely deterministic and doesn't use the nDSM for crown detection.
CreateFishnet grid over extent
→
Intersect polygons x grid
→
Result split pieces
Best for: uniform canopy density where the grid cell size approximates average crown diameter. Not recommended when trees have highly variable crown sizes.
R
Road analysis
Road network extraction with Voronoi medial axis centerlines
Ph 0-3 Shared
→
Ph 4a Simp+Dissolve
→
Ph 5-6 Geom+Enrich
→
Ph 7 Classify
→
Ph 7.5 Centerlines
→
Ph 8 Export
Phase 4a — Simplify + Dissolve
Two steps unique to roads:
SimplifyPolygon (POINT_REMOVE, 0.15 m) — removes pixel staircase
Dissolve (SINGLE_PART) — merges all touching polygons into contiguous road segments
After dissolve, 296 raw fragments might become 45 road segments. This is essential because roads are linear features, not discrete objects.
Phase 7 — Classification
Roads use inverted nDSM logic (ceiling, not floor) plus MBR dimensions:
Area below min (2 m²) — noise patch
nDSM is NULL — reject or keep (configurable)
nDSM above max (0.5 m) — elevated, not a road
MBR length below min (3 m) — too short
MBR width below min (1.5 m) — too narrow
Phase 7.5 — Voronoi centerline extraction
Medial axis approach for road centerlines
The centerline extraction converts accepted road polygons into polyline features representing the road network. Two methods are available:
arcpy-only. Rasterize, Thin, RasterToPolyline, TrimLine. Produces spurs at junctions.
Voronoi centerline — step by step
For each accepted road polygon:
Fill holes ≤ 20 m²
→
Densify boundary
→
scipy Voronoi
→
Interior edges only
networkx graph
→
Prune short branches
→
shapely linemerge
→
SpatialJoin + PAEK smooth
Why Voronoi and not Thin?
The original morphological Thin approach produced excessive spurs at junctions and variable-width sections. The Voronoi medial axis computes the true geometric center of the polygon at every point. Combined with graph-based pruning, it produces clean centerlines that handle intersections natively.
Hole filling
Vehicles, shadows, and small misclassified objects sitting inside road polygons create interior holes. The Voronoi medial axis would branch around each hole, producing noisy centerlines. Filling holes smaller than max_hole_area (default 20 m², covering most vehicles at ~12 m²) before computing the medial axis eliminates these artifacts.
Graph pruning
After filtering to interior Voronoi edges, short dead-end branches remain along the polygon boundary. The pruning algorithm walks from each degree-1 node (leaf) toward the nearest junction (degree 3+). If the walk distance is shorter than prune_factor x median_road_width, the branch is removed. This repeats iteratively until stable.
Parameter
Default
Purpose
Min centerline length
5.0 m
Removes short fragments after extraction
Max hole area
20 m²
Fill vehicle/shadow holes before Voronoi
Prune factor
2.0x
Branch pruning = factor x median road width
Densify factor
5.0x
Boundary sampling = factor x cell size
Max boundary pts
15,000
Cap to prevent excessive computation (hardcoded)
Developed by Nikolaos Koroniadis · MSc Geography and Applied Geoinformatics · University of the Aegean
Remote Sensing & GIS Research Group · MicaSense Altum-PT · ArcGIS Pro 3.6.2