Instance Segmentation
May 5, 2026 ยท View on GitHub
Instance Segmentation
Introduction
Learning Objectives
Instance Segmentation vs. Semantic Segmentation
Mask R-CNN Architecture
Backbone Encoder
Region Proposal Network
Detection Head
Mask Head
RoI Align: Preserving Spatial Precision
The Complete Pipeline
Downloading the FTW Dataset
from pathlib import Path
import geopandas as gpd
import geoai
geoai.download_ftw(countries=["luxembourg"], output_dir="ftw_data")
Exploring the Dataset
country_dir = Path("ftw_data") / "luxembourg"
chips_gdf = gpd.read_parquet(country_dir / "chips_luxembourg.parquet")
print(f"Total chips: {len(chips_gdf)}")
print(f"\nSplit distribution:")
print(chips_gdf["split"].value_counts())
geoai.view_vector_interactive(chips_gdf, column="split")
geoai.display_ftw_samples("ftw_data", country="luxembourg", num_samples=4)
Preparing Training Data
data = geoai.prepare_ftw("ftw_data", country="luxembourg")
data
geoai.display_training_tiles(
output_dir="field_boundaries",
num_tiles=4,
figsize=(12, 6),
cmap="tab20",
)
Training a Mask R-CNN Model
geoai.train_instance_segmentation_model(
images_dir=data["images_dir"],
labels_dir=data["labels_dir"],
output_dir="field_boundaries/models",
num_classes=2,
num_channels=4,
batch_size=4,
num_epochs=20,
learning_rate=0.005,
val_split=0.2,
instance_labels=True,
visualize=True,
verbose=True,
)
geoai.plot_performance_metrics(
history_path="field_boundaries/models/training_history.pth",
figsize=(15, 5),
verbose=True,
)
Running Inference
test_images = sorted(Path(data["test_dir"]).glob("*.tif"))
test_image_path = str(test_images[0])
masks_path = "field_boundary_prediction.tif"
model_path = "field_boundaries/models/best_model.pth"
result = geoai.instance_segmentation(
input_path=test_image_path,
output_path=masks_path,
model_path=model_path,
num_classes=2,
num_channels=4,
window_size=256,
overlap=128,
confidence_threshold=0.5,
batch_size=4,
vectorize=True,
class_names=["background", "building"],
)
result
Visualizing Raw Predictions
geoai.view_raster(
result["instance"],
nodata=0,
cmap="tab20",
basemap=test_image_path,
backend="ipyleaflet",
)
geoai.view_raster(
result["class_label"],
nodata=0,
cmap="binary",
basemap=test_image_path,
backend="ipyleaflet",
)
geoai.view_raster(
result["score"], nodata=0, basemap=test_image_path, backend="ipyleaflet"
)
geoai.view_vector_interactive(result["vector"], tiles=test_image_path, column="score")
Post-Processing Predictions
cleaned_masks_path = "field_boundary_prediction_cleaned.tif"
geoai.clean_instance_mask(
result["instance"], cleaned_masks_path, min_area=100, max_hole_area=100
)
geoai.view_raster(
cleaned_masks_path,
nodata=0,
cmap="tab20",
basemap=test_image_path,
backend="ipyleaflet",
)
Vectorizing Predictions
output_vector_path = "field_boundary_prediction.geojson"
gdf = geoai.raster_to_vector(cleaned_masks_path, output_vector_path)
Comparing Predictions with Imagery
geoai.create_split_map(
left_layer=gdf,
right_layer=test_image_path,
left_args={"style": {"color": "red", "fillOpacity": 0.2}},
basemap=test_image_path,
)
Extracting Geometric Properties
gdf_props = geoai.add_geometric_properties(gdf, area_unit="ha", length_unit="m")
gdf_props.head()
gdf_props.describe()
Visualizing Fields by Property
geoai.view_vector_interactive(gdf_props, column="area_ha", tiles=test_image_path)
geoai.view_vector_interactive(gdf_props, column="elongation", tiles=test_image_path)
Batch Processing
geoai.instance_segmentation_batch(
input_dir=data["test_dir"],
output_dir="field_boundaries/predictions",
model_path=model_path,
num_classes=2,
num_channels=4,
window_size=256,
overlap=128,
confidence_threshold=0.5,
batch_size=4,
)
Key Takeaways
Exercises
Exercise 1: Confidence Threshold Analysis
Exercise 2: Multi-Country Comparison
Exercise 3: Field Size Classification
Exercise 4: Post-Processing Parameter Sensitivity
Exercise 5: End-to-End Field Boundary Pipeline