"""Quick test: run 12-class segmentation on 10 diverse images and save results.""" from __future__ import annotations import sys import shutil from pathlib import Path import torch import numpy as np from PIL import Image # Ensure project root is on path. ROOT = Path(__file__).resolve().parent sys.path.insert(0, str(ROOT)) sys.path.insert(0, str(ROOT / "src" / "nn" / "segearth_ov3")) from src.conf.config_loader import load_all_configs from src.augmentor.models import load_segmentation_model from src.augmentor.inference import infer_segmentation_batch from src.augmentor.io_utils import save_segmentation INPUT_ROOT = Path("/mnt/data1tb/cvgl_datasets/UAV-GeoLoc") # 10 diverse test images: satellite (DB) — urban + terrain TEST_IMAGES = [ # Urban (satellite) "Country/German/Munich/Ludwigs/DB/img/crop_12_4.png", "Country/French/Paris/LeMarais/DB/img/crop_12_4.png", "Country/Italy/Venice/SanMarco/DB/img/crop_12_4.png", "Country/USA/NewYork/Manhattan/DB/img/crop_12_4.png", "Country/Australia/Sydney/SydneyCBD/DB/img/crop_12_4.png", "Country/Korea/Busan/Gwangalli/DB/img/crop_12_4.png", # Terrain (satellite) "Terrain/Desert/GobiDesert/DB/img/crop_50_33.png", "Terrain/Glacier/AthabascaGlacier/DB/img/crop_12_4.png", "Terrain/Volcano/KilaueaVolcano/DB/img/crop_12_4.png", "Terrain/Danxia/GrandCanyon/DB/img/crop_50_33.png", ] OUTPUT_DIR = ROOT / "test_seg_output" def main(): # Load configs (reads all .gin files) configs = load_all_configs(str(ROOT / "in" / "config_files") + "/") pipeline_conf = configs["pipeline"] hw_conf = configs["hardware"] models_conf = configs["models"] input_conf = configs["input"] seg_conf = configs["seg"] print(f"Prompts ({len(seg_conf.prompts)}): {seg_conf.prompts}") print(f"Threshold: {seg_conf.threshold}") print(f"Resolution: {seg_conf.default_resolution}") device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"Device: {device}") # Load model print("\nLoading SegEarth-OV3...") model, seg_config = load_segmentation_model(models_conf, hw_conf, seg_conf, device) num_classes = seg_config.get("num_classes", 150) print(f"Model loaded. Type: {seg_config['type']}, num_classes: {num_classes}") # Prepare output dir OUTPUT_DIR.mkdir(exist_ok=True) # Process each image for i, rel_path in enumerate(TEST_IMAGES): img_path = INPUT_ROOT / rel_path if not img_path.exists(): print(f"[{i+1}/10] SKIP (not found): {rel_path}") continue print(f"\n[{i+1}/10] Processing: {rel_path}") # Load and preprocess pil_img = Image.open(img_path).convert("RGB") img_np = np.array(pil_img).astype(np.float32) / 255.0 img_tensor = torch.from_numpy(img_np).permute(2, 0, 1).unsqueeze(0) # [1, 3, H, W] # Infer seg_ids = infer_segmentation_batch(model, seg_config, img_tensor, device) # seg_ids: [1, 1, H, W] uint8 # Save original + segmentation side by side stem = img_path.stem tag = rel_path.split("/")[0] # Country or Terrain if tag == "Country": tag = rel_path.split("/")[2] # city name elif tag == "Terrain": tag = rel_path.split("/")[1] # terrain type out_stem = f"{i:02d}_{tag}_{stem}" # Save original for reference pil_img.save(OUTPUT_DIR / f"{out_stem}_orig.png") # Save segmentation vis save_segmentation( seg_ids[0], OUTPUT_DIR, out_stem, save_npy=False, save_vis=True, num_classes=num_classes, ) unique_classes = torch.unique(seg_ids[0]).tolist() class_names = [seg_conf.prompts[c] for c in unique_classes if c < len(seg_conf.prompts)] print(f" -> Classes found: {class_names}") print(f"\nDone! Results saved to: {OUTPUT_DIR}") if __name__ == "__main__": main()