Rilevamento dei bordi

Il rilevamento dei bordi predice quanto è probabile che ogni pixel si trovi sul contorno di un oggetto. LibreYOLO lo espone come task edge, che restituisce una mappa densa di probabilità sul canvas dell'immagine originale invece di un insieme di segmenti.

Definizione

Il task edge predice una probabilità per pixel a partire da una singola immagine RGB: 0 significa non-bordo e 1 significa bordo. La mappa resta continua, quindi la scelta della soglia che la trasforma in un'immagine binaria di contorni è lasciata a chi chiama, e la soglia giusta dipende dal dataset e dall'uso a valle.

Una predizione riempie result.edges, un payload EdgeMap che contiene un array float32 (H, W) in [0, 1] sul canvas dell'immagine originale. .array restituisce quella mappa come NumPy e .binary(threshold) restituisce una maschera booleana. result.boxes resta vuoto, quindi conf, iou e max_det non hanno effetto. Results.plot() copre questo task e disegna la mappa direttamente.

Modelli

Tre famiglie servono edge.

DexiNed, la Dense Extreme Inception Network, fonde diverse uscite laterali in un'unica mappa di probabilità e gira a una risoluzione nativa di 352 px.

TEED, il Tiny and Efficient Edge Detector, è una rete piccola alla stessa risoluzione nativa di 352 px, con uno stride di downsample di 4 contro i 16 di DexiNed, quindi accetta più valori di imgsz.

LibreMODUS produce bordi in stile Canny come uno dei target di un modello any-to-any. Richiede l'extra modus e un tuo account Hugging Face autenticato, e non offre né val()export(), quindi non compare nelle sezioni di validazione ed esportazione qui sotto.

Predizione

LibreYOLO non pubblica nessun checkpoint edge. I pesi DexiNed e TEED rilasciati ufficialmente sono addestrati su BIPED, i cui termini pubblicati del dataset limitano l'uso a scopi non commerciali, quindi LibreYOLO non ne fa il mirror. Converti un checkpoint che sei autorizzato a usare, poi carica il file convertito indicandone il percorso:

bash
python weights/convert_dexined_weights.py upstream.pth weights/LibreDexiNedb-edge.pt --verify

Predire una mappa di bordi
from libreyolo import LibreYOLO, SAMPLE_IMAGE # LibreYOLO non include nessun checkpoint edge; convertine uno prima (sotto).model = LibreYOLO("weights/LibreDexiNedb-edge.pt")result = model(SAMPLE_IMAGE, save=True) edges = result.edgesprint(edges.array.shape)          # (H, W) float32 in [0, 1]print(edges.binary(0.5).sum())    # conteggio dei pixel di bordo a 0.5
Scegliere la propria soglia
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreDexiNedb-edge.pt")result = model(SAMPLE_IMAGE) # La mappa continua viene conservata perché la soglia resti una tua scelta.for t in (0.3, 0.5, 0.7):    print(t, int(result.edges.binary(t).sum()))
Salvare la visualizzazione
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreDexiNedb-edge.pt")result = model(SAMPLE_IMAGE) # plot() disegna la mappa; è definito per i risultati edge e normal.result.plot().save("edges.png")

Il nome del file deve portare il suffisso di task -edge perché il loader lo riconosca. imgsz deve essere divisibile per lo stride di downsample della rete, e quando non lo è LibreYOLO solleva un errore chiaro che indica il divisore. Vedi predizione per sorgenti, streaming e gestione dei risultati.

Formato del dataset

La validazione edge abbina ogni immagine RGB a una mappa a canale singolo con lo stesso nome base e la stessa risoluzione, più una maschera di validità opzionale.

dataset/
  data.yaml
  images/
    val/scene.jpg
  edges/
    val/scene.png
  masks/
    val/scene.png
yaml
path: dataset
train: images/train
val: images/val
edges_dir: edges
masks_dir: masks
nc: 1
names: {0: edge}

Il target è un PNG o TIF a canale singolo, non una visualizzazione RGB. Le mappe intere vengono divise per il massimo del loro dtype; le mappe float devono già essere finite e in [0, 1]. I pixel della maschera contano come validi quando sono diversi da zero, e i pixel di padding non contribuiscono mai a una metrica. edge_invert: true copre le sorgenti che memorizzano bordi neri su bianco. Vedi formati dei dataset per il contratto completo.

Addestramento

Nessuna famiglia edge in LibreYOLO ha un'implementazione dell'addestramento: train() solleva NotImplementedError su tutte e tre. La pagina di ogni modello indica lo script di conversione che trasforma un checkpoint addestrato altrove in uno che LibreYOLO può caricare.

Validazione

val() riporta le F-measure in stile BSDS. Le predizioni continue vengono prima assottigliate con una non-maximum suppression del gradiente a quattro direzioni, poi i pixel di bordo predetti e quelli del ground truth vengono abbinati uno a uno entro una tolleranza di distanza.

Validare e leggere le chiavi delle metriche
from libreyolo import LibreYOLO model = LibreYOLO("weights/LibreDexiNedb-edge.pt")metrics = model.val(data="my-dataset.yaml", imgsz=352) print(metrics["metrics/ODS"])              # fitnessprint(metrics["metrics/OIS"])print(metrics["metrics/best_threshold"])
Cambiare lo sweep e la tolleranza di corrispondenza
from libreyolo import LibreYOLO model = LibreYOLO("weights/LibreDexiNedb-edge.pt")metrics = model.val(    data="my-dataset.yaml",    imgsz=352,    edge_thresholds=(0.1, 0.2, 0.3, 0.4, 0.5),    edge_max_dist=0.0075,) print(metrics["metrics/ODS"], metrics["metrics/best_threshold"])

metrics/ODS è la F-measure optimal-dataset-scale: i conteggi delle corrispondenze vengono aggregati su tutto il dataset a ogni soglia, e viene riportata la migliore di quelle F-measure aggregate. È anche fitness, il numero che legge la selezione del miglior checkpoint. metrics/OIS è la F-measure optimal-image-scale, la media sulle immagini della migliore F-measure di ciascuna immagine, quindi lascia che ogni immagine scelga la propria soglia. metrics/best_threshold è la singola soglia che ha prodotto ODS, ed è quella da riusare in edges.binary() durante l'inferenza.

Due argomenti controllano lo sweep. edge_thresholds è l'insieme delle soglie provate, che per default va da 0.01 a 0.99 a passi di un centesimo. edge_max_dist è la tolleranza di corrispondenza espressa come frazione della diagonale dell'immagine, con default 0.0075; una coppia più distante di così non è una corrispondenza.

Esportazione

Un modello edge esportato si ricarica tramite LibreYOLO() in base al suffisso del file, quindi un file .onnx si comporta come un checkpoint e restituisce gli stessi Results.

Esportare
from libreyolo import LibreYOLO model = LibreYOLO("weights/LibreDexiNedb-edge.pt")model.export(format="onnx", imgsz=352)
Eseguire il file esportato
from libreyolo import LibreYOLO, SAMPLE_IMAGE # La factory instrada in base al suffisso del file, così un artefatto esportato# si carica come un checkpoint qualsiasi e restituisce lo stesso oggetto Results.model = LibreYOLO("weights/LibreDexiNedb-edge.onnx")result = model(SAMPLE_IMAGE) print(result.edges.array.shape)

L'esportazione edge usa un contratto di runtime a risoluzione fissa e batch 1: dynamic e un batch diverso da 1 vengono rifiutati, e il grafo esportato emette un'unica mappa di probabilità fusa. La copertura per formato è nelle pagine DexiNed e TEED e nella matrice completa di esportazione. Esportazione elenca gli argomenti che ogni formato accetta.

Verificato con LibreYOLO v1.5.0.