使用导数拉直样条曲线以确定每个点的旋转

时间:2017-09-04 02:17:13

标签: python scipy

我正在努力将样条作为我的大项目的一个组成部分,以拉直弯曲的文本。

将样条曲线拟合到我的数据点后,我使用scipy的splev来获得曲线上每个点的样条曲线的导数。由于导数给出了给定点处曲线的切线的斜率(除非我非常困惑),我通过将导数与具有0斜率的线进行比较来确定产生直线所需的旋转。

确定了每个点所需的旋转以拉直我的样条曲线后,我遍历每个点并将校正旋转应用于当前点和每个前一点。

相关代码如下:

import numpy as np
from numpy import arange
from scipy import interpolate
import matplotlib.pyplot as plt
import math
import random

def rotate(origin, point, angle):

    ox, oy = origin
    px, py = point

    qx = ox + math.cos(angle) * (px - ox) - math.sin(angle) * (py - oy)
    qy = oy + math.sin(angle) * (px - ox) + math.cos(angle) * (py - oy)

    return qx, qy

xxx = [0,2,4,4,2,0]
yyy = [0,2,4,6,8,10]

tckp, u = interpolate.splprep([xxx, yyy], s=3, k=2, nest=-1)

xpointsnew, ypointsnew = interpolate.splev(u, tckp)

dx, dy = interpolate.splev(u, tckp, der=1)
fullder = dy/dx

rotating_x = xxx
rotating_y = yyy
index = -1
for i in fullder:
    index += 1
    corrective_rotation = -(math.degrees(math.atan(0)-math.atan(fullder[index])))
    print(corrective_rotation)
    rotation_center = [rotating_x[index], rotating_y[index]]
    target_indices = np.arange(0,index,1)
    for i in target_indices:
        rotation_target = [rotating_x[i], rotating_y[i]]
        qx, qy = rotate(rotation_target,rotation_center,math.radians(corrective_rotation))
        rotating_x[i] = qx
        rotating_y[i] = qy

print(rotating_x)
print(rotating_y)

plt.plot(xpointsnew, ypointsnew, 'r-')
plt.plot(rotating_x, rotating_y, 'b-')
plt.show()

我正在做的事情不起作用,但我不确定为什么。不仅生成的线不直,它也比原始曲线短得多。以上概述的方法是否在某种程度上存在根本缺陷?我在代码中做了些什么蠢事吗?我真的很感激第二双眼睛。

1 个答案:

答案 0 :(得分:0)

该算法的一个基本缺陷是,它将一个点的斜率作为两个段之一的必要旋转量,其中该点将曲线分开。例如,考虑60度的直线。您的算法将在线的每个结处产生60度的旋转,实际上使它们都是120度角。

您不是在旋转整个曲线,只是旋转它的一部分(在您的版本中最多index;在我的版本中i之后)。适当的旋转量是曲线在该点处转动的程度,这可以通过其斜率的变化来反映 - 而不是斜率本身。

然后有一些小细节,如

  • 参数列表中的rotation_center和rotation_target顺序不正确;
  • 毫无意义地转换到度和回;
  • 使用atan(dy/dx),其中应使用atan2(dy, dx);
  • 以及从曲线末端旋转的奇怪决定。

这是我的版本;唯一的变化是在for循环中。

for i in range(len(xxx)-1):
    corrective_rotation = -(math.atan2(dy[i+1], dx[i+1]) - math.atan2(dy[i], dx[i])) 
    print(corrective_rotation)
    rotation_center = [rotating_x[i], rotating_y[i]]
    for k in range(i+1, len(xxx)):
        rotation_target = [rotating_x[k], rotating_y[k]]
        qx, qy = rotate(rotation_center, rotation_target, corrective_rotation)   
        rotating_x[k] = qx
        rotating_y[k] = qy

straightened

顺便说一句,plt.axes().set_aspect('equal')有助于避免曲线在旋转后改变长度的错觉。

最后,我应该说从插值样条的导数的点值获取角度是一个非常值得怀疑的决定。适当规模的有限差异更加稳健。

相关问题