Detekcja obróconych obiektów
Detekcja obróconych obiektów lokalizuje każdą instancję za pomocą obróconego prostokąta zamiast prostokąta wyrównanego do osi. Dzięki temu pochylony obiekt jest ciasno ograniczony, a ramka nie zawiera dużej ilości tła. Klucz zadania to obb.
Definicja
Detekcja obróconych obiektów dodaje do detekcji jedną liczbę: kąt. Każda instancja otrzymuje obrócony prostokąt, klasę i wynik. Korzyścią jest ścisłe dopasowanie. Statek ustawiony pod kątem 45 stopni, dach magazynu lub rząd zaparkowanych ciężarówek zostałby otoczony ramką wyrównaną do osi, która w większości zawierałaby tło. Dwie sąsiednie ramki nakładałyby się nawet wtedy, gdy obiekty się nie stykają. Dlatego zadanie to jest standardem w obrazowaniu lotniczym i analizie układu dokumentów, a jego referencyjnym zbiorem danych jest DOTA.
obb jest kanonicznym kluczem zadania, a sufiks -obb w nazwie pliku
checkpointu wybiera to zadanie, więc task= nie jest potrzebne przy wczytywaniu
opublikowanych wag.
predict() wypełnia result.obb. Pole .xywhr ma kanoniczną postać (N, 5):
środek x, środek y, szerokość, wysokość i kąt w radianach określający obrót boku
szerokości wokół środka. Pola .conf i .cls zawierają wynik i indeks klasy w
result.names, a .id identyfikator ścieżki podczas śledzenia. Pole
.xyxyxyxy przekształca każdy wiersz w cztery punkty narożne jako piksele
(N, 4, 2), .xyxyxyxyn normalizuje te narożniki, a .xyxy zwraca otaczającą
ramkę wyrównaną do osi. Tej ostatniej postaci należy użyć, gdy dalszy kod
rozumie tylko prostokąty. result.boxes również jest wypełnione postacią
wyrównaną do osi.
Modele
To zadanie obsługują cztery rodziny.
RF-DETR obsługuje trenowanie. Przewiduje, trenuje, waliduje i eksportuje obrócone ramki oraz udostępnia checkpointy tego zadania w czterech rozmiarach: n, s, m i l. Wymaga własnego dodatku, pip install "libreyolo[rfdetr]", a strona modelu podaje licencję wag i ich pochodzenie.
Przed zaplanowaniem użycia tych checkpointów należy przeczytać poniższą sekcję, która wyjaśnia, co faktycznie przewidują.
RT-DETRv2 jest rodziną z wagami dla obrazów lotniczych.
Udostępnia modele od LibreRTDETRv2n-obb.pt do LibreRTDETRv2x-obb.pt, czyli
oficjalne checkpointy DOTA v1.0 w jednej skali, przekonwertowane do formatu
LibreYOLO. Obejmują one 15 klas DOTA przy 1024 px. Rodzina nie wymaga dodatków
poza pakietem podstawowym, graf obróconych ramek jest rozpoznawany z tensorów
checkpointu, a predykcja, walidacja oraz eksport do ONNX i TorchScript są w
pełni obsługiwane. Trenowanie nie jest obsługiwane. Zadanie obróconych ramek w
tej rodzinie służy tylko do inferencji, train() zgłasza błąd i nie ma transferu
z wag detekcji, które używają innego backbone. Śledzenie i augmentacja w czasie
testu również nie są dostępne dla obróconych ramek.
Należy wybrać zestaw etykiet checkpointu i obsługę trenowania odpowiednie dla zbioru danych.
YOLO-NAS również obsługuje trenowanie i inferencję OBB. Jego wstępnie wytrenowane wagi zachowują niekomercyjne warunki projektu źródłowego.
GTR udostępnia LibreGTRs-obb.pt i LibreGTRx-obb.pt,
które przewidują 15 klas DOTA v1.0 przy stałym rozmiarze wejścia 1024. Działa z
pakietem podstawowym i obsługuje predykcję, trenowanie, walidację oraz eksport
do ONNX i TorchScript.
Predykcja
Przy pierwszym użyciu wagi są pobierane z Hugging Face i zapisywane lokalnie w pamięci podręcznej.
# Wymaga dodatku rfdetr: pip install "libreyolo[rfdetr]"from libreyolo import LibreYOLO, SAMPLE_IMAGE # Sufiks -obb w nazwie pliku wybiera zadanie, dlatego argument# task nie jest potrzebny.model = LibreYOLO("LibreRFDETRs-obb.pt")result = model(SAMPLE_IMAGE, save=True) obb = result.obbprint(obb.xywhr) # (N, 5): środek x, środek y, szerokość, wysokość, radianyprint(obb.conf, obb.cls)libreyolo predict model=LibreRFDETRs-obb.pt save=True \ source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpgfrom libreyolo import LibreYOLO, SAMPLE_IMAGE result = LibreYOLO("LibreRFDETRs-obb.pt")(SAMPLE_IMAGE)obb = result.obb print(obb.xyxyxyxy.shape) # punkty narożne (N, 4, 2) w pikselachprint(obb.xyxyxyxyn.shape) # te same punkty po normalizacjiprint(obb.xyxy.shape) # otaczająca ramka (N, 4) wyrównana do osifrom libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreRFDETRn-obb.pt")result = model(SAMPLE_IMAGE) print(result.obb.xywhr.shape)from libreyolo import LibreYOLO # Wagi DOTA v1.0, 15 klas lotniczych przy 1024 px. Graf obróconych ramek# jest rozpoznawany z tensorów checkpointu, więc argument task jest zbędny.model = LibreYOLO("LibreRTDETRv2n-obb.pt")result = model("aerial.png", save=True) obb = result.obbprint(obb.xywhr)print(result.names) # samolot, statek, port, helikopter i 11 innych klasPrzed uruchomieniem opublikowanych checkpointów RF-DETR warto wiedzieć, czego dotyczą. Choć DOTA jest referencyjnym benchmarkiem tego zadania, wagi te nie zostały na nim wytrenowane. Wszystkie cztery zainicjowano wagami detekcji RF-DETR i dostrojono na jednym zbiorze danych z nagraniami z dronów, obejmującym sześć klas pojazdów: bike, bus, car, other_vehicle, taxi i truck. Karty modeli opisują je jako wagi rozwojowe utworzone podczas walidacji obsługi trenowania obróconych ramek i zaznaczają, że nie należy ich traktować jako wag produkcyjnych ani oficjalnych dla benchmarku.
W praktyce są działającym punktem wyjścia dla obróconych ramek pojazdów
widzianych z góry oraz do sprawdzenia, czy pipeline działa od początku do końca.
Każda inna dziedzina wymaga trenowania na własnych etykietach obróconych ramek.
Dla kategorii lotniczych znanych ze zbioru DOTA właściwym wyborem są checkpointy
RT-DETRv2, rzeczywiście wytrenowane na tych danych. conf i max_det kształtują
dane wyjściowe tak samo jak w detekcji, a agnostic_nms=True tłumi nakładające
się ramki między klasami za pomocą obróconego IoU. Informacje o źródłach,
streamingu i obsłudze wyników znajdują się w sekcji predykcja.
Format zbioru danych
Układ odpowiada detekcji: na każdy obraz przypada jeden plik etykiet .txt,
znajdowany przez zastąpienie images ciągiem labels w ścieżce obrazu i zmianę
rozszerzenia.
dataset/ data.yaml images/ train/P0001.png val/P0101.png labels/ train/P0001.txt val/P0101.txtWiersz zawiera dokładnie dziewięć pól: indeks klasy, po którym następują cztery punkty narożne w kolejności:
<class_id> <x1> <y1> <x2> <y2> <x3> <y3> <x4> <y4>Cztery punkty są znormalizowanymi liczbami zmiennoprzecinkowymi z zakresu
[0, 1] i muszą tworzyć niezdegenerowany obrócony prostokąt. W pliku etykiet
nie zapisuje się kąta. Moduł wczytujący wyprowadza z narożników kanoniczną postać
xywhr. Parser jest domyślnie rygorystyczny i odrzuca współrzędne spoza zakresu,
natomiast podczas wczytywania zbioru danych i walidacji może najpierw ograniczyć
do [0, 1] poprawne poza tym etykiety na granicy wycinka, po czym nadal odrzuci
zdegenerowane ramki.
Analiza wierszy uwzględnia zadanie. Dziewięć pól oznacza obróconą ramkę tylko w
trybie obb. W trybie segment ten sam wiersz jest odczytywany jako wielokąt z
czterema punktami.
Plik YAML ma format używany w detekcji:
path: datasettrain: images/trainval: images/valnames: 0: plane 1: shipMożna także wczytać natywny plik COCO JSON z mapowaniem annotations między
nazwą podziału a plikiem JSON. Adnotacje są odczytywane w następującej
kolejności priorytetów: pole obb z ośmioma narożnikami w przestrzeni pikseli,
pole obb w postaci [cx, cy, w, h, angle] z kątem w radianach, wielokąt
segmentation lub RLE dopasowane ponownie do prostokąta o minimalnym polu albo
zwykłe pole COCO bbox, traktowane jako prostokąt wyrównany do osi i
kanonizowane do xywhr.
Kanoniczny parser wiersza to libreyolo.data.parse_yolo_obb_label_line.
Trenowanie
from libreyolo import LibreYOLO # Kontynuuje od opublikowanych wag obróconych ramek. data musi wskazywać# zbiór danych, którego wiersze etykiet zawierają cztery narożniki.model = LibreYOLO("LibreRFDETRs-obb.pt")model.train(data="my-obb-dataset.yaml", epochs=50, imgsz=512, batch=8, lr0=1e-4)libreyolo train model=LibreRFDETRs-obb.pt data=my-obb-dataset.yaml \ epochs=50 imgsz=512 batch=8 lr0=1e-4# Wagi detekcji nie przewidują kąta, więc jest to jawny transfer.# Żądanie task=obb udziela na niego zezwolenia.libreyolo train model=LibreRFDETRs.pt data=my-obb-dataset.yaml \ task=obb epochs=50 imgsz=512Trenowanie RF-DETR jest domyślnie kontynuowane z opublikowanego checkpointu -obb. Rozpoczęcie od wag detekcji jest świadomym
transferem. Wagi te nie przewidują kąta, a przekazanie task=obb zezwala na
zamianę. Wartość lr0 należy utrzymać na poziomie 1e-4 lub niższym, podobnie
jak w pozostałych zadaniach tej rodziny. Checkpointów obróconych ramek RT-DETRv2
nie można dostrajać. Należy używać ich bez zmian lub wytrenować model RF-DETR na
własnych etykietach. Informacje o zbiorach danych, augmentacji, wielu GPU i
loggerach znajdują się w sekcji trenowanie.
YOLO-NAS OBB używa przypisywania i funkcji strat dla obróconych ramek, augmentacji odbiciami i HSV oraz domyślnie amp=False. Wybiera checkpointy według metrics/mAP50-95(OBB).
Walidacja
val() zwraca zwykły słownik kluczy metrics/. Dopasowanie używa obróconego
IoU, obliczanego między obróconymi prostokątami, a nie między ich otaczającymi
ramkami wyrównanymi do osi. Dlatego predykcja o prawidłowym położeniu, ale
błędnym kącie, jest uznawana za chybioną.
from libreyolo import LibreYOLO model = LibreYOLO("LibreRFDETRs-obb.pt") # val() zwraca zwykły słownik, a nie obiekt.metrics = model.val(data="my-obb-dataset.yaml") print(metrics["metrics/mAP50-95"])print(metrics["metrics/mAP50"], metrics["metrics/mAP75"])print(metrics["metrics/precision"], metrics["metrics/recall"])libreyolo val model=LibreRFDETRs-obb.pt data=my-obb-dataset.yamllibreyolo val model=LibreRTDETRv2n-obb.pt data=my-obb-dataset.yamlmetrics/mAP50-95 to średnia precyzja uśredniona dla progów IoU od 0.50 do 0.95
z krokiem 0.05 i jest głównym wynikiem. W przeciwieństwie do ścieżki COCO
używanej w detekcji to zadanie respektuje iou_thresholds w konfiguracji
walidacji, więc zakres można zmienić. metrics/mAP50 i metrics/mAP75 to
warianty z jednym progiem. metrics/precision i metrics/recall są rzeczywistą
precyzją i wartością recall przy IoU 0.50, odczytywanymi w najluźniejszym punkcie
pracy. Liczy się każda predykcja, która przetrwała próg pewności, a próg ten
domyślnie wynosi 0.001 podczas walidacji. Podniesienie conf zmienia więc te
wartości, podczas gdy wyniki mAP, które używają całej krzywej precision-recall,
pozostają niezmienione. Cztery z tych metryk powtarzają się z sufiksem (OBB):
metrics/mAP50-95(OBB), metrics/mAP50(OBB), metrics/precision(OBB) i
metrics/recall(OBB). Dzięki temu kod wywołujący odróżnia wynik obrócony od
wyrównanego do osi, gdy oba znajdują się w tej samej tabeli. Metryka
metrics/mAP75 nie ma odpowiednika z sufiksem.
Dwie opcje nie mają wpływu na to zadanie. save_json i save_plots są
akceptowane i powodują zapisanie ostrzeżenia w logu. Zrzuty predykcji obróconych
ramek i wykresy walidacji nie są zaimplementowane. agnostic_nms=True zgłasza tu
ValueError; obejmuje tylko walidację detekcji i segmentacji.
Eksport
from libreyolo import LibreYOLO model = LibreYOLO("LibreRFDETRs-obb.pt")model.export(format="onnx", imgsz=512)libreyolo export model=LibreRFDETRs-obb.pt format=onnx imgsz=512# ONNX i TorchScript są tutaj zweryfikowanymi celami, z FP32,# batchem 1 oraz stałym obszarem roboczym 1024 na 1024.libreyolo export model=LibreRTDETRv2n-obb.pt format=onnx imgsz=1024libreyolo export model=LibreRTDETRv2n-obb.pt format=torchscript imgsz=1024from libreyolo import LibreYOLO, SAMPLE_IMAGE # Fabryka wybiera ścieżkę na podstawie sufiksu pliku, więc wyeksportowany artefakt# wczytuje się jak checkpoint i zwraca ten sam obiekt Results.model = LibreYOLO("LibreRFDETRs-obb.onnx")result = model(SAMPLE_IMAGE) print(result.obb.xywhr)Wyeksportowany artefakt jest ponownie wczytywany przez LibreYOLO() na podstawie
sufiksu pliku, więc plik .onnx lub .engine zachowuje się jak checkpoint i
zwraca ten sam obiekt Results. Zakres formatów różni się między zadaniami w
tej samej rodzinie. Macierz na stronie modelu jest generowana ze zweryfikowanego
zestawu i podaje przyczynę niedostępności celu. Formaty, ich dodatki i
ograniczenia opisano w sekcji eksport i wdrożenie.