Я хочу написать инструмент для определения количества углов, кривых и прямых линий внутри каждого ограниченного объекта на изображении. Все входные изображения будут черными на белом фоне, и все они будут представлять символы.
Как показано на изображении, для каждой ограниченной области отмечается каждое появление формы. Было бы предпочтительнее иметь порог того, насколько кривой должна быть кривая, чтобы считаться кривой, а не углом и т. д. И то же самое для прямых линий и углов.
Я использовал Hough Line Transform для обнаружения прямых линий на других изображениях, и я подумал, что это может работать в сочетании с чем-то здесь.
Я открыт для других библиотек, кроме opencv - это то, с чем у меня есть некоторый опыт.
заранее спасибо
Обновлено:
Итак, основываясь на ответе Маркуса, я сделал программу, используя findContours()
с CHAIN_APPROX_SIMPLE
.
Он дает несколько странный результат при вводе «k», где он правильно определяет некоторые точки вокруг углов, но затем «нога» (нижняя диагональная часть) имеет много точек на ней. Я не уверен, как разделить это на сегменты, чтобы сгруппировать их в прямые, углы и кривые.
Код:
import numpy as np
img = cv2.imread('Helvetica-K.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
edges = cv2.Canny(blurred, 50, 150, apertureSize=3)
ret, thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY_INV)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#cv2.drawContours(img, contours, 0, (0,255,0), 1)
#Coordinates of each contour
for i in range(len(contours[0])):
print(contours[0][i][0][0])
print(contours[0][i][0][1])
cv2.circle(img, (contours[0][i][0][0], contours[0][i][0][1]), 2, (0,0,255), -1)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Спасибо, это имеет смысл. К сожалению, платные услуги выходят за рамки того, чем я сейчас занимаюсь.
Вы можете использовать найтиКонтуры с опцией CHAIN_APPROX_SIMPLE
.
Обновлять:
Вот некоторый код, с которого вы можете начать. В нем показано, как сгладить прямые линии, как объединить несколько угловых точек в одну и как рассчитать расстояния и углы в каждой точке. Вам еще предстоит проделать определенную работу для достижения требуемого результата, но я надеюсь, что она ведет в правильном направлении.
import numpy as np
import numpy.linalg as la
import cv2
def get_angle(p1, p2, p3):
v1 = np.subtract(p2, p1)
v2 = np.subtract(p2, p3)
cos = np.inner(v1, v2) / la.norm(v1) / la.norm(v2)
rad = np.arccos(np.clip(cos, -1.0, 1.0))
return np.rad2deg(rad)
def get_angles(p, d):
n = len(p)
return [(p[i], get_angle(p[(i-d) % n], p[i], p[(i+d) % n])) for i in range(n)]
def remove_straight(p):
angles = get_angles(p, 2) # approximate angles at points (two steps in path)
return [p for (p, a) in angles if a < 170] # remove points with almost straight angles
def max_corner(p):
angles = get_angles(p, 1) # get angles at points
j = 0
while j < len(angles): # for each point
k = (j + 1) % len(angles) # and its successor
(pj, aj) = angles[j]
(pk, ak) = angles[k]
if la.norm(np.subtract(pj, pk)) <= 4: # if points are close
if aj > ak: # remove point with greater angle
angles.pop(j)
else:
angles.pop(k)
else:
j += 1
return [p for (p, a) in angles]
def main():
img = cv2.imread('abc.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY_INV)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for c in contours: # for each contour
pts = [v[0] for v in c] # get pts from contour
pts = remove_straight(pts) # remove almost straight angles
pts = max_corner(pts) # remove nearby points with greater angle
angles = get_angles(pts, 1) # get angles at points
# draw result
for (p, a) in angles:
if a < 120:
cv2.circle(img, p, 3, (0, 0, 255), -1)
else:
cv2.circle(img, p, 3, (0, 255, 0), -1)
cv2.imwrite('out.png', img)
cv2.destroyAllWindows()
main()
Спасибо. Я вижу, что findContours может быть полезен. Однако я не могу надежно заставить findContours обнаруживать только точки контуров. т.е. применяя его к «k», он правильно обнаружит точки на углах стержня и «плеча». Однако «нога» (нижняя диагональная линия будет иметь много точек, идущих вдоль ее направления. Как мне различить их, поскольку они в основном просто проходят по прямой диагональной линии? Также я не совсем уверен в вашем предложении о как сегментировать контуры. Я не думаю, что совсем понимаю, что вы имеете в виду. Я не из математики.
Опция CHAIN_APPROX_SIMPLE
убирает лишние точки на прямых.
Спасибо. Я отредактировал исходный пост, чтобы проиллюстрировать, как он по-прежнему имеет много точек на прямых линиях, хотя CHAIN_APPROX_SIMPLE.
Я добавил код, как работать с контурами OpenCV.
Большое спасибо! Это определенно кажется полезным. Я постараюсь поработать с ним, чтобы увидеть, смогу ли я добиться чего-то в соответствии с тем, чего я хочу.
Hough это неправильный подход ИМХО. это должно работать исключительно с контурами (списками точек). сегментация контура на прямые и изогнутые части нет включена в OpenCV, но другие программные пакеты (например, коммерческий «halcon») предлагают это. - не стесняйтесь писать предложения по функциям для OpenCV. открыть вопрос на его github