使用导数拉直样条曲线以确定每个点的旋转
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用导数拉直样条曲线以确定每个点的旋转相关的知识,希望对你有一定的参考价值。
我正在努力将样条作为我的大型项目的一个组成部分,以拉直弯曲的文本。
在将样条拟合到我的数据点之后,我使用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()
我正在做的不行,但我不知道为什么。不仅生成的线不直,它也比原始曲线短得多。以上概述的方法是否在某种程度上存在根本缺陷?我在代码中做了些什么蠢事吗?我真的很感激第二双眼睛。
答案
该算法的一个基本缺陷是,它将一个点处的斜率作为两个段之一的必要旋转量,其中该点对曲线进行划分。例如,考虑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')
有助于避免曲线在旋转后改变长度的错觉。
最后,我应该说从插值样条的导数的点值获取角度是一个非常值得怀疑的决定。适当规模的有限差异更加稳健。
以上是关于使用导数拉直样条曲线以确定每个点的旋转的主要内容,如果未能解决你的问题,请参考以下文章