Autoplotter With Road Estimator Crack Info
| Platform | Strength | Typical Stack |
|----------|----------|---------------|
| Apache Airflow | Mature DAG visualisation, retry policies. | DockerOperator → autoplotter → road_estimator. |
| Prefect Cloud | Serverless, easy Python‑first syntax. | @task decorators, async execution on Fargate. |
| AWS Step Functions | Tight integration with S3, Lambda, Batch. | Lambda for vectorization, Batch for crack inference. |
| Kubernetes (Kubeflow Pipelines) | Scalable GPU jobs, experiment tracking. | Pods: autoplotter-job, estimator-job. |
Best practice: Keep the road vector as a single source of truth (e.g., a PostGIS table with a primary key). All downstream crack‑maps reference that key; when the road network is refreshed, you can simply re‑run the crack estimator without re‑segmenting.
| Metric | How to compute | Target (typical) |
|--------|----------------|------------------|
| Precision / Recall (crack detection) | Compare model output to a hand‑annotated validation set (IoU ≥ 0.5). | Precision ≥ 0.90, Recall ≥ 0.85 |
| Geometric error (centroid distance) | Distance between estimated crack line and ground‑truth line. | ≤ 0.15 m (for UAV 0.05 m/px) |
| Attribute consistency | Verify that every crack polygon has a matching road_id. | 100 % |
| Temporal stability | Run on two images captured a month apart; < 5 % change on unchanged sections. | ≤ 5 % false change |
| Processing time | Tile‑level runtime (seconds) × number of tiles. | ≤ 30 s per 1 km² tile (GPU) | autoplotter with road estimator crack
Automated QC dashboard (e.g., Streamlit or Grafana) can surface:
from cracknet import DeepCrack
model = DeepCrack("weights/deepcrack_resnet.pth")
model.eval()
def infer_crack(chip):
prob = model.predict(chip) # (H, W) probability map
binary = prob > 0.5 # threshold
# Morphological clean‑up
cleaned = binary_opening(binary, disk(2))
# Vectorize cracks (thin → skeleton → polygonize)
cracks = rasterio.features.shapes(cleaned.astype('uint8'), transform=transform)
# Convert to GeoDataFrame
gdf = gpd.GeoDataFrame([
"road_id": rid, "geometry": shape, "prob": prob.mean()
for shape, value in cracks if value == 1
], crs="EPSG:3857")
return gdf
Key post‑processing steps
| Step | Reason |
|------|--------|
| Morphological opening/closing | Removes spurious speckles, bridges tiny gaps (< 0.1 m). |
| Skeletonization + line‑simplification | Produces clean polylines suitable for GIS. |
| Confidence‑weighted filtering | Keeps only segments where prob > 0.7 or where the model’s uncertainty (Monte‑Carlo dropout) is low. |
| Spatial join to road vector | Ensures each crack inherits road_id, lane_count, surface_type. |
| Component | Core Function | Typical Input | Typical Output | |-----------|---------------|---------------|----------------| | Autoplotter | High‑throughput raster → vector conversion, geometric cleaning, and map‑ready rendering. | Orthophotos, LiDAR‐derived DEMs, satellite imagery (GeoTIFF, Cloud‑Optimized GeoTIFF). | GeoJSON / Shapefile road network, lane centrelines, shoulder polygons, attribute tables. | | Road‑Estimator | Machine‑learning based road‑surface condition estimator (roughness, texture, and especially crack detection). | Aligned road‑centerline vectors + high‑resolution surface imagery (e.g., 0.05 m/pixel UAV orthophotos). | Per‑segment crack probability, crack geometry (polylines), severity scores, confidence intervals. | | Integration Layer | Orchestrates data flow, spatial joins, and quality‑control (QC) reporting. | Outputs from the two modules above. | Final “crack‑map” product ready for GIS, asset‑management, or autonomous‑vehicle (AV) simulation. | | Platform | Strength | Typical Stack |
Bottom line: By feeding the clean, topology‑aware road vectors from Autoplotter into a Road‑Estimator model, you get pixel‑accurate crack geometries that are automatically linked to the underlying road network. The result is a single, up‑to‑date geospatial dataset that can feed maintenance planning, budgeting, and AI‑driven driving‑simulation pipelines.
import rasterio as rio
import torch
from autoplotter import RoadVectorizer, Preprocessor, SegModel
# 1️⃣ Load a COG tile (256 Mpx max per job)
with rio.open("s3://my-bucket/ortho/2025-06/region_01.tif") as src:
img = src.read(window=rio.windows.Window(col_off=0, row_off=0, width=1024, height=1024))
transform = src.window_transform(rio.windows.Window(0,0,1024,1024))
# 2️⃣ Pre‑process (normalize + DEM flatten)
proc = Preprocessor()
img_norm = proc.normalize(img)
# 3️⃣ Predict road mask
model = SegModel("weights/deeplabv3_asphalt.pth")
with torch.no_grad():
mask = model.predict(img_norm) # shape (H, W), binary road mask
# 4️⃣ Vectorize
vectorizer = RoadVectorizer(mask, transform)
gdf = vectorizer.extract_vectors(min_length=2.0, simplify_tol=0.5)
# 5️⃣ Save
gdf.to_file("output/road_vectors.gpkg", driver="GPKG")
Tip: Deploy the above as a AWS Lambda or Google Cloud Function triggered by new COG uploads. The function returns a signed URL to the generated vector file, enabling downstream pipelines to start immediately. Best practice: Keep the road vector as a