File size: 3,350 Bytes
5373059
 
 
 
 
 
 
 
 
c1f2fb8
5373059
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e22aa39
4695c60
e22aa39
 
 
 
 
 
4695c60
 
 
 
 
 
 
 
 
 
 
 
e22aa39
 
4695c60
5373059
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"""
path_utils.py
-------------
Centralised path handling for the Pothole Detection Streamlit app.
"""

from pathlib import Path

# ── Root of the project ────────────────────────────────────────────────────────
ROOT = Path(__file__).resolve().parent.parent

def get_available_models() -> dict:
    """
    Find and categorize trained weights in the project's local 'models' directory.
    
    Returns
    -------
    dict : { "πŸ› οΈ Crack Model (run_name)": Path, "πŸ•³οΈ Pothole Model (run_name)": Path }
    """
    weights_parent = ROOT / "models"
    models = {}
    
    if not weights_parent.exists():
        return models

    for run_dir in weights_parent.iterdir():
        if run_dir.is_dir():
            best_pt = run_dir / "best.pt"
            if best_pt.exists():
                name = run_dir.name
                if "crack" in name.lower():
                    label = f"πŸ› οΈ Crack Model ({name})"
                else:
                    label = f"πŸ•³οΈ Pothole Model ({name})"
                models[label] = best_pt
    return models

def get_model_path(variant: str) -> Path:
    # This is now just returning the Path directly since get_available_models returns Paths
    return Path(variant)

def get_training_artifact(model_path: Path, filename: str) -> Path:
    """Return the Path to a specific training plot/artifact, searching common synonyms."""
    base_dir = model_path.parent
    
    # Define common naming synonyms across YOLO versions
    synonyms = {
        "PR_curve.png": ["PR_curve.png", "BoxPR_curve.png"],
        "results.png": ["results.png"],
        "confusion_matrix.png": ["confusion_matrix_normalized.png", "confusion_matrix.png"],
        "val_batch0_pred.jpg": ["val_batch0_pred.jpg"],
        "val_batch0_labels.jpg": ["val_batch0_labels.jpg"]
    }
    
    if filename in synonyms:
        for syn in synonyms[filename]:
            p = base_dir / syn
            if p.exists(): return p
            
    # Fallback to exact filename
    return base_dir / filename

def get_sample_path(filename: str, is_video: bool = False, is_crack: bool = False) -> Path:
    """Find a sample file, prioritizing cloud-accessible 'assets/' folder."""
    if is_video:
        sub = "videos"
    elif is_crack:
        sub = "images/cracks"
    else:
        sub = "images"
    
    # Priority 1: Cloud Assets (included in Git)
    p = ROOT / "assets" / "samples" / sub / filename
    if p.exists(): return p
    
    # Priority 2: Local Data Folders (Git ignored)
    if is_video:
        p = ROOT / "data" / "samples" / "videos" / filename
    else:
        p = ROOT / "data" / "combined" / "train" / "images" / filename
        if not p.exists():
            p = ROOT / "data" / "combined" / "test" / "images" / filename
        if not p.exists() and is_crack:
            p = ROOT / "data" / "bc_projekt" / "test" / "images" / filename
            
    return p

def model_info(model_path: Path) -> dict:
    # Static info based on model size (deduced from filename or parent)
    name = str(model_path).lower()
    if "yolo11s" in name:
        return {"name": "YOLO11s", "map50": "74.1%", "speed_ms": "~8ms"}
    return {"name": "YOLO11n", "map50": "66.7%", "speed_ms": "~4ms"}