An end-to-end drone → 3D → detections → inventory pipeline for municipal (and utility-adjacent) tree work.
This repository is maintained by Gabriel Priante (Applied Data Scientist + Project Manager @ Frontline Gig) as the working home for turning DJI Mini 5 Pro field captures into geospatially-referenced tree detections and a clean inventory export.
At a high level:
CSV + GeoJSON) and a quick-look mapTop-level contents (as of 2026-03-07):
pipeline.py Main end-to-end runner scriptdetection-images/ Workspace folder (repo-managed)detection-data/ Workspace folder (repo-managed)LICENSE Open-source licenseNote: There’s also a
.DS_Storecommitted at repo root (macOS Finder metadata).
pipeline.py actually runs)The pipeline is intentionally linear, with each stage producing durable artifacts you can inspect, re-run, or swap out.
Inputs supported:
.mp4, .mov, .lrv, .ts) from a DJI orbital flight—the script will extract frames via ffmpegIf an accompanying DJI .SRT file exists, it’s copied alongside the imagery because ODM can use it to improve georeferencing.
ODM runs via Docker (opendronemap/odm) and generates core spatial products:
odm_orthophoto/odm_orthophoto.tifodm_georeferencing/odm_georeferenced_model.lazodm_texturing/odm_textured_model.objodm_dem/dsm.tif and odm_dem/dtm.tifThe script uses higher-quality defaults (e.g., high point-cloud quality and ~2 cm/pixel orthophoto) and includes guardrails for running locally on modest hardware (with a suggestion to use WebODM Lightning for larger datasets).
If you don’t want to run ODM locally, you can run:
python pipeline.py --input /path/to/video_or_images --project my_project --cloud
This prints WebODM Lightning instructions, then you re-run with --skip-odm after downloading outputs into the project folder.
DeepForest is applied to the orthomosaic using tiled prediction (so large rasters still work):
outputs/tree_detections.csvoutputs/tree_detections.geojsonEach detection is assigned a stable ID like TREE_0001 and enriched with:
Important: If there’s no orthomosaic (or the orbital flight doesn’t produce enough top-down coverage), the script skips detections and points you to point-cloud-based workflows instead.
When ODM produces both a DSM and DTM, the pipeline computes a Canopy Height Model (CHM):
outputs/canopy_height_model.tifThen it samples the CHM around each detection and appends:
height_m and height_ftIf DSM/DTM are missing (common in some orbital-only capture styles), height extraction is skipped and the README recommends trunk/height measurement from the point cloud using external tooling.
The final inventory is saved to:
outputs/tree_inventory.csvIt includes a clean column set appropriate for handoff to ops, GIS, or downstream analytics (IDs, crown metrics, optional height, survey date, and placeholder fields for health/species/notes).
A PNG overlay is generated for fast QA and stakeholder previews:
outputs/tree_detection_map.pngInside each project folder (created under ~/drone-projects/<project>/ by default):
outputs/tree_detections.csv Raw DeepForest boxes + metricsoutputs/tree_detections.geojson GIS export (QGIS / ArcGIS Online)outputs/tree_inventory.csv Clean inventory for reporting/opsoutputs/tree_detection_map.png QA visualizationoutputs/canopy_height_model.tif Height surface (only if DSM/DTM exist)The script imports these at runtime (install however you prefer):
deepforestgeopandasrasterionumpy, pandasmatplotlibshapelypython pipeline.py --input ~/drone-footage/DJI_0001.MP4 --project my_first_tree
python pipeline.py --input ~/drone-footage/photos/ --project lot_survey
python pipeline.py --input ~/drone-footage/DJI_0001.MP4 --project test --frames-only
python pipeline.py --input ~/drone-footage/photos/ --project lot_survey --cloud
# ... upload images, download results into the project folder ...
python pipeline.py --input ~/drone-projects/lot_survey --project lot_survey --skip-odm
This repo’s automated path focuses on crowns + geospatial inventory via ODM + DeepForest.
For trunk/DBH and detailed 3D measurements, the workflow described in pipeline.py expects you to take the ODM point cloud and use CloudCompare + 3DFin (or equivalent tooling):
odm_georeferencing/odm_georeferenced_model.laztree_inventory.csv (by location or a matching scheme)See LICENSE.
38 commits
3 commits
Python
100.0%
An end-to-end drone → 3D → detections → inventory pipeline for municipal (and utility-adjacent) tree work.
This repository is maintained by Gabriel Priante (Applied Data Scientist + Project Manager @ Frontline Gig) as the working home for turning DJI Mini 5 Pro field captures into geospatially-referenced tree detections and a clean inventory export.
At a high level:
CSV + GeoJSON) and a quick-look mapTop-level contents (as of 2026-03-07):
pipeline.py Main end-to-end runner scriptdetection-images/ Workspace folder (repo-managed)detection-data/ Workspace folder (repo-managed)LICENSE Open-source licenseNote: There’s also a
.DS_Storecommitted at repo root (macOS Finder metadata).
pipeline.py actually runs)The pipeline is intentionally linear, with each stage producing durable artifacts you can inspect, re-run, or swap out.
Inputs supported:
.mp4, .mov, .lrv, .ts) from a DJI orbital flight—the script will extract frames via ffmpegIf an accompanying DJI .SRT file exists, it’s copied alongside the imagery because ODM can use it to improve georeferencing.
ODM runs via Docker (opendronemap/odm) and generates core spatial products:
odm_orthophoto/odm_orthophoto.tifodm_georeferencing/odm_georeferenced_model.lazodm_texturing/odm_textured_model.objodm_dem/dsm.tif and odm_dem/dtm.tifThe script uses higher-quality defaults (e.g., high point-cloud quality and ~2 cm/pixel orthophoto) and includes guardrails for running locally on modest hardware (with a suggestion to use WebODM Lightning for larger datasets).
If you don’t want to run ODM locally, you can run:
python pipeline.py --input /path/to/video_or_images --project my_project --cloud
This prints WebODM Lightning instructions, then you re-run with --skip-odm after downloading outputs into the project folder.
DeepForest is applied to the orthomosaic using tiled prediction (so large rasters still work):
outputs/tree_detections.csvoutputs/tree_detections.geojsonEach detection is assigned a stable ID like TREE_0001 and enriched with:
Important: If there’s no orthomosaic (or the orbital flight doesn’t produce enough top-down coverage), the script skips detections and points you to point-cloud-based workflows instead.
When ODM produces both a DSM and DTM, the pipeline computes a Canopy Height Model (CHM):
outputs/canopy_height_model.tifThen it samples the CHM around each detection and appends:
height_m and height_ftIf DSM/DTM are missing (common in some orbital-only capture styles), height extraction is skipped and the README recommends trunk/height measurement from the point cloud using external tooling.
The final inventory is saved to:
outputs/tree_inventory.csvIt includes a clean column set appropriate for handoff to ops, GIS, or downstream analytics (IDs, crown metrics, optional height, survey date, and placeholder fields for health/species/notes).
A PNG overlay is generated for fast QA and stakeholder previews:
outputs/tree_detection_map.pngInside each project folder (created under ~/drone-projects/<project>/ by default):
outputs/tree_detections.csv Raw DeepForest boxes + metricsoutputs/tree_detections.geojson GIS export (QGIS / ArcGIS Online)outputs/tree_inventory.csv Clean inventory for reporting/opsoutputs/tree_detection_map.png QA visualizationoutputs/canopy_height_model.tif Height surface (only if DSM/DTM exist)The script imports these at runtime (install however you prefer):
deepforestgeopandasrasterionumpy, pandasmatplotlibshapelypython pipeline.py --input ~/drone-footage/DJI_0001.MP4 --project my_first_tree
python pipeline.py --input ~/drone-footage/photos/ --project lot_survey
python pipeline.py --input ~/drone-footage/DJI_0001.MP4 --project test --frames-only
python pipeline.py --input ~/drone-footage/photos/ --project lot_survey --cloud
# ... upload images, download results into the project folder ...
python pipeline.py --input ~/drone-projects/lot_survey --project lot_survey --skip-odm
This repo’s automated path focuses on crowns + geospatial inventory via ODM + DeepForest.
For trunk/DBH and detailed 3D measurements, the workflow described in pipeline.py expects you to take the ODM point cloud and use CloudCompare + 3DFin (or equivalent tooling):
odm_georeferencing/odm_georeferenced_model.laztree_inventory.csv (by location or a matching scheme)See LICENSE.
38 commits
3 commits
Python
100.0%