9. ünite / 12
Geometrik ve perspektif dönüşümler: döndür, ölçekle, düzle
Afin matris (2×3), getRotationMatrix2D, ara değerleme; homografi (3×3), dört nokta çifti ve belge düzleme.
Bu ünitenin sonunda
- Döndürme, ölçekleme ve kaydırmayı tek bir 2×3 afin matrisle yazmak
- Ters eşlemenin ve ara değerlemenin neden gerektiğini açıklamak
- Dört nokta çiftinden 3×3 homografiyi çözmek
- Eğik çekilmiş bir belgeyi yukarıdan bakılmış gibi düzlemek
Ders notları
Geometrik dönüşüm piksellerin değerini değil yerini değiştirir. Afin dönüşüm doğruları doğru, paralelleri paralel tutar ve 2×3 bir matrisle yazılır:
cv2.getRotationMatrix2D(merkez, açı, ölçek) bu matrisi verir; OpenCV'de pozitif açı saat yönünün tersidir. Afin dönüşüm üç nokta çiftinden de bulunur (getAffineTransform).
Ters eşleme ve ara değerleme
warpAffine her hedef pikseli ters matrisle kaynağa götürür ve oradan örnekler; ileri eşlemede hedefte delikler kalırdı. Kaynak konumu genelde tam sayı değildir: en yakın komşu hızlıdır ama basamaklı kenar verir, çift doğrusal dört komşunun ağırlıklı ortalamasıdır ve daha yumuşaktır.
Perspektif (homografi)
Bir düzleme açılı bakınca dikdörtgen yamuk görünür; paralellik bozulur. Bunu 3×3 bir homografi düzeltir: [x′w; y′w; w] = H·[x; y; 1]. H'nin 8 serbest değeri vardır; dört nokta çifti (her biri iki denklem) yeter: getPerspectiveTransform. Belge tarayıcıda dört köşe bulunur, sol üst–sağ üst–sağ alt–sol alt sırasına konur ve hedef dikdörtgene eşlenir.
Oyun alanları
Geometrik dönüşümler: döndür, ölçekle, kaydır
2×3 afin matrisi sağda. Açıyı, ölçeği ve kaydırmayı değiştir; ara değerleme (en yakın komşu ya da çift doğrusal) farkını kenarlarda gör.
Perspektif düzeltme (belge)
Belgenin dört köşesini sürükle ya da "Köşeleri bul" ile otomatik bulmasını iste. 3×3 homografi dört nokta çiftinden çözülür ve belge yukarıdan çekilmiş gibi düzlenir.
Köşeleri sürükle. Kırmızı nokta sol üst köşe olarak sıralandı.
3B masa ve sanal kamera
Masada A4 bir belge ve iğne deliği modeliyle bir kamera. Kamerayı yükselt, döndür, yaklaştır: görüntü bu kameradan gerçekten üretilir (her pikselin ışını masa düzlemiyle kesiştirilir). Sonra köşe bulma ve perspektif düzeltme aynı görüntüye uygulanır; gerçek köşelerle karşılaştırılır.
Kendin dene
Dönüşüm aracında açıyı 30°, ölçeği 1,5 yap ve matrisin a, b değerlerinin cos ve sin ile ilişkisini doğrula. Ara değerlemeyi en yakın komşuya çevirip yıldızın kenarındaki basamakları gör. Perspektif aracında köşeleri bul, sonra bir köşeyi bilerek 15 px kaydır: düzlenmiş belgede satırlar ne oldu? Kendi çektiğin eğik bir sayfa fotoğrafını yükle ve köşeleri elle yerleştir.
Kod
import cv2
import numpy as np
img = cv2.imread('girdi.png')
h, w = img.shape[:2]
M = cv2.getRotationMatrix2D((w / 2, h / 2), 30, 0.8) # merkez, açı (derece, saat yönü tersine), ölçek
M[:, 2] += (20, -10) # üstüne kaydırma
print('afin matris:', np.round(M, 3).tolist())
near = cv2.warpAffine(img, M, (w, h), flags=cv2.INTER_NEAREST)
lin = cv2.warpAffine(img, M, (w, h), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
x, y = 10, 10
print('(10,10) ->', np.round(M @ np.array([x, y, 1.0]), 1)) # bir noktayı dönüştür
Minv = cv2.invertAffineTransform(M) # geri dönüşüm
back = cv2.warpAffine(lin, Minv, (w, h))
cv2.imwrite('cikti.png', np.hstack([near, lin, back]))import cv2
import numpy as np
def order(pts):
s, d = pts.sum(1), np.diff(pts, axis=1).ravel()
return np.float32([pts[s.argmin()], pts[d.argmin()], pts[s.argmax()], pts[d.argmax()]]) # sol üst, sağ üst, sağ alt, sol alt
img = cv2.imread('girdi.png')
gray = cv2.GaussianBlur(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY), (5, 5), 0)
edges = cv2.dilate(cv2.Canny(gray, 50, 150), None)
cnts, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
quad = None
for cnt in sorted(cnts, key=cv2.contourArea, reverse=True)[:5]:
approx = cv2.approxPolyDP(cnt, 0.02 * cv2.arcLength(cnt, True), True)
if len(approx) == 4: # ilk dört köşeli büyük kontur: belge
quad = order(approx.reshape(4, 2).astype(np.float32))
break
h, w = img.shape[:2]
if quad is None:
quad = np.float32([[0, 0], [w - 1, 0], [w - 1, h - 1], [0, h - 1]]) # bulunamazsa tüm görüntü
W, H = 420, 594 # A4 oranı (1 : 1,414)
dst = np.float32([[0, 0], [W - 1, 0], [W - 1, H - 1], [0, H - 1]])
Hm = cv2.getPerspectiveTransform(quad, dst) # 4 nokta çifti: 8 bilinmeyen
print('köşeler:', quad.astype(int).tolist())
print('homografi:', np.round(Hm, 3).tolist())
cv2.imwrite('cikti.png', cv2.warpPerspective(img, Hm, (W, H)))Sık yapılan hatalar
- Köşe sırasını karıştırmak: dört nokta çapraz eşlenirse düzlenmiş görüntü ters ya da kelebek biçiminde çıkar. Önce sırala.
- warpAffine'e (yükseklik, genişlik) vermek: dsize (genişlik, yükseklik) ister.
- Döndürmede görüntünün köşelerinin kesildiğini fark etmemek: yeni boyutu cos/sin ile hesaplayıp matrisin kaydırmasını düzelt.
- Perspektifi afinle düzeltmeye çalışmak: afin paralellikleri korur, yamuk bir sayfayı düzeltemez.
Yazılım mühendisliği bağlantısı
Geometri kodunda birim ve koordinat sistemi karışıklığı (x/y, satır/sütun, derece/radyan) en sık hata kaynağıdır.
- Gidiş-dönüş testi yaz: bir noktayı H ile götür, H⁻¹ ile geri getir; aynı nokta olmalı.
- Dört köşenin hedefe tam oturduğunu sınayan bir test, köşe sıralama hatalarını anında yakalar.
Kendini sına
Bir homografiyi (3×3, ölçek serbest) çözmek için en az kaç nokta çifti gerekir?
warpAffine neden ters eşleme kullanır?
Afin dönüşüm hangi özelliği korur?
Eğik çekilmiş bir sayfayı düzlemek için hangisi gerekir?
Bu üniteden sonra bitirme projesinde
- Düzleme ve tarama: duzle ve taranmis; G3 ve G4 ölçümleri, elle köşe girişi (G2).