У меня была та же идея, что и в комментарии fmw42 , поэтому здесь приводится версия этой идеи. Я предполагаю, что на изображении присутствует только один (более или менее совершенный) равнобедренный треугольник .
Выполнены следующие шаги:
- Найдитекрайние внешние контуры на изображении, преобразованном в оттенках серого, см.
cv2.findContours
и RetrievalModes
. - Найдите вершины треугольника, используя
cv2.minEnclosingTriangle
. - (Необязательно) Уточните найденные вершины, найдя ближайшие точки в исходном найденном контуре. См. Следующий пример кода, почему это может иметь значение.
- Рассчитать все длины ребер. «Верхняя» вершина - это та, которая имеет наименьшее количество уникальных длин ребер.
- Вычислите среднюю точку на основании и проведите линию от «верхней» вершины до этой точки.
Вот код:
import cv2
import numpy as np
# Some dummy image
img = cv2.fillPoly(img=np.zeros((500, 500, 3), np.uint8),
pts=np.array([[[200, 100], [400, 200], [300, 300]]]),
color=(0, 0, 255))
# Find only external contours in grayscale converted image
contours, _ = cv2.findContours(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Find triangle vertices of minimum area enclosing contour
_, triangle = cv2.minEnclosingTriangle(contours[0])
pts = np.int32(np.squeeze(np.round(triangle)))
print('\nminEnclosingTriangle: \n', pts)
# Refine/improve triangle vertices (if wanted)
idx = [np.argmin(np.linalg.norm(contours[0] - pt, axis=2)) for pt in pts]
pts = np.int32(np.squeeze(contours[0][idx]))
print('\nRefined: \n', pts)
# Find index of "top" vertex by finding unique edge lengths; "top" has less than the two base vertices
idx = np.argmin([np.size(np.unique(np.linalg.norm(pts - pt, axis=1))) for pt in pts])
top = pts[idx]
# Find mid point of the base vertices
base = np.array([pts[i] for i in np.arange(3) if i != idx])
base_mid = np.int32(np.round(np.mean(base, axis=0)))
# Draw angle bisector line
img = cv2.line(img, tuple(top), tuple(base_mid) , (0, 255, 0), 2)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
И вот выходы для моего фиктивного примера:
minEnclosingTriangle:
[[199 99]
[300 300]
[400 200]]
Refined:
[[200 100]
[300 300]
[400 200]]
![Output](https://i.stack.imgur.com/84l20.png)
Обратите внимание, что для неидеальных равнобедренных треугольников могут потребоваться некоторые модификации, например, вместо нахождения уникальных краевых длин, может потребоваться установить порог, чтобы краевые длины в пределах некоторого допуска также считались одинаковыми. Это может произойти довольно быстро, особенно если обнаружение контуров не является хорошим из-за - например, интерполированных пикселей от сжатия JPG.
В любом случае - надеюсь, это поможет!
Отказ от ответственности: В настоящее время яИграю со списком Python. Итак, извините, если здесь есть какое-то (неуместное) злоупотребление.