【问题标题】:Straighten a spline using derivatives to determine rotation at each point使用导数拉直样条曲线以确定每个点的旋转
【发布时间】:2017-09-04 02:17:13
【问题描述】:

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

将样条曲线拟合到我的数据点后,我使用 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()

我正在做的事情不起作用,但我不知道为什么。结果线不仅不直,而且比原始曲线短得多。上述方法在某种程度上是否存在根本性缺陷?我在我的代码中做一些愚蠢的事情吗?我真的很感激第二双眼睛。

【问题讨论】:

  • 你定义了旋转方法,你根本不使用它。
  • @MishaVacic 我不知道吗?我很确定我在这里:qx, qy = rotate(rotation_target,rotation_center,math.radians(corrective_rotation))

标签: python scipy


【解决方案1】:

该算法的一个基本缺陷是,它将一个点的斜率作为该点分割曲线的两个线段之一的必要旋转量。例如,考虑 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

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

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

【讨论】:

    猜你喜欢
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-10
    • 1970-01-01
    • 1970-01-01
    • 2012-06-26
    • 2020-05-02
    相关资源
    最近更新 更多