Asosiy qismga o'tish

O'lcham, burish va perspektiva

4-bob 6 kod bloki 1622 so'z

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.

python16 qator
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))
Chiqish
asl: 2560 x 1440
usulvaqt, mskeskinlik (Laplacian var)qaytarishdagi xato
INTER_NEAREST0.083 9058.18
INTER_LINEAR0.13 1855.03
INTER_AREA0.571 7684.91
INTER_CUBIC0.173 9815.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:

python6 qator
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.

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

python13 qator
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.")
Chiqish
asl: (960, 540) | oddiy burish: (960, 540) | kengaytirilgan: (1086, 835)

warpAffine chiqish o'lchamini o'zi hisoblamaydi: aytmasangiz, burchaklar rasmdan chiqib ketadi.

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:

python7 qator
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.")
Chiqish
affin matritsasi (2x3):
 [[  0.994   0.25  -59.524]
 [ -0.099   0.955  51.514]]

Uch nuqta uch tenglama beradi — 2x3 matritsa shundan chiqadi.

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:

python10 qator
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.

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:

python5 qator
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.

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

  1. qurilish.jpg ni 640 kenglikka nisbatni saqlab kichraytiring, keyin 640x640 letterbox qiling (qolgan joyni kulrang bilan). Natijaning shakli va qo'shilgan chegara balandligi qancha?
  2. Bitta rasmni 10 marta ketma-ket 90° ga bursangiz (warpAffine bilan), 10 marta cv2.rotate bilan burganingizdan farq qiladimi? Nega? (Maslahat: piksellar farqini np.abs(...).mean() bilan o'lchang.)
  3. hujjat.jpg ning burchaklarini 10 piksel xato bilan bering va natijani to'g'ri burchaklardagi bilan solishtiring. Matn o'qilishiga ta'sir qildimi?
  4. Perspektiv matritsani teskari qo'llang (cv2.invert yoki getPerspectiveTransform ni 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.

Telegramda yozish Narxlar