""" 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}")