如何按顺序给定笔划的一些坐标(x,y)来平滑笔划?
How to smooth out a stroke, given some coordinates (x, y) of the stroke in order?
我目前正在做一个项目,我需要创建一个笔画图像,在给定笔画的一些有序坐标的情况下进行平滑处理。
假设我有一些积分
import numpy as np
X = np.array([1, 3, 6, 8, 5])
Y = np.array([1, 8, 4, 4, 1])
plt.plot(X, Y)
但我想要的是制作一个平滑的点集合来绘制这个(这只是一张手绘图,我想你明白了):
我看到了 this 仅适用于函数的问题(一个 x 只会输出一个 y)。但是我需要一个关系样条(不是函数)。
提前谢谢你。
柴金算法是一种直接作用于控制多边形的几何算法。曲线生成方案基于“切角”算法通过切掉原始多边形的角来生成新的控制多边形。
下图说明了这个想法,其中通过切断第一个序列的角,将初始控制多边形细化为第二个多边形(稍微偏移)。
这是一个示例实现。
"""
polygoninterpolation.py
Chaikin's Algorith for curves
http://graphics.cs.ucdavis.edu/~joy/GeometricModelingLectures/Unit-7-Notes/Chaikins-Algorithm.pdf
"""
import math
import random
from graphics import *
class MultiLine:
def __init__(self, points=None, rgb_color=(255, 255, 255), width=1):
self.lines = []
if points is None:
self.points = []
else:
self.points = points
self._build_lines()
self.rgb_color = rgb_color
self.width = width
def add_point(self):
self.points.append(point)
def _build_lines(self):
for idx, point in enumerate(self.points[:-1]):
self.lines.append(Line(self.points[idx], self.points[idx + 1]))
def draw(self, win):
for line in self.lines:
line.setOutline(color_rgb(*self.rgb_color))
line.setWidth(self.width)
line.draw(win)
def get_chaikin(points, factor=4):
new_points = [] # [points[0]]
for idx in range(len(points) - 1):
p1, p2 = points[idx], points[idx+1]
p_one_qtr, p_three_qtr = get_quarter_points(p1, p2, factor)
new_points.append(p_one_qtr)
new_points.append(p_three_qtr)
return new_points # + [points[-1]] # for a closed polygon
def get_quarter_points(p1, p2, factor=4):
n = factor
qtr_x = (p2.x - p1.x) / n
qtr_y = (p2.y - p1.y) / n
return Point(p1.x + qtr_x, p1.y + qtr_y), \
Point(p1.x + (n-1) * qtr_x, p1.y + (n-1) * qtr_y)
win = GraphWin("My Window", 500, 500)
win.setBackground(color_rgb(0, 0, 0))
# points0 = [Point(250, 20),
# Point(20, 400),
# Point(480, 400)]
# points0 = [Point(20, 400),
# Point(35, 200),
# Point(250, 100),
# Point(400, 150),
# Point(450, 350),
# Point(380, 450)]
# points0 = [Point(20, 400),
# Point(35, 200),
# Point(250, 100),
# Point(400, 150),
# Point(220, 170),
# Point(310, 190),
# Point(180, 270),
# Point(450, 230),
# Point(440, 440),
# Point(380, 450)]
points0 = [Point(random.randrange(500), random.randrange(500)) for _ in range(random.randrange(3, 80))]
x_line0 = MultiLine(points0)
# x_line0.draw(win)
points1 = get_chaikin(points0)
x_line1 = MultiLine(points1, rgb_color=(200, 200, 200), width=1)
# x_line1.draw(win)
points2 = get_chaikin(points1)
x_line2 = MultiLine(points2, rgb_color=(200, 200, 200), width=1)
# x_line2.draw(win)
points3 = get_chaikin(points2)
x_line3 = MultiLine(points3, rgb_color=(200, 200, 200), width=1)
# x_line3.draw(win)
points4 = get_chaikin(points3)
x_line4 = MultiLine(points4, rgb_color=(200, 200, 200), width=1)
# x_line4.draw(win)
points5 = get_chaikin(points4)
x_line5 = MultiLine(points5, rgb_color=(200, 200, 200), width=1)
x_line5.draw(win)
# poly0 = Polygon(points0)
# poly0.setOutline(color_rgb(0, 255, 0))
# poly0.setWidth(1)
# poly0.draw(win)
#
# points1 = get_chaikin(points0 + [points0[0]])
# poly1 = Polygon(points1)
# poly1.setOutline(color_rgb(0, 255, 0))
# poly1.setWidth(1)
# poly1.draw(win)
#
# points2 = get_chaikin(points1 + [points1[0]])
# poly2 = Polygon(points2)
# poly2.setOutline(color_rgb(0, 255, 0))
# poly2.setWidth(1)
# poly2.draw(win)
#
# points3 = get_chaikin(points2 + [points2[0]])
# poly3 = Polygon(points3)
# poly3.setOutline(color_rgb(0, 255, 0))
# poly3.setWidth(1)
# poly3.draw(win)
#
# points4 = get_chaikin(points3 + [points3[0]])
# poly4 = Polygon(points4)
# poly4.setOutline(color_rgb(0, 255, 0))
# poly4.setWidth(1)
# poly4.draw(win)
#
# points5 = get_chaikin(points4 + [points4[0]])
# poly5 = Polygon(points5)
# poly5.setOutline(color_rgb(0, 255, 0))
# poly5.setWidth(2)
# poly5.draw(win)
print("done")
print(win.getMouse())
win.close()
您可以使用来自 scipy.interpolate 的 B 样条曲线(splprep 和 splev):
import numpy as np
from scipy.interpolate import splprep, splev
import matplotlib.pyplot as plt
X = np.array([1, 3, 6, 8, 5])
Y = np.array([1, 8, 4, 4, 1])
pts = np.vstack((X, Y))
# Find the B-spline representation of an N-dimensional curve
tck, u = splprep(pts, s=0.0)
u_new = np.linspace(u.min(), u.max(), 1000)
# Evaluate a B-spline
x_new, y_new = splev(u_new, tck)
plt.plot(x_new, y_new, 'b--')
plt.show()
这将为您提供类似的内容:
您可以使用 splprep 参数来改变结果。
您可以在此 Whosebug .
中找到更多详细信息
上面的答案很优雅,但是这里尝试"hacky"解决方案,那就不那么顺利了
X_new = []
Y_new = []
for i in range(4):
line1 = [X[i],Y[i]] + np.expand_dims(np.linspace(0,1,10),-1)*np.array([X[i+1] - X[i], Y[i+1] - Y[i]])
line_normal = [- Y[i+1] + Y[i], X[i+1] - X[i]]
line_normal = line_normal/np.sqrt(np.dot(line_normal, line_normal))
line1_noisy = line1 + line_normal * 0.2*(np.random.rand(10,1) - 0.5)
X_new.append(line1_noisy[:,0])
Y_new.append(line1_noisy[:,1])
X_new = np.stack(X_new).reshape(-1)
Y_new = np.stack(Y_new).reshape(-1)
plt.plot(X_new, Y_new)
我目前正在做一个项目,我需要创建一个笔画图像,在给定笔画的一些有序坐标的情况下进行平滑处理。 假设我有一些积分
import numpy as np
X = np.array([1, 3, 6, 8, 5])
Y = np.array([1, 8, 4, 4, 1])
plt.plot(X, Y)
但我想要的是制作一个平滑的点集合来绘制这个(这只是一张手绘图,我想你明白了):
我看到了 this 仅适用于函数的问题(一个 x 只会输出一个 y)。但是我需要一个关系样条(不是函数)。 提前谢谢你。
柴金算法是一种直接作用于控制多边形的几何算法。曲线生成方案基于“切角”算法通过切掉原始多边形的角来生成新的控制多边形。
下图说明了这个想法,其中通过切断第一个序列的角,将初始控制多边形细化为第二个多边形(稍微偏移)。
这是一个示例实现。
"""
polygoninterpolation.py
Chaikin's Algorith for curves
http://graphics.cs.ucdavis.edu/~joy/GeometricModelingLectures/Unit-7-Notes/Chaikins-Algorithm.pdf
"""
import math
import random
from graphics import *
class MultiLine:
def __init__(self, points=None, rgb_color=(255, 255, 255), width=1):
self.lines = []
if points is None:
self.points = []
else:
self.points = points
self._build_lines()
self.rgb_color = rgb_color
self.width = width
def add_point(self):
self.points.append(point)
def _build_lines(self):
for idx, point in enumerate(self.points[:-1]):
self.lines.append(Line(self.points[idx], self.points[idx + 1]))
def draw(self, win):
for line in self.lines:
line.setOutline(color_rgb(*self.rgb_color))
line.setWidth(self.width)
line.draw(win)
def get_chaikin(points, factor=4):
new_points = [] # [points[0]]
for idx in range(len(points) - 1):
p1, p2 = points[idx], points[idx+1]
p_one_qtr, p_three_qtr = get_quarter_points(p1, p2, factor)
new_points.append(p_one_qtr)
new_points.append(p_three_qtr)
return new_points # + [points[-1]] # for a closed polygon
def get_quarter_points(p1, p2, factor=4):
n = factor
qtr_x = (p2.x - p1.x) / n
qtr_y = (p2.y - p1.y) / n
return Point(p1.x + qtr_x, p1.y + qtr_y), \
Point(p1.x + (n-1) * qtr_x, p1.y + (n-1) * qtr_y)
win = GraphWin("My Window", 500, 500)
win.setBackground(color_rgb(0, 0, 0))
# points0 = [Point(250, 20),
# Point(20, 400),
# Point(480, 400)]
# points0 = [Point(20, 400),
# Point(35, 200),
# Point(250, 100),
# Point(400, 150),
# Point(450, 350),
# Point(380, 450)]
# points0 = [Point(20, 400),
# Point(35, 200),
# Point(250, 100),
# Point(400, 150),
# Point(220, 170),
# Point(310, 190),
# Point(180, 270),
# Point(450, 230),
# Point(440, 440),
# Point(380, 450)]
points0 = [Point(random.randrange(500), random.randrange(500)) for _ in range(random.randrange(3, 80))]
x_line0 = MultiLine(points0)
# x_line0.draw(win)
points1 = get_chaikin(points0)
x_line1 = MultiLine(points1, rgb_color=(200, 200, 200), width=1)
# x_line1.draw(win)
points2 = get_chaikin(points1)
x_line2 = MultiLine(points2, rgb_color=(200, 200, 200), width=1)
# x_line2.draw(win)
points3 = get_chaikin(points2)
x_line3 = MultiLine(points3, rgb_color=(200, 200, 200), width=1)
# x_line3.draw(win)
points4 = get_chaikin(points3)
x_line4 = MultiLine(points4, rgb_color=(200, 200, 200), width=1)
# x_line4.draw(win)
points5 = get_chaikin(points4)
x_line5 = MultiLine(points5, rgb_color=(200, 200, 200), width=1)
x_line5.draw(win)
# poly0 = Polygon(points0)
# poly0.setOutline(color_rgb(0, 255, 0))
# poly0.setWidth(1)
# poly0.draw(win)
#
# points1 = get_chaikin(points0 + [points0[0]])
# poly1 = Polygon(points1)
# poly1.setOutline(color_rgb(0, 255, 0))
# poly1.setWidth(1)
# poly1.draw(win)
#
# points2 = get_chaikin(points1 + [points1[0]])
# poly2 = Polygon(points2)
# poly2.setOutline(color_rgb(0, 255, 0))
# poly2.setWidth(1)
# poly2.draw(win)
#
# points3 = get_chaikin(points2 + [points2[0]])
# poly3 = Polygon(points3)
# poly3.setOutline(color_rgb(0, 255, 0))
# poly3.setWidth(1)
# poly3.draw(win)
#
# points4 = get_chaikin(points3 + [points3[0]])
# poly4 = Polygon(points4)
# poly4.setOutline(color_rgb(0, 255, 0))
# poly4.setWidth(1)
# poly4.draw(win)
#
# points5 = get_chaikin(points4 + [points4[0]])
# poly5 = Polygon(points5)
# poly5.setOutline(color_rgb(0, 255, 0))
# poly5.setWidth(2)
# poly5.draw(win)
print("done")
print(win.getMouse())
win.close()
您可以使用来自 scipy.interpolate 的 B 样条曲线(splprep 和 splev):
import numpy as np
from scipy.interpolate import splprep, splev
import matplotlib.pyplot as plt
X = np.array([1, 3, 6, 8, 5])
Y = np.array([1, 8, 4, 4, 1])
pts = np.vstack((X, Y))
# Find the B-spline representation of an N-dimensional curve
tck, u = splprep(pts, s=0.0)
u_new = np.linspace(u.min(), u.max(), 1000)
# Evaluate a B-spline
x_new, y_new = splev(u_new, tck)
plt.plot(x_new, y_new, 'b--')
plt.show()
这将为您提供类似的内容:
您可以使用 splprep 参数来改变结果。
您可以在此 Whosebug
上面的答案很优雅,但是这里尝试"hacky"解决方案,那就不那么顺利了
X_new = []
Y_new = []
for i in range(4):
line1 = [X[i],Y[i]] + np.expand_dims(np.linspace(0,1,10),-1)*np.array([X[i+1] - X[i], Y[i+1] - Y[i]])
line_normal = [- Y[i+1] + Y[i], X[i+1] - X[i]]
line_normal = line_normal/np.sqrt(np.dot(line_normal, line_normal))
line1_noisy = line1 + line_normal * 0.2*(np.random.rand(10,1) - 0.5)
X_new.append(line1_noisy[:,0])
Y_new.append(line1_noisy[:,1])
X_new = np.stack(X_new).reshape(-1)
Y_new = np.stack(Y_new).reshape(-1)
plt.plot(X_new, Y_new)