aee0f09db8
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
197 lines
6.3 KiB
Python
197 lines
6.3 KiB
Python
"""
|
|
RIVP Pilot 1 - Road Change Detection
|
|
Analyserar förändringar på vägar med satellitbilder
|
|
"""
|
|
import json
|
|
import os
|
|
from datetime import datetime
|
|
|
|
class RoadChangeDetector:
|
|
"""Detekterar förändringar på vägar med Sentinel-2 bilder"""
|
|
|
|
def __init__(self, road_name, bbox):
|
|
self.road_name = road_name
|
|
self.bbox = bbox
|
|
self.observations = []
|
|
|
|
def analyze_images(self, image_before, image_after):
|
|
"""
|
|
Jämför två satellitbilder och identifierar förändringar
|
|
|
|
I verkligheten: NDVI-diff, spektral analys, ML-modell
|
|
Här: Simulerad analys baserad på kända mönster
|
|
"""
|
|
|
|
changes = []
|
|
|
|
# Simulera detektion baserat på datum och vägtyp
|
|
# I verkligheten: pixel-för-pixel jämförelse
|
|
|
|
if self.road_name == "E4":
|
|
# E4 är en hårt trafikerad motorväg
|
|
changes = [
|
|
{
|
|
"type": "pothole",
|
|
"location": {"lat": 59.85, "lon": 17.65},
|
|
"confidence": 0.82,
|
|
"size_m2": 12,
|
|
"detected_date": image_after["date"],
|
|
"severity": "medium"
|
|
},
|
|
{
|
|
"type": "construction",
|
|
"location": {"lat": 59.88, "lon": 17.72},
|
|
"confidence": 0.95,
|
|
"size_m2": 2500,
|
|
"detected_date": image_after["date"],
|
|
"severity": "high"
|
|
}
|
|
]
|
|
elif self.road_name == "Länsväg 272":
|
|
# Mindre väg, mer variation
|
|
changes = [
|
|
{
|
|
"type": "surface_damage",
|
|
"location": {"lat": 59.92, "lon": 17.55},
|
|
"confidence": 0.78,
|
|
"size_m2": 45,
|
|
"detected_date": image_after["date"],
|
|
"severity": "low"
|
|
}
|
|
]
|
|
|
|
return changes
|
|
|
|
def calculate_ndvi(self, image):
|
|
"""Beräkna NDVI (Normaliserad Differens Vegetations Index)"""
|
|
# I verkligheten: (NIR - Red) / (NIR + Red)
|
|
# Här: Simulerat värde
|
|
return 0.45
|
|
|
|
def detect_road_surface_changes(self, before, after):
|
|
"""Detektera förändringar i vägytan"""
|
|
|
|
# I verkligheten:
|
|
# 1. Extrahera vägmask från bild
|
|
# 2. Jämför spektral signatur före/efter
|
|
# 3. Klassificera förändringstyp
|
|
|
|
changes = self.analyze_images(before, after)
|
|
|
|
# Beräkna konfidens
|
|
for change in changes:
|
|
# Konfidens baserad på:
|
|
# - Bildkvalitet (molnighet)
|
|
# - Förändringsstorlek
|
|
# - Spektral tydlighet
|
|
|
|
base_confidence = change["confidence"]
|
|
|
|
# Justera för molnighet
|
|
cloud_factor = 1.0 - (after.get("cloud_cover", 0) / 100)
|
|
|
|
# Justera för storlek (större = lättare att se)
|
|
size_factor = min(1.0, change["size_m2"] / 100)
|
|
|
|
change["adjusted_confidence"] = base_confidence * cloud_factor * (0.5 + 0.5 * size_factor)
|
|
|
|
return changes
|
|
|
|
class RIVPPilot1:
|
|
"""RIVP Pilot 1 - Infrastructure Monitoring"""
|
|
|
|
def __init__(self):
|
|
self.roads = [
|
|
{
|
|
"name": "E4",
|
|
"bbox": "17.5,59.8,17.8,60.0",
|
|
"length_km": 45,
|
|
"type": "motorway"
|
|
},
|
|
{
|
|
"name": "Länsväg 272",
|
|
"bbox": "17.4,59.9,17.7,60.1",
|
|
"length_km": 23,
|
|
"type": "county_road"
|
|
}
|
|
]
|
|
|
|
self.detector = RoadChangeDetector("", "")
|
|
|
|
def run_analysis(self):
|
|
"""Kör komplett analys för alla vägar"""
|
|
|
|
results = {
|
|
"pilot": "RIVP-1",
|
|
"date": datetime.now().isoformat(),
|
|
"roads_analyzed": len(self.roads),
|
|
"total_changes": 0,
|
|
"changes_by_type": {},
|
|
"roads": []
|
|
}
|
|
|
|
for road in self.roads:
|
|
print(f"\nAnalyserar: {road['name']}")
|
|
print(f" Typ: {road['type']}")
|
|
print(f" Längd: {road['length_km']} km")
|
|
|
|
# Simulera bilder före/efter
|
|
image_before = {
|
|
"date": "2026-06-01",
|
|
"cloud_cover": 10
|
|
}
|
|
image_after = {
|
|
"date": "2026-07-01",
|
|
"cloud_cover": 15
|
|
}
|
|
|
|
# Detektera förändringar
|
|
self.detector.road_name = road["name"]
|
|
self.detector.bbox = road["bbox"]
|
|
|
|
changes = self.detector.detect_road_surface_changes(image_before, image_after)
|
|
|
|
road_result = {
|
|
"name": road["name"],
|
|
"changes_detected": len(changes),
|
|
"changes": changes
|
|
}
|
|
|
|
results["roads"].append(road_result)
|
|
results["total_changes"] += len(changes)
|
|
|
|
# Räkna per typ
|
|
for change in changes:
|
|
change_type = change["type"]
|
|
if change_type not in results["changes_by_type"]:
|
|
results["changes_by_type"][change_type] = 0
|
|
results["changes_by_type"][change_type] += 1
|
|
|
|
print(f" → {change_type}: {change['severity']} (confidence: {change['adjusted_confidence']:.2f})")
|
|
|
|
return results
|
|
|
|
if __name__ == "__main__":
|
|
print("=" * 60)
|
|
print("RIVP Pilot 1 - Road Change Detection")
|
|
print("=" * 60)
|
|
|
|
pilot = RIVPPilot1()
|
|
results = pilot.run_analysis()
|
|
|
|
print("\n" + "=" * 60)
|
|
print("SAMMANFATTNING")
|
|
print("=" * 60)
|
|
print(f"Vägar analyserade: {results['roads_analyzed']}")
|
|
print(f"Totala förändringar: {results['total_changes']}")
|
|
print(f"\nFörändringar per typ:")
|
|
for change_type, count in results["changes_by_type"].items():
|
|
print(f" {change_type}: {count}")
|
|
|
|
# Spara resultat
|
|
output_file = "/home/bernt/.openclaw/workspace/rivp-pilot-1/results.json"
|
|
with open(output_file, "w") as f:
|
|
json.dump(results, f, indent=2)
|
|
|
|
print(f"\nResultat sparade: {output_file}")
|