Estimate Canopy Height from Aerial and Satellite Imagery with GeoAI
In this tutorial, I show you how to estimate canopy height from aerial or satellite imagery using pretrained deep learning models with just one or two lines of code. The GeoAI Python package integrates Meta’s High-Resolution Canopy Height Model, which was trained on aerial imagery, satellite imagery, and airborne/spaceborne LiDAR data. You can run the model on GPU for fast inference (a few seconds) or on CPU if no GPU is available (5-10 minutes).
Video tutorial: Estimate Canopy Height with GeoAI
What You Will Need¶
Python 3.9 or later with the GeoAI package installed.
A GPU with at least 8 GB of memory is recommended for fast inference. The model also runs on CPU, but it will be significantly slower (10-20x).
High-resolution aerial or satellite imagery (e.g., USDA NAIP or Maxar). This does not work with coarse-resolution imagery like Landsat.
Install GeoAI using conda (recommended) or pip. See the installation guide for details.
Available Models¶
Meta provides four pretrained model checkpoints:
Small aerial model (CPU-friendly, smaller file size): Best for getting started with aerial imagery.
Large aerial model (~2.9 GB): Higher accuracy for aerial imagery, requires GPU.
Small satellite model: For satellite imagery on CPU.
Large satellite model: For satellite imagery with GPU.
Choose the model based on your input data type (aerial vs. satellite) and available hardware. You can list all available models in GeoAI:
from geoai.canopy import list_canopy_models
list_canopy_models()Step-by-Step Workflow¶
Import the Library¶
import geoai
from geoai.canopy import CanopyHeightEstimationDownload Sample Data¶
GeoAI provides two sample files for testing: an RGB aerial image and the corresponding ground truth canopy height model.
rgb_image = geoai.download_file("sample_rgb.tif")
ground_truth = geoai.download_file("sample_chm.tif")You can visualize them side by side in the notebook. The ground truth shows taller trees in yellow and ground/water in darker colors.
Initialize the Model¶
estimator = CanopyHeightEstimation(model_name="aerial_small")On first run, the model checkpoint downloads to your user directory. Subsequent runs load it from the local cache. If you have a GPU, the model loads onto it automatically.
Run Prediction¶
estimator.predict(
input="sample_rgb.tif",
output="canopy_height_prediction.tif",
batch_size=4
)The batch_size parameter controls how many tiles are processed at once. Increase it (8, 16) if you have a larger GPU. The output is saved as a GeoTIFF with the same spatial reference as the input.
Visualize Results¶
Compare the input imagery, predicted canopy height, and ground truth side by side. The predicted map should show similar spatial patterns to the ground truth. Some underestimation is normal, but the overall pattern of tree locations and relative heights should match well.
You can also compute pixel-level differences by subtracting the prediction from the ground truth for more detailed validation.
Quick Prediction (One Function Call)¶
If you just want to run the prediction without manually initializing the model, use the convenience function:
from geoai.canopy import canopy_height_estimation
canopy_height_estimation(
input="sample_rgb.tif",
output="canopy_height_prediction.tif",
model_name="aerial_small"
)This handles model initialization, prediction, and cleanup in a single call. Use model_name="satellite_small" or "satellite_large" if your input is satellite imagery instead of aerial.
Tips¶
GPU monitoring: On Linux, use
nvidia-smiornvtopto monitor GPU usage during inference. On Windows, check the Task Manager.Batch size: Start with 4 and increase if your GPU has enough memory. Larger batch sizes speed up inference.
Data quality: The model works best with high-resolution imagery. Artifacts from mosaic boundaries in the input imagery are normal and do not significantly affect the canopy height estimation.
Validation: Compare predictions against ground truth LiDAR-derived canopy height models when available. Look at spatial patterns first, then compute pixel-level statistics if needed.
Resources¶
Try it out with your own aerial or satellite imagery. If you run into any issues, feel free to open an issue on GitHub.