Как сгладить штрих, зная некоторые координаты (x, y) штриха по порядку?

В настоящее время я работаю над проектом, в котором мне нужно создать изображение сглаженного штриха с учетом некоторых упорядоченных координат штриха. Предположим, у меня есть несколько точек

import numpy as np
X = np.array([1, 3, 6, 8, 5])
Y = np.array([1, 8, 4, 4, 1])
plt.plot(X, Y)

Как сгладить штрих, зная некоторые координаты (x, y) штриха по порядку?

Но я хочу создать сглаженную коллекцию точек, которая будет отображать это (это просто нарисованная от руки картинка, я думаю, вы поняли):

Как сгладить штрих, зная некоторые координаты (x, y) штриха по порядку?

Я видел вопрос это, который работает только для функций (один x выводит только один y). Но мне нужен сплайн для отношения (а не функции). Заранее спасибо.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
466
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

См. алгоритм Чайкина.

Алгоритм Чайкина — это геометрический алгоритм, работающий непосредственно с управляющим полигоном. Схема генерации кривой основана на «разрезании углов», когда алгоритм генерирует новый контрольный многоугольник, обрезая углы исходного. Рисунок ниже иллюстрирует эту идею, где исходный контрольный многоугольник был преобразован во второй многоугольник (с небольшим смещением) путем срезания углов первой последовательности.

Вот пример реализации.

"""
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()
Ответ принят как подходящий

Вы можете использовать B-сплайн (splprep и splev) из scipy.interpolate:

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, чтобы изменить результат. Вы можете найти более подробную информацию в этом StackOverflow Почта.

Приведенные выше ответы очень элегантны, но вот попытка «хакерского» решения, которое гораздо менее гладко.

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)

Прошу прощения за плохой рисунок в моем вопросе, но выходной график не должен быть шумным. А также просто взять 3 точки для рисования линии для конкретной точки может быть не очень хорошей идеей.

Rahat Zaman 22.02.2019 08:50

Другие вопросы по теме