Выпрямить B-сплайн

Я интерполировал сплайн, чтобы подогнать данные о пикселях из изображения с кривой, которую я хотел бы выпрямить. Я не уверен, какие инструменты подходят для решения этой проблемы. Может ли кто-нибудь порекомендовать подход?

Вот как я получаю свой сплайн:

import numpy as np
from skimage import io
from scipy import interpolate
import matplotlib.pyplot as plt
from sklearn.neighbors import NearestNeighbors
import networkx as nx

# Read a skeletonized image, return an array of points on the skeleton, and divide them into x and y coordinates
skeleton = io.imread('skeleton.png')
curvepoints = np.where(skeleton==False)
xpoints = curvepoints[1]
ypoints = -curvepoints[0]

# reformats x and y coordinates into a 2-dimensional array
inputarray = np.c_[xpoints, ypoints]

# runs a nearest neighbors algorithm on the coordinate array
clf = NearestNeighbors(2).fit(inputarray)
G = clf.kneighbors_graph()
T = nx.from_scipy_sparse_matrix(G)

# sorts coordinates according to their nearest neighbors order
order = list(nx.dfs_preorder_nodes(T, 0))
xx = xpoints[order]
yy = ypoints[order]

# Loops over all points in the coordinate array as origin, determining which results in the shortest path
paths = [list(nx.dfs_preorder_nodes(T, i)) for i in range(len(inputarray))]

mindist = np.inf
minidx = 0

for i in range(len(inputarray)):
    p = paths[i]           # order of nodes
    ordered = inputarray[p]    # ordered nodes
    # find cost of that order by the sum of euclidean distances between points (i) and (i+1)
    cost = (((ordered[:-1] - ordered[1:])**2).sum(1)).sum()
    if cost < mindist:
        mindist = cost
        minidx = i

opt_order = paths[minidx]

xxx = xpoints[opt_order]
yyy = ypoints[opt_order]

# fits a spline to the ordered coordinates
tckp, u = interpolate.splprep([xxx, yyy], s=3, k=2, nest=-1)
xpointsnew, ypointsnew = interpolate.splev(np.linspace(0,1,270), tckp)

# prints spline variables
print(tckp)

# plots the spline
plt.plot(xpointsnew, ypointsnew, 'r-')
plt.show()

Мой более широкий проект состоит в том, чтобы следовать подходу, изложенному в новом методе выпрямления изогнутых строки текста в стилистических документах. Эта статья достаточно подробно описывает поиск линии, описывающей искривленный текст, но гораздо меньше, когда речь идет о выпрямлении кривой. Мне трудно представить, что единственная ссылка на выпрямление, которую я вижу, находится в аннотации:

найдите угол между нормалью в точке на кривой и вертикальной линией и, наконец, посетите каждую точку в тексте и поверните их на соответствующие углы.

Я также нашел геометрическую деформацию изображения в python, что кажется многообещающим. Если бы я мог исправить сплайн, я думаю, это позволило бы мне установить диапазон целевых точек для сопоставления с аффинным преобразованием. К сожалению, я не нашел способа исправить свой сплайн и протестировать его.

Наконец, эта программа реализует алгоритм выпрямления сплайнов, но статья о алгоритм находится за платной стеной, и я не могу понять javascript.

В основном, я потерян и нуждаюсь в указателях.

Обновить

Аффинное преобразование было единственным подходом, который я имел представление о том, как начать изучение, поэтому я работал над ним с момента публикации. Я сгенерировал набор координат пункта назначения, выполнив приблизительное выпрямление кривой на основе евклидова расстояния между точками моего b-сплайна.

С того места, где остановился последний блок кода:

# calculate euclidian distances between adjacent points on the curve
newcoordinates = np.c_[xpointsnew, ypointsnew]
l = len(newcoordinates) - 1
pointsteps = []
for index, obj in enumerate(newcoordinates):
    if index < l:
        ord1 = np.c_[newcoordinates[index][0], newcoordinates[index][1]]
        ord2 = np.c_[newcoordinates[index + 1][0], newcoordinates[index + 1][1]]
        length = spatial.distance.cdist(ord1, ord2)
        pointsteps.append(length)

# calculate euclidian distance between first point and each consecutive point
xpositions = np.asarray(pointsteps).cumsum()

# compose target coordinates for the line after the transform
targetcoordinates = [(0,0),]
for element in xpositions:
    targetcoordinates.append((element, 0))

# perform affine transformation with newcoordinates as control points and   targetcoordinates as target coordinates

tform = PiecewiseAffineTransform()
tform.estimate(newcoordinates, targetcoordinates)

В настоящее время я зациклен на ошибках с аффинным преобразованием (scipy.spatial.qhull.QhullError: QH6154 Qhull precision error: Initial simplex is flat (facet 1 is coplanar with the interior point) ), но я не уверен, связано ли это с тем, как я подаю данные, или потому, что я злоупотребляю преобразованием для своей проекции .


person Tric    schedule 03.02.2017    source источник
comment
вы ищете преобразование, которое проецирует ваш сплайн на заданную прямую линию, или вы пытаетесь определить прямую линию из заданного преобразования? Надеюсь, это имеет смысл.   -  person DrBwts    schedule 03.02.2017
comment
Если я правильно понимаю ваш вопрос, я хочу найти преобразование, которое спроецирует мой сплайн на прямую.   -  person Tric    schedule 05.02.2017
comment
А у вас есть уравнение этой прямой?   -  person DrBwts    schedule 05.02.2017
comment
Я думаю так. Любая линия ничем не хуже другой, если она прямая. Скажем, f(x)=0.   -  person Tric    schedule 06.02.2017
comment
Если вы хотите спроецировать свой сплайн на ось x, все, что вам нужно сделать, это взять все координаты x и соединить их с y=0. Это даст вам проекцию «а» на ось x. Я не уверен, что это то, что вам нужно.   -  person DrBwts    schedule 06.02.2017


Ответы (1)


Я получил ту же ошибку с вами при использовании scipy.spatial.ConvexHull. Во-первых, позвольте мне объяснить мой проект: я хотел отделить людей от их фона (матирование изображения). В моем коде я сначала считываю изображение и тримап, затем по тримапу сегментирую исходное изображение на передний план, задний план и неизвестные пиксели. Вот часть студентки:

img = scipy.misc.imread('sweater_black.png') #color_image

trimap = scipy.misc.imread('sw_trimap.png', flatten='True') #trimap

bg = trimap == 0 #background

fg = trimap == 255 #foreground

unknown = True ^ np.logical_or(fg,bg) #unknown pixels

fg_px = img[fg] #here i got the rgb value of the foreground pixels,then send them to the ConvexHull

fg_hull = scipy.spatial.ConvexHull(fg_px)

Но я получил ошибку здесь. Поэтому я проверяю массив fg_px, а затем я обнаружил, что этот массив равен n * 4. что означает, что каждый скаляр, который я отправляю в ConvexHull, имеет четыре значения. Однако ввод ConvexHUll должен быть трехмерным. Я обнаружил свою ошибку и обнаружил, что входное цветное изображение имеет размер 32 бита (канал RGB и альфа-канал), что означает, что оно имеет альфа-канал. После перевода изображения в 24 бит (а значит только rgb каналы) код работает.

В одном предложении ввод ConvexHull должен быть b * 4, поэтому проверьте свои входные данные! Надеюсь, это сработает для вас~

person Nan Shi    schedule 19.01.2018