Измерение сложных форм с использованием центров Вороного

В настоящее время я работаю над проектом, используя opencv и python для измерения объектов, которые обычно изогнуты, например, стрелка, показанная ниже, как можно точнее.

Изогнутая стрелка

Я думал, что одной из стратегий может быть использование функции scipy Voronoi для получения точек вдоль центрального стержня стрелки, но сейчас у меня проблемы. Вот мой код:

img = cv2.imread('example_rubystreak_2.PNG')
img.shape
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,190,255,cv2.THRESH_BINARY)
countimage, contours, hierarchy = cv2.findContours(thresh,1,2)
blank = np.zeros((img.shape[0],img.shape[1],1),np.uint8)
#get max length contour
max_contour = 0
contour_idx = None
for ii in range(len(contours)):
    if len(contours[ii]) > max_contour:
        contour_idx = ii
        max_contour = len(contours[ii])
cv2.drawContours(blank,contours,contour_idx,255,cv2.FILLED,8,hierarchy)
apdp = cv2.approxPolyDP(contours[contour_idx],1,True)
ap = [(a[0][0],a[0][1]) for a in apdp]
vor_ap = Voronoi(ap)
spined = []
for ridge in vor_ap.ridge_vertices:
    if cv2.pointPolygonTest(cnt,tuple(vor_ap.vertices[ridge[0]]),True) <= 0.0 or cv2.pointPolygonTest(cnt,tuple(vor_ap.vertices[ridge[1]]),True) <= 0.0:
        continue
    else:
        if tuple(vor_ap.vertices[ridge[0]]) not in spined:
            spined.append([tuple(vor_ap.vertices[ridge[0]].tolist()),cv2.pointPolygonTest(cnt,tuple(vor_ap.vertices[ridge[0]]),True)])
        if tuple(vor_ap.vertices[ridge[1]]) not in spined:
            spined.append([tuple(vor_ap.vertices[ridge[1]].tolist()),cv2.pointPolygonTest(cnt,tuple(vor_ap.vertices[ridge[1]]),True)])
plt.figure(figsize=(12,12))
plt.scatter([s[0][0] for s in spined],[s[0][1] for s in spined])
plt.plot([a[0] for a in ap],[a[1] for a in ap])

Что производит эту картину:

Стрела Вороного

У кого-нибудь есть идеи относительно того, как я могу измерить длину стрелки, используя эти центральные точки? Я пробовал использовать np.polyfit и просматривал страницу здесь, но не могу найти способ последовательно получить кривую, прочерченную самыми центральными точками, поскольку стрелки иногда изогнуты как буква S или имеют точки другой формы . Любая помощь могла бы быть полезна. Спасибо.


person user2587593    schedule 07.08.2015    source источник
comment
спасибо, что заметили @paisanco   -  person user2587593    schedule 07.08.2015


Ответы (1)


Вот схема того, что я бы попробовал:

1) Найдите параметризованное представление вашей центральной кривой, интерполируя точки с помощью кубических B-сплайнов. Используйте scipy.interpolate.splrep. Возможно, вам придется удалить точки выброса, которые не следуют центральной кривой, чтобы получить хорошее соответствие кубическому сплайну.

2) Когда у вас есть кривая кубического сплайна, вы можете найти длину дуги, используя интегральную формулу длины дуги из исчисления, и вычислить этот интеграл численно с пределами интегрирования конечных точек вашей кривой. Для этого вам нужно получить первые производные X и Y вашей сплайновой кривой, которые scipy.interpolate.splev или scipy.interpolate.spalde должны быть в состоянии дать вам. Используйте процедуры численного интегрирования scipy для функции, представленной массивами Numpy.

person paisanco    schedule 07.08.2015
comment
спасибо за подсказку, но у меня проблемы с splrep, так как многие точки вдоль стрелок имеют несколько значений y для одного значения x, и эти кривые не всегда поддаются сортировке. Есть ли у вас какие-либо предложения о том, как справиться с этим? - person user2587593; 07.08.2015
comment
Я не смог запустить ваш код (какой должна быть переменная cnt в вызовах cv2.pointPolygonTest? Контур знаю, но какой на данном этапе выполнения). Не знал, что у некоторых X есть несколько Y, но в этих случаях имеет ли смысл брать среднее значение Y? - person paisanco; 08.08.2015