Векторизируем график функции(python, skimage)
Пусть у нас есть картинка, содержащая график функции, где прямоугольниками обозначены её значения в отдельных точках, которые соединены прямыми линиями. Задача - определить координаты вершин и связи между ними и нарисовать векторизированное изображение того же самого.
Для начала, выделим интересующие нас линии и точки на основе цвета:
import numpy as np
from scipy.misc import imshow, imsave, imread
from scipy.ndimage import filters, morphology, measurements
from skimage.draw import line, circle
img = imread("laGK6.jpg")
r = img[:,:, 0]
g = img[:,:, 1]
b = img[:,:, 2]
mask = (r.astype(np.float)-np.maximum(g,b) ) > 20
С помощью морфологических операций уберем линии, оставив только вершины, для чего последовательно применим несколько бинарных эрозий и затем дилляцию для восстановления связанности:
mask2 = morphology.binary_erosion(mask)
mask2 = morphology.binary_erosion(mask2)
mask2 = morphology.binary_erosion(mask2)
mask2 = morphology.binary_erosion(mask2)
mask2 = morphology.binary_dilation(mask2)
Найдем вершины и их центры масс:
label, numvertices = measurements.label(mask2)
mc = measurements.center_of_mass(mask2, label, range(1,numvertices+1) )
Найдем линии, связывающие вершины между собой с ппомощью алгоритма, напоминающего линии Хафа. Для этого, определим координаты точек, лежащих на каждой линии, соединяющей вершины и посчитаем долю тех, которые имеют значение True в нашей маске. Если две вершины действительно соединены линией, то их доля будет почти стопроцентной.
arr = range(numvertices)
connections=[]
for i in range( numvertices):
arr.remove(i)
for j in arr:
rr,cc = line(mc[i][0], mc[i][1], mc[j][0], mc[j][1])
ms = np.sum(mask[rr,cc]).astype(np.float)/len(rr)
if ms > 0.9:
connections.append((i,j))
print "vertices: ", np.array(mc).astype(np.uint32)
print "connections: ", connections
Получим следующий результат:
vertices: [[ 76 288] [ 76 613] [138 126] [139 450] [265 207] [264 369] [265 694] [265 45] [327 532]]
connections: [(0, 4), (0, 5), (1, 6), (1, 8), (2, 4), (2, 7), (3, 5), (3, 8)]
Ну и наконец, нарисуем картинку на основе полученных вершин и связей, чтобы убедиться в правильности работы алгоритма:
mask3 = np.zeros(mask2.shape, dtype=np.uint8)
mask3[:]=255
for p in mc:
rr, cc = circle(p[0], p[1], 5)
#mask3[p[0], p[1]]=255
mask3[rr,cc]=20
for cn in connections:
i, j = cn
rr,cc = line(mc[i][0], mc[i][1], mc[j][0], mc[j][1])
mask3[rr,cc]=12
Полный исходный код примера здесь.