O'lcham, burish va perspektiva
Kichraytirish — eng ko'p ishlatiladigan amal
Model 640x640 kutadi, kamera 2560x1440 beradi. Kichraytirish har bir quvurda bor, va u tekin emas: hisob tezlashadi, tafsilot yo'qoladi.
import time katta = cv2.imread(str(RASM / "qurilish.jpg")) print("asl:", katta.shape[1], "x", katta.shape[0]) qatorlar = [] for nom, usul in [("INTER_NEAREST", cv2.INTER_NEAREST), ("INTER_LINEAR", cv2.INTER_LINEAR), ("INTER_AREA", cv2.INTER_AREA), ("INTER_CUBIC", cv2.INTER_CUBIC)]: t0 = time.perf_counter() for _ in range(20): kichik = cv2.resize(katta, (640, 360), interpolation=usul) ms = (time.perf_counter() - t0) / 20 * 1000 keskinlik = cv2.Laplacian(cv2.cvtColor(kichik, cv2.COLOR_BGR2GRAY), cv2.CV_64F).var() qayta = cv2.resize(kichik, (katta.shape[1], katta.shape[0]), interpolation=cv2.INTER_CUBIC) xato = float(np.abs(katta.astype(np.int16) - qayta.astype(np.int16)).mean()) qatorlar.append({"usul": nom, "vaqt, ms": round(ms, 2), "keskinlik (Laplacian var)": round(keskinlik), "qaytarishdagi xato": round(xato, 2)}) show(pd.DataFrame(qatorlar))
asl: 2560 x 1440
| usul | vaqt, ms | keskinlik (Laplacian var) | qaytarishdagi xato |
|---|---|---|---|
| INTER_NEAREST | 0.08 | 3 905 | 8.18 |
| INTER_LINEAR | 0.1 | 3 185 | 5.03 |
| INTER_AREA | 0.57 | 1 768 | 4.91 |
| INTER_CUBIC | 0.17 | 3 981 | 5.35 |
Ikki ustunni birga o'qish kerak, chunki ular qarama-qarshi javob berayotgandek ko'rinadi.
"Keskinlik" ustuni bo'yicha INTER_NEAREST yuqorida (3 905), INTER_AREA esa eng pastda (1 768). Bu
INTER_NEAREST yaxshi degani emas. Laplacian dispersiyasi keskin o'tishlarni sanaydi, va NEAREST
kichraytirganda soxta keskinlik yasaydi: u piksellarni o'rtachalamasdan tashlab yuboradi, natijada tishli
("zinapoyali") chekkalar paydo bo'ladi. Metrika ularni "tafsilot" deb hisoblaydi, ko'z esa buzilish deb ko'radi.
Shuning uchun ikkinchi o'lchov qo'shildi: rasmni kichraytirib, yana asl o'lchamga qaytaramiz va asl bilan
farqini o'lchaymiz. Bu yerda INTER_AREA eng kam xato beradi — demak u ma'lumotni eng yaxshi saqlagan.
Xulosa: kichraytirish uchun INTER_AREA (sohadagi piksellar o'rtachasi olinadi), kattalashtirish uchun
INTER_CUBIC yoki INTER_LINEAR. INTER_NEAREST faqat maska va segmentatsiya yorliqlari uchun — u yerda
oraliq qiymat yasash mumkin emas (0.5-sinf degani yo'q).
Va umumiy saboq: bitta metrikaga qarab qaror qilmang. "Keskinroq" har doim "yaxshiroq" degani emas.
Farqni ko'rish uchun kichik bo'lakni kattalashtiramiz:
bolak = katta[560:640, 980:1060] # 80x80 piksel a = cv2.resize(bolak, (320, 320), interpolation=cv2.INTER_NEAREST) b = cv2.resize(bolak, (320, 320), interpolation=cv2.INTER_LINEAR) c = cv2.resize(bolak, (320, 320), interpolation=cv2.INTER_CUBIC) ko_rsat(a, b, c, nom="interpolatsiya.png", sarlavhalar=["NEAREST — kvadratlar", "LINEAR — silliq", "CUBIC — silliqroq"], izoh="80x80 bo'lak 4 barobar kattalashtirildi. NEAREST piksellarni ko'rsatadi, CUBIC chekkalarni yumshatadi.")

80x80 bo'lak 4 barobar kattalashtirildi. NEAREST piksellarni ko'rsatadi, CUBIC chekkalarni yumshatadi.
:::tip Nisbatni saqlang
cv2.resize(img, (640, 360)) nisbatni buzishi mumkin. To'g'ri yo'l: bitta o'lchamni belgilab, ikkinchisini
hisoblash — h = int(w * img.shape[0] / img.shape[1]). Model uchun kvadrat kerak bo'lsa, cho'zish o'rniga
letterbox qiling: nisbatni saqlab kichraytirib, qolgan joyni bo'yash (YOLO shunday qiladi).
:::
Burish: markaz, burchak, masshtab
img = cv2.imread(str(RASM / "qurilish_kichik.jpg")) h, w = img.shape[:2] M = cv2.getRotationMatrix2D((w / 2, h / 2), 20, 1.0) # markaz, 20 daraja, masshtab 1 burilgan = cv2.warpAffine(img, M, (w, h)) # burchaklar kesilmasligi uchun yangi o'lchamni hisoblaymiz cos, sin = abs(M[0, 0]), abs(M[0, 1]) yangi_w, yangi_h = int(h * sin + w * cos), int(h * cos + w * sin) M[0, 2] += yangi_w / 2 - w / 2 M[1, 2] += yangi_h / 2 - h / 2 toliq = cv2.warpAffine(img, M, (yangi_w, yangi_h)) print("asl:", (w, h), "| oddiy burish:", burilgan.shape[1::-1], "| kengaytirilgan:", toliq.shape[1::-1]) ko_rsat(burilgan, toliq, nom="burish.png", sarlavhalar=["20° — burchaklar kesildi", "tuval kattalashtirildi"], izoh="warpAffine chiqish o'lchamini o'zi hisoblamaydi: aytmasangiz, burchaklar rasmdan chiqib ketadi.")
asl: (960, 540) | oddiy burish: (960, 540) | kengaytirilgan: (1086, 835)

warpAffine chiqish o'lchamini o'zi hisoblamaydi: aytmasangiz, burchaklar rasmdan chiqib ketadi.
90, 180, 270 daraja uchun matritsa shart emas — cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) tezroq va
aniqroq (interpolatsiya umuman bo'lmaydi).
Affin: uchta nuqta yetarli
Affin almashtirish to'g'ri chiziqlarni to'g'ri qoldiradi va parallellikni saqlaydi (siljish, burish, masshtab, qiyshaytirish). Uni aniqlash uchun uchta nuqtaning qayerga ko'chishini bilish kifoya:
manba = np.float32([[80, 80], [880, 100], [100, 480]]) nishon = np.float32([[40, 120], [840, 60], [160, 500]]) A = cv2.getAffineTransform(manba, nishon) affin = cv2.warpAffine(img, A, (w, h)) print("affin matritsasi (2x3):\n", np.round(A, 3)) ko_rsat(img, affin, nom="affin.png", sarlavhalar=["asl", "affin: qiyshaytirish + siljish"], izoh="Uch nuqta uch tenglama beradi — 2x3 matritsa shundan chiqadi.")
affin matritsasi (2x3): [[ 0.994 0.25 -59.524] [ -0.099 0.955 51.514]]

Uch nuqta uch tenglama beradi — 2x3 matritsa shundan chiqadi.
Perspektiva: to'rtta nuqta
Perspektiv almashtirish parallellikni saqlamaydi — aynan shu bizga kerak, chunki telefonda qiyshiq olingan hujjat shunday buziladi. To'rt burchakni to'g'rilasak, "skaner" effekti chiqadi:
hujjat = cv2.imread(str(RASM / "hujjat.jpg")) burchaklar = np.float32([[150, 90], [720, 170], [650, 940], [90, 830]]) # varaqning 4 burchagi kenglik, balandlik = 640, 900 nishon = np.float32([[0, 0], [kenglik, 0], [kenglik, balandlik], [0, balandlik]]) P = cv2.getPerspectiveTransform(burchaklar, nishon) togrilangan = cv2.warpPerspective(hujjat, P, (kenglik, balandlik)) belgili = hujjat.copy() cv2.polylines(belgili, [burchaklar.astype(int)], True, (0, 255, 0), 3) ko_rsat(belgili, togrilangan, nom="perspektiva.png", sarlavhalar=["topilgan 4 burchak", "to'g'rilangan varaq"], izoh="getPerspectiveTransform 4 nuqtadan 3x3 matritsa yasaydi; warpPerspective uni qo'llaydi.")

getPerspectiveTransform 4 nuqtadan 3x3 matritsa yasaydi; warpPerspective uni qo'llaydi.
Bu yerda burchaklarni qo'lda yozdik. 17-bobdagi loyihada ularni avtomatik topamiz: chekka → kontur → eng katta to'rtburchak. Shundan keyin hujjat skaneri tayyor bo'ladi.
:::gotcha Burchaklar tartibi muhim
getPerspectiveTransform nuqtalarni bir xil tartibda kutadi: manba va nishon da ham yuqori-chap,
yuqori-o'ng, past-o'ng, past-chap. Tartib aralashsa, rasm ag'darilgan yoki ko'zguga tushgan bo'lib chiqadi.
Konturdan olingan nuqtalarni tartiblash uchun: yig'indisi (x+y) eng kichigi — yuqori-chap, eng kattasi —
past-o'ng; ayirmasi (y−x) bo'yicha qolgan ikkitasi ajratiladi.
:::
Chegara qo'shish
Model kvadrat kutganda yoki filtr chekkada joy talab qilganda:
kichik = cv2.resize(img, (320, 180)) usullar = {"CONSTANT": cv2.BORDER_CONSTANT, "REPLICATE": cv2.BORDER_REPLICATE, "REFLECT": cv2.BORDER_REFLECT} rasmlar = [cv2.copyMakeBorder(kichik, 40, 40, 40, 40, t, value=(0, 0, 0)) for t in usullar.values()] ko_rsat(*rasmlar, nom="chegara.png", sarlavhalar=list(usullar), kenglik=13, izoh="CONSTANT — bir xil rang (letterbox uchun), REPLICATE — chekka pikselni cho'zadi, REFLECT — ko'zgu.")

CONSTANT — bir xil rang (letterbox uchun), REPLICATE — chekka pikselni cho'zadi, REFLECT — ko'zgu.
Filtrlar (keyingi boblar) chekkada nima qilishni bilishi kerak — ularning borderType argumenti aynan shu.
Xulosa
| Tushuncha | Asosiy fikr |
|---|---|
| Kichraytirish | INTER_AREA — sifat va tezlik bo'yicha eng to'g'ri tanlov |
| Kattalashtirish | INTER_CUBIC / INTER_LINEAR; NEAREST kvadratlar beradi |
| Nisbat | Cho'zmang: bitta o'lchamdan ikkinchisini hisoblang yoki letterbox qiling |
| Burish | getRotationMatrix2D + warpAffine; tuval o'lchamini o'zingiz hisoblang |
| 90° | cv2.rotate — interpolatsiyasiz va tez |
| Affin | 3 nuqta, parallellik saqlanadi |
| Perspektiva | 4 nuqta, parallellik buziladi — hujjatni to'g'rilash uchun |
| Chegara | copyMakeBorder: CONSTANT, REPLICATE, REFLECT |
Talaba ishi
qurilish.jpgni 640 kenglikka nisbatni saqlab kichraytiring, keyin 640x640 letterbox qiling (qolgan joyni kulrang bilan). Natijaning shakli va qo'shilgan chegara balandligi qancha?- Bitta rasmni 10 marta ketma-ket 90° ga bursangiz (
warpAffinebilan), 10 martacv2.rotatebilan burganingizdan farq qiladimi? Nega? (Maslahat: piksellar farqininp.abs(...).mean()bilan o'lchang.) hujjat.jpgning burchaklarini 10 piksel xato bilan bering va natijani to'g'ri burchaklardagi bilan solishtiring. Matn o'qilishiga ta'sir qildimi?- Perspektiv matritsani teskari qo'llang (
cv2.invertyokigetPerspectiveTransformni teskari tartibda) va to'g'rilangan varaqni yana qiyshaytiring. Asl rasm bilan farqi qancha?
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.