简体   繁体   English

拉直B样条曲线

[英]Straighten B-Spline

I've interpolated a spline to fit pixel data from an image with a curve that I would like to straighten. 我已经插入了样条曲线,以使图像中的像素数据具有我想拉直的曲线。 I'm not sure what tools are appropriate to solve this problem. 我不确定哪种工具适合解决此问题。 Can someone recommend an approach? 有人可以推荐一种方法吗?

Here's how I'm getting my spline: 这是我得到样条的方式:

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()

My broader project is to follow the approach outlined in A novel method for straightening curved text-lines in stylistic documents . 我的更广泛的项目是遵循一种新的方法中概述的方法, 该方法可以使样式化文档中的弯曲文本行变直 That article is reasonably detailed in finding the line that describes curved text, but much less so where straightening the curve is concerned. 该文章在查找描述弯曲文本的线​​时进行了详细介绍,但在涉及到拉直曲线时要少得多。 I have trouble visualizing the only reference to straightening that I see is in the abstract: 我很难想象我看到的关于矫直的唯一参考是抽象的:

find the angle between the normal at a point on the curve and the vertical line, and finally visit each point on the text and rotate by their corresponding angles. 找到曲线上某个点的法线与垂直线之间的角度,最后访问文本上的每个点并旋转它们相应的角度。

I also found Geometric warp of image in python , which seems promising. 我还在python中发现了图像的几何变形 ,这似乎很有希望。 If I could rectify the spline, I think that would allow me to set a range of target points for the affine transform to map to. 如果可以校正样条曲线,我认为这将允许我设置仿射变换要映射到的目标点范围。 Unfortunately, I haven't found an approach to rectify my spline and test it. 不幸的是,我还没有找到一种方法来纠正我的样条并对其进行测试。

Finally, this program implements an algorithm to straighten splines, but the paper on the algorithm is behind a pay wall and I can't make sense of the javascript. 最后, 程序实现了拉直样条曲线的算法,但是关于该算法的论文在收费壁垒后面,我无法理解javascript。

Basically, I'm lost and in need of pointers. 基本上,我迷路了,需要指针。

Update 更新

The affine transformation was the only approach I had any idea how to start exploring, so I've been working on that since I posted. 仿射变换是我不知道如何开始探索的唯一方法,因此自发布以来我一直在努力。 I generated a set of destination coordinates by performing an approximate rectification of the curve based on the euclidean distance between points on my b-spline. 我根据b样条曲线上各点之间的欧式距离对曲线进行了近似校正,从而生成了一组目标坐标。

From where the last code block left off: 从最后一个代码块停止的地方:

# 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)

I'm presently hung up on errors with the affine transform ( scipy.spatial.qhull.QhullError: QH6154 Qhull precision error: Initial simplex is flat (facet 1 is coplanar with the interior point) ), but I'm not sure whether it's because of a problem with how I'm feeding the data in, or because I'm abusing the transform to do my projection. 我目前挂在仿射变换的错误上( scipy.spatial.qhull.QhullError: QH6154 Qhull precision error: Initial simplex is flat (facet 1 is coplanar with the interior point) ),但我不确定是否是因为我要如何输入数据而出现问题,或者是因为我滥用转换来进行投影。

I got the same error with you when using scipy.spatial.ConvexHull. 使用scipy.spatial.ConvexHull时,您遇到相同的错误。 First, let me explain my project: what i wanted to do is to segment the people from its background(image matting). 首先,让我解释一下我的项目:我想做的是从背景中区分人物(图像遮罩)。 In my code, first I read an image and a trimap, then according to the trimap, I segment the original image to foreground, bakground and unknown pixels. 在我的代码中,首先读取图像和Trimap,然后根据Trimap将原始图像分割为前景,bakground和未知像素。 Here is part of the coed: 这是男女同校的一部分:

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)

But i got an error here.So I check the Array of fg_px and then I found this array is n*4. 但是我在这里出错了,所以我检查了fg_px的数组,然后发现这个数组是n * 4。 which means every scalar i send to ConvexHull has four values. 这意味着我发送给ConvexHull的每个标量都有四个值。 Howerver, the input of ConvexHUll should be 3 dimension. 但是,ConvexHUll的输入应为3维。 I source my error and found that the input color image is 32bits(rgb channel and alpha channel) which means it has an alpha channel. 我发现错误,并发现输入的彩色图像是32位(RGB通道和Alpha通道),这意味着它具有Alpha通道。 After transferring the image to 24 bit (which means only rgb channels), the code works. 将图像传输到24位(这意味着仅rgb通道)后,代码起作用。

In one sentence, the input of ConvexHull should be b*4, so check your input data! 一句话,ConvexHull的输入应为b * 4,因此请检查您的输入数据! Hope this works for you~ 希望这对你有用〜

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM