На первый взгляд, для человеческого глаза есть 4 угла. Но в компьютерном зрении угол считается точкой, в которой интенсивность градиента изменяется по всей его окрестности. Окрестность может быть 4-пиксельной или 8-пиксельной.
В уравнении, указанном для нахождения градиента интенсивности, он был рассмотрен для 4-пиксельной окрестности СМ. ДОКУМЕНТАЦИЯ .
Вот мой подход к рассматриваемому изображению. У меня также есть код на Python:
path = r'C:\Users\selwyn77\Desktop\Stack\corner'
filename = 'env.jpg'
img = cv2.imread(os.path.join(path, filename))
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #--- convert to grayscale
Это хороший выбор, чтобы всегда размыть изображение, чтобы удалить менее возможные изменения градиента и сохранить более интенсивные. Я решил выбрать двусторонний фильтр , который в отличие от фильтра Гаусса не размывает все пиксели в окрестности. Это скорее размывает пиксели, которые имеют интенсивность пикселей, аналогичную интенсивности центрального пикселя. Короче говоря, он сохраняет края / углы с высоким изменением градиента, но размывает области с минимальными изменениями градиента.
bi = cv2.bilateralFilter(gray, 5, 75, 75)
cv2.imshow('bi',bi)
Для человека это не такая большая разница по сравнению с исходным изображением. Но это имеет значение. Теперь находим возможные углы:
dst = cv2.cornerHarris(bi, 2, 3, 0.04)
dst
возвращает массив (той же 2D-формы изображения) с собственными значениями, полученными из упомянутого окончательного уравнения ЗДЕСЬ .
Теперь необходимо применить порог, чтобы выбрать те углы, которые выходят за пределы определенного значения. Я буду использовать один в документации:
#--- create a black image to see where those corners occur ---
mask = np.zeros_like(gray)
#--- applying a threshold and turning those pixels above the threshold to white ---
mask[dst>0.01*dst.max()] = 255
cv2.imshow('mask', mask)
Белые пиксели - это области возможных углов. Вы можете найти много углов, соседствующих друг с другом.
Чтобы нарисовать выбранные углы на изображении:
img[dst > 0.01 * dst.max()] = [0, 0, 255] #--- [0, 0, 255] --> Red ---
cv2.imshow('dst', img)
(пиксели красного цвета - углы, не очень заметные)
Чтобы получить массив всех пикселей с углами:
coordinates = np.argwhere(mask)
UPDATE
Переменная coor
- это массив массивов. Преобразование его в список списков
coor_list = [l.tolist() for l in list(coor)]
Преобразование вышеупомянутого в список кортежей
coor_tuples = [tuple(l) for l in coor_list]
У меня есть простой и довольно наивный способ найти 4 угла. Я просто рассчитал расстояние каждого угла до каждого другого угла. Я сохранил те углы, расстояние которых превышало определенный порог.
Вот код:
thresh = 50
def distance(pt1, pt2):
(x1, y1), (x2, y2) = pt1, pt2
dist = math.sqrt( (x2 - x1)**2 + (y2 - y1)**2 )
return dist
coor_tuples_copy = coor_tuples
i = 1
for pt1 in coor_tuples:
print(' I :', i)
for pt2 in coor_tuples[i::1]:
print(pt1, pt2)
print('Distance :', distance(pt1, pt2))
if(distance(pt1, pt2) < thresh):
coor_tuples_copy.remove(pt2)
i+=1
До запуска фрагмента выше coor_tuples
имел все угловые точки:
[(4, 42),
(4, 43),
(5, 43),
(5, 44),
(6, 44),
(7, 219),
(133, 36),
(133, 37),
(133, 38),
(134, 37),
(135, 224),
(135, 225),
(136, 225),
(136, 226),
(137, 225),
(137, 226),
(137, 227),
(138, 226)]
После запуска фрагмента у меня осталось 4 угла:
[(4, 42), (7, 219), (133, 36), (135, 224)]
ОБНОВЛЕНИЕ 2
Теперь все, что вам нужно сделать, это просто отметить эти 4 точки на копии исходного изображения.
img2 = img.copy()
for pt in coor_tuples:
cv2.circle(img2, tuple(reversed(pt)), 3, (0, 0, 255), -1)
cv2.imshow('Image with 4 corners', img2)