Rilevamento di punti

Il rilevamento di punti restituisce una posizione x, y per oggetto invece di un bounding box. LibreYOLO lo espone come task point, e una predizione porta una riga con x, y, classe e confidenza per ogni oggetto.

Definizione

Il task point localizza ogni oggetto con una singola coordinata x, y e una classe, senza larghezza, altezza o maschera. Poiché una predizione è un elenco piatto di oggetti, il numero di righe è il numero di oggetti, ed è questo che ne fa il task di conteggio.

Una predizione riempie result.points, un payload Points che incapsula un array (N, 4) di righe x, y, class, confidence in pixel dell'immagine originale. .xy restituisce le coordinate, .xyn le stesse coordinate divise per la dimensione dell'immagine, .cls gli indici di classe e .conf i punteggi; len() restituisce il numero di punti. result.boxes resta vuoto, quindi iou e max_det non hanno nulla su cui agire.

Modelli

Tre famiglie coprono point, e non sono intercambiabili.

FOMO è l'opzione a vocabolario fisso: un classificatore a griglia che etichetta ogni cella di una griglia a bassa risoluzione come sfondo o come centro di un oggetto. È l'unica famiglia point che LibreYOLO può addestrare, e l'unica che si esporta.

LocateAnything accetta testo invece di un indice di classe, quindi il vocabolario è qualunque frase tu scriva. Richiede l'extra vlm, si costruisce come LibreLocateAnything invece che tramite la factory LibreYOLO(), e i suoi pesi sono limitati all'uso non commerciale. I termini esatti, e le altre due licenze che il checkpoint compone, sono sulla sua pagina.

SenseNova-Vision arriva a point attraverso lo stesso checkpoint a generazione guidata da prompt che usa per altri sei task, caricato con LibreVLM("sensenova-vision", task="point"). Richiede l'extra sensenova, e ogni predizione è un passaggio di generazione su un modello da 7B, quindi aspettati una latenza per immagine nettamente più alta rispetto a un rilevatore dedicato. I suoi pesi sono non commerciali; la licenza è sulla sua pagina.

Predizione

I pesi di LibreFOMO sono l'unica eccezione al download automatico su questo sito. LibreYOLO("LibreFOMOs-point.pt") cerca quel file su disco e solleva un ValueError che lo nomina invece di scaricarlo. Scarica prima un checkpoint dall'organizzazione LibreYOLO su Hugging Face e caricalo dal percorso locale, oppure addestrane uno tuo.

Predire i punti e contarli
from libreyolo import LibreYOLO, SAMPLE_IMAGE # I pesi di LibreFOMO non vengono scaricati automaticamente. Scarica prima# un checkpoint da https://huggingface.co/LibreYOLO e caricalo dal percorso locale.model = LibreYOLO("./LibreFOMOs-point.pt")result = model(SAMPLE_IMAGE, save=True) points = result.pointsprint(len(points))     # numero di oggettiprint(points.xy)       # (N, 2) centri in pixel dell'immagine originaleprint(points.cls, points.conf)
Coordinate normalizzate e conteggi per classe
from collections import Counter from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("./LibreFOMOs-point.pt")result = model(SAMPLE_IMAGE) points = result.points.numpy()print(points.xyn)                          # gli stessi centri in [0, 1]print(Counter(points.cls.astype(int).tolist()))

Il nome del file deve portare il suffisso di task -point perché il loader lo riconosca. predict(..., nms_radius=1) controlla di quante celle della griglia devono essere distanti due rilevamenti FOMO perché sopravvivano entrambi. Vedi predizione per sorgenti, streaming e gestione dei risultati.

Formato del dataset

point non ha un formato di etichette proprio. Le famiglie point leggono il layout standard di rilevamento YOLO e ricavano un centro da ogni riga di box, quindi cx cy è il punto e w h decidono soltanto se la riga è valida.

dataset/
  data.yaml
  images/
    train/scene.jpg
    val/scene.jpg
  labels/
    train/scene.txt
    val/scene.txt

Ogni file di etichette contiene una riga per oggetto, con coordinate normalizzate:

<class_id> <cx> <cy> <w> <h>
yaml
path: dataset
train: images/train
val: images/val
nc: 1
names: {0: seedling}

Un file di etichette mancante o vuoto significa che non ci sono oggetti. Vedi formati dei dataset per il contratto completo.

Addestramento

FOMO è l'unica famiglia point con un'implementazione di addestramento. train() su LocateAnything e su SenseNova-Vision solleva NotImplementedError; fai fine-tuning di quei modelli a monte e carica il risultato.

Addestrare FOMO su un dataset YOLO
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt")model.train(data="my-dataset.yaml", epochs=40, batch=32, lr0=3e-4)
Predire con il checkpoint addestrato
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("./LibreFOMOs-point.pt")results = model.train(data="my-dataset.yaml", epochs=40) # train() ricarica il checkpoint migliore nello stesso oggetto, quindi al# ritorno della chiamata il modello predice con i pesi addestrati.print(results["best_checkpoint"])print(model(SAMPLE_IMAGE).points.xy)

imgsz non è una scelta libera con FOMO: il valore predefinito è la risoluzione nativa del checkpoint caricato, e passare un valore diverso solleva un ValueError che indica la dimensione attesa. Vedi addestramento per dataset, logger e multi-GPU, e la pagina di FOMO per i valori predefiniti di questa famiglia.

Validazione

val() associa i punti predetti ai punti ground truth uno a uno con l'algoritmo ungherese, su uno sweep di soglie di distanza. Una soglia è una distanza euclidea in coordinate immagine normalizzate, e lo sweep predefinito è di dieci valori da 0.01 a 0.10.

Validare e leggere le chiavi delle metriche
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/precision"], metrics["metrics/recall"])print(metrics["metrics/f1"])print(metrics["metrics/mAP@[0.01:0.10]"])   # fitnessprint(metrics["metrics/MLE"])               # errore medio di localizzazioneprint(metrics["metrics/MAE"], metrics["metrics/RMSE"])   # errore di conteggio
Cambiare le soglie di distanza
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt") # I limiti dello sweep fanno parte del testo della chiave, quindi uno sweep# personalizzato rinomina le chiavi mAP che produce.metrics = model.val(data="my-dataset.yaml", dist_thresholds=[0.02, 0.05]) print(metrics["metrics/mAP@0.02"])print(metrics["metrics/mAP@[0.02:0.05]"])

metrics/precision, metrics/recall e metrics/f1 sono mediate a livello macro sulle classi alla soglia più severa dello sweep, 0.01 per impostazione predefinita. metrics/mAP@0.01 è l'average precision a quella stessa soglia, e metrics/mAP@[0.01:0.10] è la media sull'intero sweep. Quel valore dello sweep è anche fitness, il numero letto dalla selezione del checkpoint migliore. Entrambe le chiavi mAP sono costruite a partire dalle soglie in uso, quindi passare dist_thresholds= le rinomina.

metrics/MLE è la distanza media tra le coppie associate alla soglia più severa, nelle stesse unità normalizzate. metrics/MAE e metrics/RMSE sono metriche di conteggio più che di localizzazione: misurano la differenza, immagine per immagine, tra il numero di punti predetti e quello dei punti ground truth.

A queste FOMO aggiunge un secondo gruppo, a livello di griglia. Fa uno sweep su confidenza e nms_radius e pubblica la combinazione con l'F1 migliore come metrics/grid_F1, metrics/grid_precision, metrics/grid_recall, metrics/grid_mean_distance, metrics/grid_TP, metrics/grid_FP e metrics/grid_FN, con le impostazioni che l'hanno prodotta sotto decode/threshold e decode/nms_radius.

Esportazione

FOMO si esporta attraverso il percorso di esportazione condiviso, e un artefatto esportato si ricarica tramite LibreYOLO() in base al suffisso del file, quindi un file .onnx o .engine si comporta come un checkpoint e restituisce lo stesso Results.

Esportare
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt")model.export(format="onnx")
Eseguire il file esportato
from libreyolo import LibreYOLO, SAMPLE_IMAGE # La factory smista in base al suffisso del file, quindi un artefatto esportato# si carica come qualsiasi checkpoint e restituisce lo stesso oggetto Results.model = LibreYOLO("./LibreFOMOs-point.onnx")result = model(SAMPLE_IMAGE) print(result.points.xy)

La copertura per formato è sulla pagina di FOMO e nella matrice completa delle esportazioni. LocateAnything e SenseNova-Vision non si esportano: export() solleva un'eccezione in entrambi i casi, perché un modello generativo non ha un grafo di rilevamento tracciabile.

Verificato con LibreYOLO v1.5.0.