Kodda Maskeleri Kullanma: Alan, Örtüşme, Konturlar, Kesitler
masks.data ve masks.xy değerlerini doğru oku, nesne alanını ve doluluk oranını ölç, kutular yerine maskelerle örtüşmeyi test et ve nesneleri kareden kesip çıkar.
Bir segmentasyon modeli, ancak kod maskelerini bir karara dönüştürdüğünde karşılığını verir. Otobüs fotoğrafında her yayanın kutusu otobüsün kutusuyla %56–74 oranında örtüşürken maskeleri otobüsle %0 örtüşür — kutulara dayalı bir "araç bölgesindeki kişi" uyarısı, kaldırımda duran dört kişinin tamamı için tetiklenirdi. Maskeler bu yanıtları doğru verir; ancak varsayılan görünümlerindeki boyut ve biçim tuzakları, makul görünen ama yanlış sayılara yol açabilir.
Uygulamalı
Aynı maskenin iki görünümü#

result.masks, her örnek maskesini iki gösterimde tutar. Sonraki kod satırının yapacağı işe göre seçim yap; Results başvurusu tüm öznitelikleri listeler.
| Öznitelik | Şekil | Koordinatlar | Kullanım amacı |
|---|---|---|---|
masks.data | 0/1 değerlerinden oluşan N × H × W tensörü | varsayılan olarak çıkarım boyutu; retina_masks=True ile özgün boyut | piksel alanları, maskeler arası örtüşmeler, kesitler |
masks.xy | her biri P × 2 boyutunda olan N dizi listesi | özgün görüntünün pikselleri | kontur çizmek, poligonları dışa aktarmak |
masks.xyn | her biri P × 2 boyutunda olan N dizi listesi | normalize edilmiş 0–1 | YOLO poligon etiketlerini dışa aktarmak |
1080 × 810 boyutundaki otobüs görüntüsünde masks.data, (5, 640, 480) olarak döner — bu, mektup kutulu çıkarım boyutudur — dolayısıyla piksel sayıları yaklaşık 2.85× az çıkar ve maske özgün görüntünün üzerine yerleştirilemez. retina_masks=True, küçük bir son işleme maliyetiyle maskeleri özgün çözünürlüğe yükseltir. Ölçüm veya kırpma yaptığında bunu kullan.
Her nesnenin ölçümünü al ve kesitini çıkar#
Bu betik her nesne için iki görünümü okur: masks.data ile piksel alanını, masks.xy ile kontur boyutunu ve maskeyi alfa kanalı olarak kullanan şeffaf bir PNG kesiti. Segmentasyon nesnelerini yalıtma kılavuzu daha fazla kesit çeşidini ele alır.
import cv2
import numpy as np
from ultralytics import YOLO
model = YOLO("yolo26n-seg.pt")
result = model("https://ultralytics.com/images/bus.jpg", retina_masks=True)[0] # masks at original resolution
print("masks.data:", tuple(result.masks.data.shape), "orig_shape:", result.orig_shape)
for i, box in enumerate(result.boxes):
name = result.names[int(box.cls)]
mask = result.masks.data[i].cpu().numpy().astype(np.uint8) # H x W, 1 = object
polygon = result.masks.xy[i] # P x 2 outline in original pixels
x1, y1, x2, y2 = box.xyxy[0].int().tolist()
mask_area = int(mask.sum())
box_area = (x2 - x1) * (y2 - y1)
print(f"{name:6s} conf={float(box.conf):.2f} mask={mask_area:7d}px box={box_area:7d}px fill={mask_area / box_area:.2f} polygon={len(polygon)} pts")
# Cut the object out on a transparent background
cutout = np.dstack([result.orig_img, mask * 255])[y1:y2, x1:x2]
cv2.imwrite(f"{i}_{name}.png", cutout)masks.data: (5, 1080, 810) orig_shape: (1080, 810)
person conf=0.88 mask= 49331px box= 97219px fill=0.51 polygon=575 pts
person conf=0.86 mask= 21316px box= 67760px fill=0.31 polygon=408 pts
bus conf=0.86 mask= 255265px box= 409822px fill=0.62 polygon=1172 pts
person conf=0.81 mask= 33524px box= 55842px fill=0.60 polygon=350 pts
person conf=0.64 mask= 11109px box= 23828px fill=0.47 polygon=211 ptsÇıktıda dikkat etmen gerekenler:
masks.data: (5, 1080, 810),orig_shapeile eşleşiyor; dolayısıylaretina_masks=Truegörevini yaptı ve tüm piksel sayıları özgün pikseller üzerinden.iindeksi ikisini birbirine bağlar.result.masks.data[i],result.boxes[i]öğesine aittir; bu nedenle adlar ve güven değerleri kutudan, pikseller ise maskeden gelir.- Doluluk, algılayıcının veremeyeceği bir bilgi sunar: otobüs kutusunun %62'sini kaplarken çerçevenin sağ kenarında kesilen ve otobüsün önünde duran ikinci kişi yalnızca %31 doluluk oranına sahiptir.
- Kesitler, yalnızca kişiyi veya otobüsü içeren, başka hiçbir şey içermeyen BGRA PNG dosyalarıdır — katalog, ikinci bir model veya inceleme kuyruğu için hazırdır.
Yalıtma kılavuzundaki kırpılmış sürüm, şeffaf arka plan yerine siyah arka plan kullanır:

Örtüşme: kutuların kapladığı alanlar#
"Kişi kısıtlı bölgenin içinde" veya "ürün taşıma bandını kaplıyor" gibi kurallar, örtüşme testleridir. Aynı testi kutularla ve maskelerle çalıştır:
import numpy as np
from ultralytics import YOLO
result = YOLO("yolo26n-seg.pt")("https://ultralytics.com/images/bus.jpg", retina_masks=True, verbose=False)[0]
names = [result.names[int(c)] for c in result.boxes.cls]
masks = result.masks.data.cpu().numpy().astype(bool) # N x H x W at original resolution
boxes = np.zeros_like(masks)
for i, (x1, y1, x2, y2) in enumerate(result.boxes.xyxy.int().tolist()):
boxes[i, y1:y2, x1:x2] = True # the same objects as filled rectangles
bus = names.index("bus")
for i, name in enumerate(names):
if name == "person":
by_box = (boxes[i] & boxes[bus]).sum() / boxes[i].sum()
by_mask = (masks[i] & masks[bus]).sum() / masks[i].sum()
print(f"person {i}: {by_box:4.0%} of box overlaps the bus box, {by_mask:4.0%} of mask overlaps the bus mask")person 0: 67% of box overlaps the bus box, 0% of mask overlaps the bus mask
person 1: 69% of box overlaps the bus box, 0% of mask overlaps the bus mask
person 3: 74% of box overlaps the bus box, 0% of mask overlaps the bus mask
person 4: 56% of box overlaps the bus box, 0% of mask overlaps the bus maskİnsanlar otobüsün önünde durduğundan otobüs maskesi her birinin konturunda sona erer ve maskeler ortak piksel içermez. Kutular ise her ikisinin çevresine çizilmiş dikdörtgenlerdir; bu nedenle büyük ölçüde örtüşürler. Aynı hesaplama, kendin çizdiğin her bölge için de geçerlidir: cv2.fillPoly ile sıfırlardan oluşan bir diziye poligon doldur ve otobüs maskesinin yerine kullan.
İçinde, dokunuyor, kapatıyor veya engelliyor şeklinde ifade edilen her kural, bir örtüşme testidir. Bu testi maskeler üzerinde yap. Birkaç piksellik farkın sonucu değiştirmediği yakınında ve solunda gibi durumlarda kutular uygundur.
Piksellerden gerçek dünya yanıtlarına#
| Soru | Hesaplama | Dikkat et |
|---|---|---|
| Ne kadar büyük? | mask.sum() × (cm²/piksel başına) | Bilinen bir nesneyle cm²/piksel değerini bir kez kalibre et. Açılı bir kamerada alan mesafeye göre değişir: her bölgeyi ayrı ayrı kalibre et veya yalnızca tek bir bölgede ölçüm yap. |
| Bölgenin ne kadarı kaplı? | sınıf maskesi pikselleri ÷ bölge pikselleri | Üst üste binen örneklerin bir mi, iki mi sayılacağına karar ver. |
| Bölgenin içinde mi? | (mask & zone).sum() / mask.sum() | Bölgeyi özgün görüntü boyutunda çiz. |
| Dış hatları nasıl görünüyor? | masks.xy[i] | Alanı hesaplamadan önce aşağıdaki bölünmüş nesne uyarısına bak. |
Yaygın Hatalar#
Belirti: Nesne bulunmayan karelerde AttributeError: 'NoneType' object has no attribute 'xy'. Neden: Model hiçbir şey bulamadığında result.masks, boş bir nesne değil, None değeridir. Çözüm: result.boxes üzerinde döngü kur (segment modellerinde boş olur, hiçbir zaman None olmaz) ve masks.py örneğinde olduğu gibi döngünün içinde maskeleri indeksle veya önce result.masks is None değerini denetle.
Belirti: Örtülmüş nesneler için alanlar çok yanlış çıkıyor. Neden: Örtücü bir nesne, bir nesneyi böldüğünde masks.xy tüm konturları tek bir dizide birleştirir ve bu dizi üzerinde cv2.contourArea kullanmak gerçekte var olmayan bir şeklin alanını ölçer. Çözüm: Alanları masks.data piksel sayılarına göre hesapla; çokgenleri çizim için kullan.
Belirti: İki çalıştırmadaki alanlar yaklaşık 2.85 kat farklı. Neden: Çalıştırmalardan birinde retina_masks=False kullanıldığından alanlar çıkarım pikselleri cinsinden. Çözüm: Her yerde retina_masks=True ile ölç; CUDA üzerinde .numpy() çağrısından önce .cpu() çağır.
Çözümü göster
retina_masks=True olmadan, otobüs görüntüsü (5, 640, 480) şekline sahip masks.data döndürür: her piksel alanı (1080 × 810) / (640 × 480) ≈ 2.85 kat küçülür ve kesitler için maske artık orig_img ile hizalanmaz. Görüntünün en-boy oranı çıkarım boyutundan farklı olduğunda, letterbox dolgusu ikinci bir hizasızlığa yol açar.
Otobüs görüntüsünde doluluk oranı en düşük olan, ikinci kişidir (0.31): karenin sağ kenarında kesilmiş ve otobüse yaslanarak duruyor; bu nedenle kutunun büyük kısmı arka plan ve otobüsten oluşuyor.
Bölgeyi özgün boyutta bir kez oluştur ve maske testini yeniden kullan:
import cv2
h, w = result.orig_shape
zone = np.zeros((h, w), np.uint8)
cv2.fillPoly(zone, [np.array([[0, 2 * h // 3], [w, 2 * h // 3], [w, h], [0, h]])], 1)
zone = zone.astype(bool)
for i, name in enumerate(names):
print(f"{name} {i}: box {(boxes[i] & zone).sum() / boxes[i].sum():.0%}, mask {(masks[i] & zone).sum() / masks[i].sum():.0%}")Otobüs görüntüsünde:
person 0: box 36%, mask 29%
person 1: box 33%, mask 37%
bus 2: box 4%, mask 0%
person 3: box 31%, mask 21%
person 4: box 47%, mask 53%İnsanların bacakları gerçekten alt üçte birlik kısımda, dolayısıyla kutu ve maske yaklaşık on puan farkla örtüşüyor. Yanlış alarm otobüs: kutusu bölgenin %4'üne giriyor, maskesi ise hiç girmiyor. “İçeride %0'dan fazla” kuralıyla kutular otobüsü işaretler, maskeler işaretlemezdi.