Döndürülmüş Nesneler için Yönlendirilmiş Sınırlayıcı Kutular
Dört köşeli OBB'leri etiketle, DOTA8 üzerinde yolo26n-obb.pt eğit ve xywhr tahminlerini açı kurallarına takılmadan kararlı bir yönelim eksenine dönüştür.
Limanlardaki gemiler, bantlardaki kargolar ve yukarıdan görülen otoparklardaki arabalar aynı sorunu paylaşır: döndürülmüş ve sıkışık nesnelerin etrafındaki eksenlere hizalı kutular birbirleriyle örtüşür ve arka planı içine alır; bunun sonucunda NMS gerçek nesneleri siler ve sayım düşük çıkar. Yönlendirilmiş sınırlayıcı kutular her nesneye döndürülmüş bir dikdörtgen uydurur; bu, yoğun sahnelerde sayım sorununu çözer ve doğrudan bir açı bilgisi verir. Ancak açı, ilk entegrasyonların neredeyse hepsini zorlayan kuralları da beraberinde getirir — bu dersteki liman görüntüsünde ilk gemi −15° dönüş bildirirken gövdesi 75° boyunca uzanır.
Uygulamalı
Dönüş önemli olduğunda#

Poz Tahmini ve OBB, algılama yerine OBB'nin ne zaman seçileceğini anlatır. Pratik test şu: komşu nesnelerin etrafındaki eksenlere hizalı sınırlayıcı kutular, nesnelerin kendilerinden daha fazla örtüşüyorsa NMS gerçek algılamaları baskılar ve sayım düşük çıkar. Havadan görüntüler bunun klasik örneğidir; önceden eğitilmiş yolo26n-obb.pt modelinin imgsz=1024 ile DOTA üzerinde eğitilmesinin nedeni de budur.
| Eksenlere hizalı kutu | Yönlendirilmiş kutu | |
|---|---|---|
| 45° açıyla duran bir gemiye uydurulmuş | yaklaşık yarısı arka plan | sıkı |
| Yoğun, döndürülmüş sıralar | kutular örtüşür; NMS gerçek nesneleri siler | kutular birbirinden net biçimde ayrılır |
| Açı verir | hayır | evet, eksen olarak (180°'ye göre kalan) |
| Sonuç alanı | result.boxes | result.obb |
xyxyxyxy etiket biçimi#
Bir OBB etiket satırı, sınıf indeksinin ardından çevre boyunca sıralanmış, normalize edilmiş dört köşeden oluşur. Gerçek bir DOTA8 satırı (sınıf 1 ship değeridir):
1 0.813477 0.523437 0.814453 0.504882 0.87207 0.504882 0.87207 0.524414Bunu dört nokta olarak oku: (0.813, 0.523) → (0.814, 0.505) → (0.872, 0.505) → (0.872, 0.524). Bu gemi neredeyse yatay durur; görüntünün yaklaşık 0.059'u kadar geniş ve 0.019'u kadar yüksektir. Ultralytics, her köşe kümesini minimum alanlı dikdörtgeni uydurarak merkez, genişlik, yükseklik ve dönüşe (xywhr) dönüştürür; böylece bir etiketleme aracından gelen hafifçe dikdörtgen olmayan bir dörtgenle bile eğitim yapılabilir. OBB veri kümesi kılavuzu biçimi açıklar; ultralytics.data.converter içindeki convert_dota_to_yolo_obb ise orijinal DOTA açıklamalarını dönüştürür.

DOTA8 üzerinde eğit#
DOTA8, işlem hatlarını test etmek için oluşturulmuş küçük bir yönlendirilmiş kutu veri kümesidir:

from ultralytics import YOLO
model = YOLO("yolo26n-obb.pt")
model.train(data="dota8.yaml", epochs=1, imgsz=320, device="cpu")
metrics = model.val()
print(f"OBB mAP50: {metrics.box.map50:.3f} mAP50-95: {metrics.box.map:.3f}")OBB mAP50: 0.995 mAP50-95: 0.832OBB metrikleri metrics.box içinde yer alır, ancak bu metriklerin temelindeki IoU, döndürülmüş dikdörtgenler arasında hesaplanır.
DOTA8, ön eğitim verilerinin bir dilimi olduğu için puan yüksektir. Bu, iş hattının çalıştığını kanıtlar; kendi görüntülerin hakkında hiçbir şey söylemez.
Tahminleri oku ve açıyı normalleştir#
import math
from collections import Counter
from ultralytics import YOLO
def long_side_axis(w, h, r):
"""Angle of the box's long side in degrees, in [0, 180), whichever side the model called width."""
deg = math.degrees(r) + (90 if w < h else 0)
return deg % 180
model = YOLO("yolo26n-obb.pt") # trained on DOTAv1, 15 aerial classes
result = model("https://ultralytics.com/images/boats.jpg", verbose=False)[0]
obb = result.obb.cpu()
print("xywhr:", tuple(obb.xywhr.shape), " xyxyxyxy:", tuple(obb.xyxyxyxy.shape))
print(Counter(result.names[int(c)] for c in obb.cls.tolist()))
for (cx, cy, w, h, r), conf in list(zip(obb.xywhr.tolist(), obb.conf.tolist()))[:5]:
print(f"{conf:.2f} center=({cx:.0f},{cy:.0f}) size={w:.0f}x{h:.0f} raw={math.degrees(r):4.0f} deg axis={long_side_axis(w, h, r):4.0f} deg")xywhr: (173, 5) xyxyxyxy: (173, 4, 2)
Counter({'ship': 168, 'harbor': 5})
0.87 center=(619,850) size=33x108 raw= -15 deg axis= 75 deg
0.86 center=(1650,937) size=116x33 raw= 21 deg axis= 21 deg
0.86 center=(1105,571) size=124x35 raw= 21 deg axis= 21 deg
0.86 center=(1596,1037) size=129x35 raw= 25 deg axis= 25 deg
0.86 center=(825,940) size=34x99 raw= -15 deg axis= 75 degSatır satır:
xywhr: (173, 5)— her biri merkez x, merkez y, piksel cinsinden genişlik ve yükseklik ile radyan cinsinden dönüş açısı içeren 173 tespit.xyxyxyxy, aynı kutularıcv2.polylinesiçin hazır dört köşe noktası olarak içerir.- Sayaç,
result.obb.clsüzerinden sayım yapar: 168 gemi ve 5 liman. OBB modellerinderesult.boxes,Noneolur; bu nedenle tespit için yazılmış sayım kodunda alanları değiştirmen gerekir. rawileaxiskarşılaştırması. İlk gemi −15° açıyla 33 × 108 boyutundadır:wkısa kenardır, bu nedenle gövde −15° + 90° = 75° boyunca uzanır. İkinci gemi 21° açıyla 116 × 33 boyutundadır ve uzun kenarı zaten ilk sıradadır. Ham açıları okursan ilk geminin ekseni 90° hatalı olur; normalleştirme sonrasında her geminin açısı aynı anlama gelir ve gemiler ile kareler arasında karşılaştırılabilir.
Kural, kurulu kaynak kodundan gelir: tahmin edilen dönüş açısı [−π/4, 3π/4) aralığındadır — yaklaşık −45° ile 135° arasıdır — ve aynı dikdörtgen (w, h, θ) veya (h, w, θ + 90°) olabilir. w değerinin uzun kenar olduğunu asla varsayma.
Küçük nesneler küçültme değil, karo kullanmayı gerektirir#
Havadan görüntülenen nesneler küçüktür; doğrulama veya dağıtım sırasında eğitimde kullanılan imgsz değerinin altına inmek, kısa sürede geri çağırma oranını düşürür. Modelin girişinden büyük uydu karolarını küçültmek yerine örtüşen karolara böl; yoksa 30 piksellik bir araba 5 piksellik bir lekeye dönüşür. SAHI karo çıkarımları kılavuzu bu tekniği gösteriyor; dedektör kullanılan bir otoyol karesinde tam görüntü çıkarımı, uzaktaki araçların çoğunu kaçırıyor:

Karo çıkarımı ise bunları bulur:

Yaygın Hatalar#
Belirti: Kareler arasında 180° dönen bir "yön" veya geriye doğru gidiyor gibi görünen gemiler. Neden: 180° döndürülmüş bir dikdörtgen yine aynı dikdörtgendir; bu nedenle OBB bir yön doğrultusu verir, ilerleme yönünü değil. Çözüm: Geminin veya forkliftin hangi yöne baktığını bilmen gerekiyorsa baş kısmına ya da çatal uçlarına bir poz anahtar noktası ekle veya kırpılmış görüntü üzerinde bir sınıflandırıcı kullan.
Belirti: Benzer verilerde OBB precision-recall eğrileri, tespit çalıştırmalarındakilerden farklı görünüyor. Neden: OBB doğrulaması varsayılan olarak conf=0.01 kullanırken diğer görevler 0.001 kullanır. Çözüm: mAP değerlerini karşılaştır veya eşleşen kesinlik-duyarlılık eğrilerine ihtiyacın varsa conf değerini açıkça ayarla.
Çözümü göster
import math
from collections import Counter
from ultralytics import YOLO
result = YOLO("yolo26n-obb.pt")("https://ultralytics.com/images/boats.jpg", verbose=False)[0]
axes = []
for (cx, cy, w, h, r), cls in zip(result.obb.xywhr.cpu().tolist(), result.obb.cls.tolist()):
if result.names[int(cls)] == "ship":
axes.append((math.degrees(r) + (90 if w < h else 0)) % 180) # long-side axis in [0, 180)
def axis_gap(a, b):
"""Smallest difference between two axes; 175 and 5 degrees are only 10 apart."""
d = abs(a - b) % 180
return min(d, 180 - d)
common = Counter(round(a / 10) * 10 % 180 for a in axes).most_common(1)[0][0]
off = [a for a in axes if axis_gap(a, common) > 30]
print(f"{len(axes)} ships, most common axis ~{common} deg, {len(off)} more than 30 deg off it")168 ships, most common axis ~20 deg, 32 more than 30 deg off itTeknelerin çoğu yaklaşık 20° açıyla paralel duruyor; eksenden sapan 32 gemi, bir liman izleme kuralının inceleme için işaretleyeceği aykırı değerlerdir. Dikdörtgen 180° döndürmede simetrik olduğundan OBB geminin başıyla kıçını ayırt edemez; baş kısmına bir poz anahtar noktası eklemek gerçek baş yönünü verir.