SAHI-Powered Reconnaissance System for Small Object Detection in Satellite Imagery
Identify small military vehicles (Tanks, Trucks, Cargo) in high-resolution satellite imagery using Slicing Aided Hyper Inference (SAHI) to solve the critical Small Object Problem.
| Challenge | Standard Approach | GeoIntel Solution |
|---|---|---|
| Satellite Image | 4000Γ4000 px | Process as tiles |
| Military Vehicle | ~20Γ20 px | Preserved at full resolution |
| YOLO Input | Resize to 640Γ640 | 512Γ512 overlapping tiles |
| Result | Objects destroyed | Objects detected |
Standard YOLO: 4000px β 640px = 84% resolution loss
20px tank β 3px blob (undetectable!)
GeoIntel + SAHI: 4000px β 64 tiles @ 512px each
20px tank stays 20px (detectable!)
# 1. Clone and setup
cd GeoIntel
pip install -r requirements.txt
# 2. Verify your dataset
python -m src.data_loader --data-dir data/raw
# 3. Run SAHI inference on a satellite image
python -m src.geointel_eye --image satellite.jpg --output final_map_with_tanks.jpgGeoIntel/
βββ config/
β βββ config.yaml # Tile sizes, overlap ratios, model params
βββ src/
β βββ data_loader.py # MVRSD dataset verification & loading
β βββ tiling_utils.py # Manual image slicing utilities
β βββ trainer.py # YOLOv8 fine-tuning pipeline
β βββ geointel_eye.py # π― Main SAHI inference engine
βββ notebooks/
β βββ Exploration.ipynb # Dataset visualization & analysis
βββ data/
β βββ raw/ # Place MVRSD dataset here
β β βββ images/
β β βββ labels/
β βββ processed/ # Train/val/test splits
β βββ outputs/ # Detection results
βββ models/ # Trained model weights
βββ requirements.txt
The heart of the system - src/geointel_eye.py - uses SAHI's get_sliced_prediction to detect small objects:
from src.geointel_eye import GeoIntelEye
# Initialize with YOLOv8-Medium
eye = GeoIntelEye(model_path="models/geointel_best.pt")
# Scan satellite imagery
result = eye.scan(
image_path="satellite_scan.jpg",
output_path="final_map_with_tanks.jpg",
compare_standard=True # See SAHI vs standard comparison
)
print(f"Detected {result.total_detections} military assets")
print(f"Tanks: {result.detections_by_class['tank']}")# config/config.yaml
tiling:
slice_height: 512 # Tile size (px)
slice_width: 512
overlap_height_ratio: 0.2 # 20% overlap
overlap_width_ratio: 0.2
inference:
sahi:
postprocess_type: "NMS" # Merge overlapping detections
postprocess_match_threshold: 0.5Military Vehicle Remote Sensing Dataset - Expected structure:
data/raw/
βββ images/
β βββ satellite_001.jpg
β βββ satellite_002.jpg
β βββ ...
βββ labels/ # YOLO format
βββ satellite_001.txt
βββ satellite_002.txt
βββ ...
YOLO Annotation Format:
# class_id x_center y_center width height (normalized 0-1)
0 0.5 0.5 0.02 0.02 # Tank at center, 2% of image
1 0.3 0.7 0.03 0.02 # Truck
2 0.8 0.2 0.04 0.03 # Cargo
Classes:
- 0: Tank
- 1: Truck
- 2: Cargo
- 3: Military Vehicle (generic)
# Prepare dataset splits
python -m src.data_loader --data-dir data/raw --prepare-splits --output-dir data/processed
# Train YOLOv8-Medium
python -m src.trainer --data data/processed/data.yaml --epochs 100 --batch-size 16
# Validate
python -m src.trainer --data data/processed/data.yaml --validate-only --model runs/train/best.ptpython -m src.geointel_eye --image satellite.jpg --output detected.jpgpython -m src.geointel_eye --batch-dir images/ --output-dir results/python -m src.geointel_eye --image satellite.jpg --compareOutput:
============================================================
SAHI vs STANDARD INFERENCE COMPARISON
============================================================
Metric SAHI Standard
------------------------------------------------------------
Total Detections 47 12
Inference Time (s) 8.32 0.45
tank 23 5
truck 18 6
cargo 6 1
------------------------------------------------------------
SAHI detected 35 MORE assets (291.7% improvement)
============================================================
- Visualization:
final_map_with_tanks.jpg- Annotated satellite image - GeoJSON:
scan_results.geojson- For GIS integration - JSON: Detection metadata with confidence scores
Edit config/config.yaml for your use case:
model:
architecture: "yolov8m" # YOLOv8 Medium
confidence_threshold: 0.25
iou_threshold: 0.45
tiling:
slice_height: 512 # Adjust for your imagery
slice_width: 512
overlap_height_ratio: 0.2 # Increase for dense scenesclass GeoIntelEye:
def scan(
image_path: str,
output_path: str = None,
export_geojson: bool = True,
visualize: bool = True,
compare_standard: bool = False
) -> ScanResult
def scan_standard(image_path: str) -> ScanResult
def batch_scan(image_dir: str, output_dir: str = None) -> List[ScanResult]@dataclass
class ScanResult:
image_path: str
image_size: Tuple[int, int]
total_detections: int
detections_by_class: Dict[str, int]
assets: List[MilitaryAsset]
inference_time_seconds: float
method: str # "sahi_sliced" or "standard"
tile_info: Dict # tile_size, overlap, grid dimensionsSAHI (Slicing Aided Hyper Inference) by Fatih Akyon:
- Paper: arxiv.org/abs/2202.06934
- GitHub: github.com/obss/sahi
Key Insight: Instead of downscaling large images (destroying small objects), process overlapping tiles at full resolution and merge predictions.
MIT License
GeoIntel - "See what others miss"

