Kinetic Analysis & Regional Enforcement Network
Multi-modal probabilistic building change detection — a grdl-runtime workflow implementation.
KAREN detects minor building perimeter and roof modifications in high-resolution (0.3m) overhead imagery using a two-stage hybrid approach:
Stage A (Stateless) — GRDL-orchestrated ML/CV detection pipeline:
- Ingest temporal GeoTIFFs via
grdl.IO - Coregister image pairs via
grdl.coregistration - Extract building footprints using SpaceNet ML detectors (SN2/SN4/SN7)
- Refine with CV post-processing: shadow masking, edge alignment, morphological cleanup
- Output
DetectionSet(GeoJSON) with delta-polygons and confidence scores
Stage B (Stateful) — SQLite-backed persistence engine:
- Match detections to tracked buildings via spatial IoU
- Update confidence matrix with decay/confirmation logic
- Classify changes (perimeter vs. roof) and escalate confirmed violations
conda activate starlight
# Install karen in editable mode with dev dependencies
pip install -e ".[dev]"
# Install PyTorch (required for SpaceNet detectors)
pip install torch torchvision
# Optional: download SpaceNet test data and pretrained weights
pip install -e ".[spacenet]"
python scripts/download_weights.py
python scripts/download_spacenet_data.pyfrom grdl_rt import Workflow
from grdl.IO import GeoTIFFReader
from karen.processors.preprocessing import ImageNormalizer
from karen.detectors.sn4_offnadir import SN4OffNadirDetector
wf = (
Workflow("Footprint Extract", version="1.0.0", modalities=["EO"])
.reader(GeoTIFFReader)
.chip("full")
.step(ImageNormalizer, method="percentile")
.step(SN4OffNadirDetector, confidence_threshold=0.5)
)
result = wf.execute("image.tif")from karen.persistence.database import KarenDatabase
from karen.persistence.confidence import ConfidenceMatrix
from karen.persistence.ingest import DetectionSetIngestor
from karen.config import KarenConfig
config = KarenConfig()
db = KarenDatabase(config)
confidence = ConfidenceMatrix(config, db)
ingestor = DetectionSetIngestor(config, db, confidence)
# Run Stage A workflow on each temporal image...
detection_set = wf.execute("image_t2.tif")
# Stage B: ingest into persistence engine
ingestor.ingest(detection_set, image_date="2026-02-12", image_source="image_t2.tif")See architecture.md for the full technical architecture including:
- Package structure and module layout
- Processor and detector hierarchy
- SpaceNet model integration details
- SQLite persistence schema
- Data flow diagrams
- Workflow YAML definitions
- Configuration reference
grdl (primitives) --> grdl-runtime (framework) --> karen (workflows)
^
grdl-imagej (CV filters)
- grdl provides image processing primitives, I/O, coregistration, geolocation
- grdl-runtime provides the workflow engine, metadata injection, processor discovery
- grdl-imagej provides edge detection, morphological operations, filters
- karen defines domain-specific processors and workflows for building change detection
conda activate starlight
# Run tests
pytest tests/ -x -q
# Lint
ruff check karen/ tests/
# Type check
mypy karen/SpaceNet data and model weights are cached at C:\tmp\karen\:
C:\tmp\karen\
├── data/
│ ├── sn2/ # SpaceNet 2 test imagery
│ ├── sn4/ # SpaceNet 4 summary data
│ └── sn7/ # SpaceNet 7 subset
└── weights/
├── sn4/ # Pretrained SN4 DenseNet161 weights
└── sn7/ # Pretrained SN7 HRNet weights
MIT License. See LICENSE for details.