Obyekt aniqlash — qayerda va nima
Klassifikatsiya "bu rasmda nima bor?" degan savolga javob beradi. Aniqlash esa "qayerda va nima?"
Klassifikatsiya: rasm -> "mushuk"
Aniqlash: rasm -> [("mushuk", x=120, y=45, w=200, h=180),
("it", x=380, y=90, w=150, h=140)]
Hujjat uchun bu muhim: "bu sahifada jadval bor" emas, balki "jadval aynan shu koordinatalarda".
Bounding box formatlari
Uch xil format bor va ular tez-tez chalkashtiriladi:
# 1. XYWH — chap-yuqori burchak + o'lcham (OpenCV) quti_xywh = (100, 50, 200, 150) # 2. XYXY — chap-yuqori + o'ng-past (PyTorch, ko'p model) quti_xyxy = (100, 50, 300, 200) # 3. CXCYWH — markaz + o'lcham, NORMALLASHGAN (YOLO) quti_yolo = (0.4, 0.3, 0.25, 0.2) # 0.0 dan 1.0 gacha
O'tkazish:
def xywh_to_xyxy(x, y, w, h): return (x, y, x + w, y + h) def xyxy_to_xywh(x1, y1, x2, y2): return (x1, y1, x2 - x1, y2 - y1) def yolo_to_xyxy(cx, cy, w, h, rasm_k, rasm_b): """YOLO normallashgan formatdan piksel koordinatalariga.""" x1 = (cx - w / 2) * rasm_k y1 = (cy - h / 2) * rasm_b x2 = (cx + w / 2) * rasm_k y2 = (cy + h / 2) * rasm_b return (round(x1), round(y1), round(x2), round(y2)) print("xywh->xyxy:", xywh_to_xyxy(100, 50, 200, 150)) print("yolo->xyxy:", yolo_to_xyxy(0.4, 0.3, 0.25, 0.2, 640, 480))
Natija:
xywh->xyxy: (100, 50, 300, 200) yolo->xyxy: (176, 96, 336, 192)
YOLO formati normallashgan — 0 dan 1 gacha. Shuning uchun rasm o'lchami o'zgarsa ham koordinatalar to'g'ri qoladi.
Bu format xatosi eng ko'p vaqt yo'qotadigan muammolardan biri. Model ishlaydi, lekin qutilar noto'g'ri joyda chiqadi.
IoU — qutilar qanchalik mos
IoU (Intersection over Union) — ikkita quti qanchalik ustma-ust tushishini o'lchaydi. Butun aniqlash sohasi shunga tayanadi.
IoU = kesishma maydoni / birlashma maydoni
def iou(a, b): """Ikki XYXY quti orasidagi IoU. 0.0 dan 1.0 gacha.""" ax1, ay1, ax2, ay2 = a bx1, by1, bx2, by2 = b # Kesishma to'rtburchagi kx1 = max(ax1, bx1) ky1 = max(ay1, by1) kx2 = min(ax2, bx2) ky2 = min(ay2, by2) # Kesishma bormi? kw = max(0, kx2 - kx1) kh = max(0, ky2 - ky1) kesishma = kw * kh a_maydon = (ax2 - ax1) * (ay2 - ay1) b_maydon = (bx2 - bx1) * (by2 - by1) birlashma = a_maydon + b_maydon - kesishma return kesishma / birlashma if birlashma > 0 else 0.0 print("bir xil :", iou((0,0,100,100), (0,0,100,100))) print("yarmi :", iou((0,0,100,100), (50,0,150,100))) print("tegmaydi :", iou((0,0,100,100), (200,200,300,300))) print("ichida :", round(iou((0,0,100,100), (25,25,75,75)), 4))
Natija:
bir xil : 1.0 yarmi : 0.3333333333333333 tegmaydi : 0.0 ichida : 0.25
"Yarmi" 0.5 emas, 0.33 — bu ko'pchilikni ajablantiradi. Ikki quti yarmi bilan ustma-ust tushsa: kesishma 50x100=5000, birlashma 10000+10000-5000=15000. 5000/15000 = 0.33.
IoU maxrajda birlashmani ishlatadi, shuning uchun u har doim "ko'zga ko'ringan" ustma-ustlikdan kichikroq chiqadi.
max(0, ...) qatorlari muhim. Qutilar kesishmasa, farq
manfiy chiqadi va usiz IoU ham manfiy bo'lardi — bu mantiqsiz.
IoU qanday o'qiladi:
| IoU | Ma'nosi |
|---|---|
| 1.0 | aynan bir xil |
| 0.5 dan yuqori | odatda "to'g'ri topilgan" hisoblanadi |
| 0.0 | umuman tegmaydi |
0.5 chegarasi shartli — COCO datasetida 0.5 dan 0.95 gacha
bir nechta chegarada o'lchanadi.
NMS — takroriy qutilarni o'chirish
Model bitta obyekt uchun bir nechta quti qaytaradi. Ular deyarli bir xil joyda.
NMS (Non-Maximum Suppression) shularni tozalaydi:
def nms(qutilar, ballar, chegara=0.5): """Ustma-ust tushgan qutilardan eng yaxshisini qoldiradi.""" if not qutilar: return [] # Ball bo'yicha kamayish tartibida tartib = sorted(range(len(qutilar)), key=lambda i: ballar[i], reverse=True) saqlangan = [] while tartib: eng_yaxshi = tartib.pop(0) saqlangan.append(eng_yaxshi) # Unga juda o'xshaganlarni tashlaymiz tartib = [i for i in tartib if iou(qutilar[eng_yaxshi], qutilar[i]) < chegara] return saqlangan qutilar = [(10,10,110,110), (12,12,112,112), (300,300,400,400)] ballar = [0.9, 0.85, 0.95] qolgan = nms(qutilar, ballar) print("qolgan indekslar:", qolgan) for i in qolgan: print(f" quti {i}: {qutilar[i]} ball {ballar[i]}")
Natija:
qolgan indekslar: [2, 0] quti 2: (300, 300, 400, 400) ball 0.95 quti 0: (10, 10, 110, 110) ball 0.9
Uchtadan ikkitasi qoldi. 1-quti (ball 0.85) o'chirildi — u 0-quti bilan deyarli bir xil edi, lekin balli pastroq.
Diqqat: natija ball tartibida, asl tartibda emas.
Birinchi ikkita quti deyarli bir xil — NMS bittasini o'chiradi. Uchinchisi uzoqda, shuning uchun qoladi.
Chegara ta'siri:
- past chegara (0.3) — ko'proq o'chiradi, yaqin obyektlar yo'qolishi mumkin
- baland chegara (0.7) — kamroq o'chiradi, takroriy qutilar qoladi
Olomon ichidagi odamlarni aniqlashda bu muammo: ular haqiqatan ustma-ust turadi.
YOLO g'oyasi — bitta o'tishda
Eski usullar rasmni minglab marta tekshirardi (sliding window). YOLO — You Only Look Once — bitta o'tishda hammasini bashorat qiladi.
G'oya: rasmni katakchalarga bo'lamiz.
def yolo_setka(rasm_olcham=416, setka=13): """Har bir katakcha qancha piksel qamrab oladi.""" katak = rasm_olcham // setka print(f"rasm {rasm_olcham}x{rasm_olcham}, setka {setka}x{setka}") print(f"har bir katak: {katak}x{katak} piksel") print(f"jami katak: {setka * setka}") return katak yolo_setka()
Har bir katakcha javob beradi: "menda obyekt markazi bormi? Bo'lsa — qaysi sinf va quti qanday?"
Anchor box — har bir katakcha bir nechta oldindan belgilangan shakldagi qutini sinaydi (uzun, keng, kvadrat). Chunki odam tik, mashina keng.
Amalda: tayyor modeldan foydalanish
YOLO ni noldan o'qitish uchun katta dataset va GPU kerak. Amalda tayyor model ishlatiladi:
# parcha — ultralytics o'rnatilgan bo'lishi kerak from ultralytics import YOLO model = YOLO("yolov8n.pt") # n = nano, eng kichik natijalar = model("rasm.jpg") for r in natijalar: for quti in r.boxes: sinf = model.names[int(quti.cls)] ball = float(quti.conf) x1, y1, x2, y2 = quti.xyxy[0].tolist() print(f"{sinf}: {ball:.2f} ({x1:.0f},{y1:.0f})-({x2:.0f},{y2:.0f})")
O'rnatish: pip install ultralytics
yolov8n — nano versiya, ~6 MB, CPU da ham ishlaydi.
Kattaroqlari: s, m, l, x — aniqroq, lekin sekinroq.
Hujjat uchun: aniqlash kerakmi?
Ko'p hollarda YO'Q. 3-bobdagi morfologiya usuli oddiy hujjatlar uchun yetarli va u:
- o'qitish talab qilmaydi
- CPU da bir zumda ishlaydi
- tushuntirib beriladi
Aniqlash quyidagi hollarda kerak:
- hujjat formati juda xilma-xil
- muhr, imzo, logotip topish kerak
- jadval va rasm aralash sahifa
Amaliy tartib: avval morfologiya bilan sinang. Ishlamasa, keyin aniqlash modeliga o'ting.
O'z ma'lumotingizda o'qitish
Agar aniqlash kerak bo'lsa, belgilash formati:
# har bir rasm uchun bitta .txt fayl # sinf_id cx cy w h (hammasi 0-1 oralig'ida) 0 0.412 0.305 0.250 0.200 1 0.700 0.650 0.180 0.120
Belgilash uchun labelImg yoki CVAT ishlatiladi.
Nechta rasm kerak: har bir sinf uchun kamida 100–200 belgilangan misol. Kamroq bo'lsa transfer learning ham yordam bermaydi.
Bu — eng ko'p vaqt oladigan qism. Model o'qitish bir soat, belgilash esa bir hafta bo'lishi mumkin.
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.