Я пытаюсь реализовать алгоритм обнаружения углов Харриса с нуля, но не смог реализовать не максимальное подавление

Я пытаюсь реализовать алгоритм обнаружения углов Харриса с нуля. Предполагается, что на выходе этого алгоритма должен быть один пиксель, представляющий угол, но в моем коде я получаю несколько пикселей, представляющих угол. Это может быть из-за того, что не реализована заключительная часть алгоритма non-maximum suppression. Это я не смог реализовать, потому что я не понял этого должным образом. Как это реализовать? Наряду с этим я также пытаюсь найти координаты этих углов, как это сделать без использования библиотеки cv2? изображение, используемое для кода Харриса

import numpy as np
import matplotlib.pyplot as plt  
import matplotlib.image as im   



# 1. Before doing any operations convert the image into gray scale image

img = im.imread('OD6.jpg')
plt.imshow(img)
plt.show()

# split
R=img[:,:,0]
G=img[:,:,1]
B=img[:,:,2]


M,N=R.shape

gray_img=np.zeros((M,N), dtype=int);

for i in range(M):                     
        for j in range(N):
            gray_img[i, j]=(R[i, j]*0.2989)+(G[i, j]*0.5870)+(B[i, j]*0.114);

plt.imshow(gray_img, cmap='gray')
plt.show()

# 2. Applying sobel filter to get the gradients of the images in x and y directions

sobelx = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype = np.float)
sobely = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]], dtype = np.float)


sobelxImage = np.zeros((M,N))
sobelyImage = np.zeros((M,N))
sobelGrad = np.zeros((M,N))

image = np.pad(gray_img, (1,1), 'edge')

for i in range(1, M-1):
    for j in range(1, N-1):        
        gx = (sobelx[0][0] * image[i-1][j-1]) + (sobelx[0][1] * image[i-1][j]) + \
             (sobelx[0][2] * image[i-1][j+1]) + (sobelx[1][0] * image[i][j-1]) + \
             (sobelx[1][1] * image[i][j]) + (sobelx[1][2] * image[i][j+1]) + \
             (sobelx[2][0] * image[i+1][j-1]) + (sobelx[2][1] * image[i+1][j]) + \
             (sobelx[2][2] * image[i+1][j+1])

        gy = (sobely[0][0] * image[i-1][j-1]) + (sobely[0][1] * image[i-1][j]) + \
             (sobely[0][2] * image[i-1][j+1]) + (sobely[1][0] * image[i][j-1]) + \
             (sobely[1][1] * image[i][j]) + (sobely[1][2] * image[i][j+1]) + \
             (sobely[2][0] * image[i+1][j-1]) + (sobely[2][1] * image[i+1][j]) + \
             (sobely[2][2] * image[i+1][j+1])     

        sobelxImage[i-1][j-1] = gx
        sobelyImage[i-1][j-1] = gy
        g = np.sqrt(gx * gx + gy * gy)
        sobelGrad[i-1][j-1] = g

sobelxyImage = np.multiply(sobelxImage, sobelyImage)

# 3 Apply gaussian filter along x y and xy
        
size=3;# define the filter size
sigma=1; # define the standard deviation
size = int(size) // 2
xx, yy = np.mgrid[-size:size+1, -size:size+1]
normal = 1 / (2.0 * np.pi * sigma**2)
gg =  np.exp(-((xx**2 + yy**2) / (2.0*sigma**2))) * normal

gaussx =gg
gaussy =gg

gaussxImage = np.zeros((M,N))
gaussyImage = np.zeros((M,N))
gaussxyImage = np.zeros((M,N))
gaussresult = np.zeros((M,N))

gaussimagex = np.pad(sobelxImage, (1,1), 'edge')
gaussimagey = np.pad(sobelyImage, (1,1), 'edge')
gaussimagexy = np.pad(sobelxyImage, (1,1), 'edge')


for i in range(1, M-1):
    for j in range(1, N-1):        
        ggx = (gaussx[0][0] * gaussimagex[i-1][j-1]) + (gaussx[0][1] *gaussimagex[i-1][j]) + \
             (gaussx[0][2] * gaussimagex[i-1][j+1]) + (gaussx[1][0] * gaussimagex[i][j-1]) + \
             (gaussx[1][1] * gaussimagex[i][j]) + (gaussx[1][2] * gaussimagex[i][j+1]) + \
             (gaussx[2][0] * gaussimagex[i+1][j-1]) + (gaussx[2][1] * gaussimagex[i+1][j]) + \
             (gaussx[2][2] * gaussimagex[i+1][j+1])

        ggy = (gaussy[0][0] * gaussimagey[i-1][j-1]) + (gaussy[0][1] * gaussimagey[i-1][j]) + \
             (gaussy[0][2] * gaussimagey[i-1][j+1]) + (gaussy[1][0] * gaussimagey[i][j-1]) + \
             (gaussy[1][1] * gaussimagey[i][j]) + (gaussy[1][2] * gaussimagey[i][j+1]) + \
             (gaussy[2][0] * gaussimagey[i+1][j-1]) + (gaussy[2][1] * gaussimagey[i+1][j]) + \
             (gaussy[2][2] * gaussimagey[i+1][j+1])
             
        crossgg = (gg[0][0] * gaussimagexy[i-1][j-1]) + (gg[0][1] * gaussimagexy[i-1][j]) + \
             (gg[0][2] * gaussimagexy[i-1][j+1]) + (gg[1][0] * gaussimagexy[i][j-1]) + \
             (gg[1][1] * gaussimagexy[i][j]) + (gg[1][2] * gaussimagexy[i][j+1]) + \
             (gg[2][0] * gaussimagexy[i+1][j-1]) + (gg[2][1] * gaussimagexy[i+1][j]) + \
             (gg[2][2] * gaussimagexy[i+1][j+1])     

        gaussxImage[i-1][j-1] = ggx
        gaussyImage[i-1][j-1] = ggy
        gaussxyImage[i-1][j-1] = crossgg
        blur = np.sqrt(ggx * ggx + ggy * ggy)
        gaussresult[i-1][j-1] = blur



det = gaussxImage *gaussyImage - (gaussxyImage ** 2)

alpha = 0.04
trace = alpha * (gaussxImage +gaussyImage) ** 2

#finding the harris response
R = det - trace

# applying threshold
for i in range(1, M-1):
    for j in range(1, N-1):
        if  R[i][j] > 140:
            R[i][j]==0
        else:
            R[i][j]==255


f, ax1 = plt.subplots(1, 1, figsize=(5,5))

ax1.set_title('corners')
ax1.imshow(R, cmap="gray")

person acoustic python    schedule 13.11.2020    source источник
comment
В разделе 3 этой старой, но классической статьи представлен немаксимальный алгоритм подавления, который легко понять и реализовать. Я думаю, он даст вам хорошую основу для начала: graphics.cs.cmu.edu/courses/15-463/2006_fall/www/Papers/   -  person Ash    schedule 13.11.2020
comment
Я читал, но многого не понял. Не могли бы вы проинформировать один раз.   -  person acoustic python    schedule 13.11.2020
comment
Существует множество реализаций с открытым исходным кодом. Вы изучали их, чтобы увидеть, как они это реализуют? Это может сильно помочь вам в понимании алгоритма.   -  person Cris Luengo    schedule 13.11.2020
comment
@CrisLuengo, я просмотрел некоторые реализации, но кое-что понял. Я только начал программировать, исходя из своего понимания теории. Я делаю некоторые ошибки в своей программе, как указал Эш.   -  person acoustic python    schedule 14.11.2020


Ответы (1)


Прежде всего, в вашем коде есть пара ошибок:

  • Часть R[i][j]==0 в последнем цикле пороговой обработки должна быть R[i][j]=0. Обратите внимание, что вам не нужно проходить цикл, вы можете просто сделать что-то вроде R[R>thresh]=255 и т. д.

  • Если я не ошибаюсь, значения R, соответствующие углам в алгоритме Харриса, являются большими положительными. Когда я запускаю ваш код, я получаю значения R, которые являются отрицательными для краев и углов, поэтому я подозреваю, что где-то здесь есть ошибка.

На данный момент я не думаю, что основной проблемой в вашем коде является подавление немаксимумов, но если это все же так, вот краткое объяснение подавления немаксимумов и статья, которую мы обсуждали в комментариях:

По сути, идея немаксимального подавления очень проста: если (угловой) отклик точки x не самый высокий в окрестности (которую вы можете определить в зависимости от ваших потребностей), то вы не сохраняете ее. . В вашем случае, вероятно, будет просто достаточно сравнить отклик каждой из обнаруженных вами точек интереса с откликом ближайших соседей и оставить их только в том случае, если они выше по отношению ко всем из них. Что касается статьи, которую мы обсуждали, ее цель состоит в том, чтобы подавить ключевые точки (которые не являются локальными максимумами) таким образом, чтобы получить более равномерное пространственное распределение. Пусть S будет ключевыми точками, отсортированными в порядке убывания отклика угла. Идея состоит в том, чтобы назначить каждому из них радиус подавления, то есть радиус, в котором эти точки не будут считаться локальным максимумом. Так как S[0] имеет самый высокий угол отклика на изображении, он никогда не будет подавляться, поэтому вы можете установить для него радиус подавления radius_list[0]=inf. Далее, давайте посмотрим на S[1]. Поскольку список S отсортирован, единственной точкой с наивысшим откликом, чем S[1], является S[0], и из этого следует, что радиус, при котором S[1] перестает быть локальным максимумом, равен Dist(S[1], S[2]). То есть, как только мы включим S[0] в локальную окрестность S[1], поскольку response[S[0]]>response[S[1]], S[0] станет максимальным в этой окрестности. Обратите внимание, что по мере того, как вы продолжаете в том же духе, радиусы, которые вы считаете, будут становиться все меньше и меньше. После того, как вы вычислили radius_list, предполагая, что вам нужно N характерных точек, вы просто выберете N точек, которые имеют самые высокие значения radius_list. В псевдокоде:

#let S be the keypoints, sorted in decreasing corner response order
#Assume you want only to keep N keypoints at the end
radius=zeros(len(S))
radius[0]=inf
for i in range(len(S[1:])):
    candidate_radii=[]
    for j in range(0,i):
        if response[i]<response[j]*some_const:#you can set some_const to something in [0.9,1]
            candidate_radii.append(image_space_dist(S[i],S[j]))
    radius[i]=min(candidate_radii)

sorted_indexes = argsort(radius)
kept_points = S[sorted_indexes][:N]
    

Надеюсь это поможет.

person Ash    schedule 13.11.2020
comment
вы прокомментировали что-то о том, что R является большим положительным, поскольку вы упомянули об этом отрицательном, я посмотрел на матрицу R, которая, на самом деле, отрицательная. Надеюсь, я правильно применил фильтр, я прав? - person acoustic python; 16.11.2020