Merhabalar, bu yazımda Harris feature detector algoritmasını birlikte anlatacağım.
Harris Corner Detektörü, her piksel için her yönde süregelen yerel yoğunluk değişikliklerini ölçeklendirmeye çalışır. Daha genel ifadeyle belirli bi alan içerisindeki piksellerin baskın ortogonal gradyan yönlerinin seçilmesi işlemidir.
Genel hatlarıyla anlatmaya çalışacağım, ayrıca wiki üzerinden bakabilirsiniz genel yapısına. Yazının sonuna yardımcı linkler de ekledim.
Kod yazarken adımlarımız şu şekilde olacak:
1) İlk olarak Gauss filtersi uygula
2) x ve y yönlerinde gradyanlarını bul ve Ix Iy değişkenlerine ata
3) Harris algoritmasını uygulaya
- t değikeninde bir eşik değeri ve W değişkeninde sabit boyutlu pencere tanımla, sonrasında filtrelerle gradyanları (Ix,Iy) hesapla
- Belirlenen pencere(W) içerisindeki tüm piksellerde G matrisini1 hesapla
- Eğer en küçük tekil değer ro(G), t’den büyükse o pikseli feature point olarak işaretle
4) Feature’ların yerlerini orijinal resmin üzerine çizdir.
İlk olarak GaussianFilter fonksiyonumuzu yazıp görüntümüzü işleyelim.
def GaussianFilter(img): # 3x3 Gauss kerneli oluşturuyoruz kernel = np.ones((3,3), dtype='float64') size = 3 mean = int(size/2) sigma = 1 # standart sapmayı 1 olarak aldım sumAll = 0 for i in range(size): for j in range(size): kernel[i,j] = math.exp(-1* ((math.pow( (i-mean)/sigma, 2.0) + (math.pow((j-mean)/sigma, 2.0)) ) / (2* math.pow(sigma,2)) )) / (sigma * math.pow(2*math.pi, 1/2)) sumAll += kernel[i,j] # normalizing kernel for i in range(size): for j in range(size): kernel[i,j] /= sumAll # Oluşturulan kernel ile görüntümüzü konvolüsyona tabi tutuyoruz img = convolution(img, kernel) # filtered image
Son satırdaki konvolüsyon fonksiyonumuz ise:
def convolution(img, dest): #res = img [h,w] = img.shape [kh, kw] = dest.shape # kernel shape kr = int(kh/2) # kernel radius res = np.zeros(img.shape) sumAll2=0 for i in range(0+kr,h-kr): for j in range(0+kr,w-kr): for k in range(-1 * kr, kr + 1): for m in range(-1 * kr, kr + 1): res[i,j] += dest[k,m]*img[i+k, j+m] sumAll2+=res[i,j] res[i,j] /= sumAll2 res[:,0] = res[:, 1] res[:,w-1] = res[:, w-2] res[0,:] = res[1,:] res[h-1,:] = res[h-2,:] res=res.astype(np.uint8) return res
İkinci adımımız olan gradyanların hesaplanmasına geliyoruz. Aşağıdaki kod görüntü üzerinde x yönündeki min ve maks gradyanları çizdiriyor. Ardından gradient structure tensor(second-moment matrix) dediğimiz G matrisimizi hesaplıyoruz. Oluşan matrisin trace’ini calculateTrace() fonksiyonuyla hesaplıyoruz. En sonunda başta algoritmada belirttiğimiz t eşik değeri üzerinde olanları calculateThres() fonksiyonu yardımıyla çizdiriyoruz ve çıktımızı alıyoruz.
def calculateGradients(img): [h,w]= img.shape grad_x = np.zeros((h,w), dtype = 'float64') grad_y = np.zeros((h,w), dtype = 'float64') print('Gradyanlar hesaplanıyor') # piksel piksel türevleri hesaplıyoruz for i in range(h): for j in range(w): if(j >= w-1): # son kolonda grad_y[i,j] = (img[i,j] - img[i,j-1]) / 2 elif (j== 0): # ilk kolonda grad_y[i,j] = (img[i,j+1] - img[i,j]) / 2 else: # ilk ve son kolon arasında gezinirken grad_y[i,j] = (img[i,j+1] - img[i,j-1]) / 2 if(i >= h-1): # son satırda grad_x[i,j] = (img[i,j] - img[i-1,j]) / 2 elif (i== 0): # ilk satırda grad_x[i,j] = (img[i+1,j] - img[i,j]) / 2 else: # ilk ve son satır arasında grad_x[i,j] = (img[i+1,j] - img[i-1,j]) / 2 #gradyanlarımızı kaydetmek için dosya açıyoruz try: fP = open(('xgrad.txt'), 'w') maxGradX = 0 minGradX = 0 maxTuple = [0,0] minTuple = [0,0] for i in range(h): for j in range(w): fP.write(str(i) + ' ' + str(j) + ' ' + str(grad_x[i,j]) + '\n') if(grad_x[i,j] > maxGradX): maxGradX = grad_x[i,j] maxTuple = [i,j] if(grad_x[i,j] < minGradX): minGradX = grad_x[i,j] minTuple = [i,j] fP.close() # Burada yaptığımız şey x yönündeki # gradyanın minimum ve maksimum değerlerini # çizdirip kaydetmek pointed=img.copy() pointed[maxTuple[0],:] = 255 pointed[:,maxTuple[1]] = 255 pointed[minTuple[0],:] = 2 pointed[:,minTuple[1]] = 2 cv2.imwrite('pointed.jpg', pointed) except: print('cannot open file') structTensor = createStructureTensor(img, grad_x, grad_y) R = calculateTrace(img, structTensor) calculateThres(img,R) def calculateTrace(img,M): h,w = img.shape R = np.zeros((h,w), dtype = 'float64') k = 0.04 for x in range(h): for y in range(w): deter = M[x,y,0,0]*M[x,y,1,1] - (M[x,y,1,0] * M[x,y,1,0]) trace = M[x,y,0,0]+M[x,y,1,1] R[x,y] = (deter - (trace**2)*k) return R def calculateThres(img,R): h,w = img.shape corners = np.zeros((h,w,3),dtype=np.uint8) corners[:,:,0]=img corners[:,:,1]=img corners[:,:,2]=img t = 400000 for x in range(h): for y in range(w): if R[x,y] > t: corners[x,y] = [0,254,0] print(str(x) + ' ' + str(y) + ' ' + str (R[x,y])) # Köşeleri bulunmuş görüntümüzü çıktı olarak alıyoruz cv2.imwrite('result.jpg', corners) def createStructureTensor(img,Ix,Iy): h,w = img.shape structTensor = np.zeros((h,w,2,2),dtype='float64') Ixx = Ix*Ix Ixy = Ix*Iy Iyx = Iy*Ix Iyy = Iy*Iy for x in range(h): for y in range(w): for i in range(-1,2): for j in range(-1,2): if not(x+j<0 or x+j >= h or y+i <0 or y+i >= w): structTensor[x,y,0,0]+=Ixx[x+j][y+i] structTensor[x,y,0,1]+=Ixy[x+j][y+i] structTensor[x,y,1,0]+=Iyx[x+j][y+i] structTensor[x,y,1,1]+=Iyy[x+j][y+i] return structTensor import math import numpy as np import cv2 path="lena.jpg" inputImage = cv2.imread(path,cv2.IMREAD_GRAYSCALE) filtered = GaussianFilter(inputImage) # Birinci adım calculateGradients(filtered) #İkinci ve üçüncü adım
Yardımcı linkler:
https://en.wikipedia.org/wiki/Structure_tensor
https://www.youtube.com/watch?v=P35WsRDnTsU&t=41m12s
https://docs.opencv.org/3.4/d4/d70/tutorial_anisotropic_image_segmentation_by_a_gst.html
https://docs.opencv.org/3.4.2/dc/d0d/tutorial_py_features_harris.html