人工神经网络实现三阶贝塞尔曲线拟合散点

一、背景

        之前做过一个项目是需要将位图转换成矢量图,其中一个很重要的步骤,就是需要用贝塞尔曲线拟合一些散列点。了解贝塞尔曲线的同学都知道,如果贝塞尔曲线的控制点都明确的情况下,想算出来线上的点是很容易的,直接套公式就可以把点的坐标算出来。但是如果这个过程反过来,给你一些点的坐标,求出贝塞尔曲线的控制点,是很困难的。

        三阶贝塞尔曲线的公式: P = P0*(1-t)**3 + 3*P1*t*(1-t)**2 + 3*P2*t**2*(1-t) + P3*t**3 (公式中*表示乘法运算,**表示幂运算)

二、思路

       1、用圆拟合散点,再用三阶贝塞尔曲线拟合圆。优点算法简单,缺点,曲线很僵硬,放大看全是圆弧,失去了贝塞尔曲线的强大的表达能力。

       2、用二阶贝塞尔曲线拟合散点,优点算法简单,运算效率高。缺点二阶贝塞尔曲线实际就是抛物线,表达能力有限和思路1类似。

       3、用最小二乘法。优点运算可靠,速度快。缺点,公式推导复杂,理解很难。方法很可取,但是不是本文讲述的重点。

       4、网上搜了很多,有用遗传算法的,各种。后来想想,目前这么火热的人工神经网络能否解决这个问题呢?本文带大家一起尝试一下。

三、尝试

      试着用人工神经网络来搞定这个问题。就要考虑输入输出。

      1、输入,输入肯定是散列点。但是怎么输入呢,人工神经网络大部分输入参数都是固定的,但是散列点根据线的长度,个数不固定。能否想办法固定下来呢?我们选一些代表性的点,起点、终点、三个四分之一点。总共5个点,10个值。

      2、输出,输出控制点的坐标。起点、终点已知、那么就要两个控制点的坐标,总共4个数字。那么输出就是4个值。

四、网络搭建

       本次网络不牵涉到图像运算,就采用双隐藏层的ANN网络即可解决问题。网络结构很简单,读者可自行搜索。这里不做详细介绍,后面直接上代码。

五、数据集

       数据集自己写随机代码生成即可,放在训练过程中,可以做成无监督学习,省时省力。

六、实验效果。

       直接上图,图中红色点是实际控制点,黄色点是网络预测的点,几乎重合,曲线也几乎重合,效果很好:

七、代码

tensorflow 2.0+,如果对您有用,请帮忙点赞哈,文章是原创,转载请标明出处,沟通交流加我QQ306128847,。

import tensorflow as tf
from tensorflow.keras import layers, models
from matplotlib import pyplot as plt
import numpy as np
import os

b_xs = []
b_ys = []
# xs表示原始数据
# n表示阶数
# k表示索引
def one_bezier_curve(a, b, t):
    return (1 - t) * a + t * b


def n_bezier_curve(xs, n, k, t):
    if n == 1:
        return one_bezier_curve(xs[k], xs[k + 1], t)
    else:
        return (1 - t) * n_bezier_curve(xs, n - 1, k, t) + t * n_bezier_curve(xs, n - 1, k + 1, t)

def bezier_curve(xs, ys, num, b_xs, b_ys):
    n = 3  # 采用5次bezier曲线拟合
    t_step = 1.0 / (num - 1)
    # t_step = 1.0 / num
    print(t_step)
    t = np.arange(0.0, 1 + t_step, t_step)
    print(len(t))
    for each in t:
        b_xs.append(n_bezier_curve(xs, n, 0, each))
        b_ys.append(n_bezier_curve(ys, n, 0, each))

class AnnNet(object):
    def __init__(self):
        model = models.Sequential()
        model.add(layers.Dense(64, activation='sigmoid', input_shape=(10,)))
        model.add(layers.Dense(32, activation='sigmoid'))
        model.add(layers.Dense(4))
        model.summary()
        self.model = model

    def GenerateArray(self):
        while 1:
            x= []
            y= []
            for i in range(10):
                point = np.random.rand(8) * 10
                times = np.random.rand(3)
                times = [0.2, 0.5, 0.8]
                pt1x = ((1 - times[0]) ** 3) * point[0] + 3 * times[0] * ((1 - times[0]) ** 2) * point[2]  + 3 * (times[0] ** 2) * (1 - times[0]) * point[4] + (times[0] ** 3) * point[6]
                pt1y = ((1 - times[0]) ** 3) * point[1] + 3 * times[0] * ((1 - times[0]) ** 2) * point[3]  + 3 * (times[0] ** 2) * (1 - times[0]) * point[5] + (times[0] ** 3) * point[7]
                pt2x = ((1 - times[1]) ** 3) * point[0] + 3 * times[1] * ((1 - times[1]) ** 2) * point[2]  + 3 * (times[1] ** 2) * (1 - times[1]) * point[4] + (times[1] ** 3) * point[6]
                pt2y = ((1 - times[1]) ** 3) * point[1] + 3 * times[1] * ((1 - times[1]) ** 2) * point[3]  + 3 * (times[1] ** 2) * (1 - times[1]) * point[5] + (times[1] ** 3) * point[7]
                pt3x = ((1 - times[2]) ** 3) * point[0] + 3 * times[2] * ((1 - times[2]) ** 2) * point[2]  + 3 * (times[0] ** 2) * (1 - times[2]) * point[4] + (times[2] ** 3) * point[6]
                pt3y = ((1 - times[2]) ** 3) * point[1] + 3 * times[2] * ((1 - times[2]) ** 2) * point[3]  + 3 * (times[0] ** 2) * (1 - times[2]) * point[5] + (times[2] ** 3) * point[7]
                x.append([point[0], point[1], pt1x, pt1y, pt2x, pt2y, pt3x, pt3y, point[6], point[7]])
                y.append([point[2], point[3], point[4], point[5]])
            X = np.array(x)
            Y = np.array(y)
            yield (X, Y)

    def LossFunc(self, ytrue, ypred):
        loss = tf.reduce_mean(tf.square(ytrue-ypred))
        return loss

    def Train(self):
        print('train start!')
        self.check_path = 'save.ckpt'
        if os.path.exists(self.check_path + '.index'):
            self.model.load_weights(self.check_path)
        self.model.compile(optimizer='adam', loss = self.LossFunc)
        save_model_cb = tf.keras.callbacks.ModelCheckpoint(self.check_path, save_weights_only=True, verbose=1, period=1)
        back = self.model.fit_generator(self.GenerateArray(), steps_per_epoch=1000, epochs=100, callbacks=[save_model_cb])
        print('train end!')

    def Test(self):
        print('test start!')
        self.check_path = 'save.ckpt'
        if os.path.exists(self.check_path + '.index'):
            self.model.load_weights(self.check_path)
        x= []
        y= []
        point = np.random.rand(8) * 10
        times = [0.2, 0.5, 0.8]
        pt1x = ((1 - times[0]) ** 3) * point[0] + 3 * times[0] * ((1 - times[0]) ** 2) * point[2]  + 3 * (times[0] ** 2) * (1 - times[0]) * point[4] + (times[0] ** 3) * point[6]
        pt1y = ((1 - times[0]) ** 3) * point[1] + 3 * times[0] * ((1 - times[0]) ** 2) * point[3]  + 3 * (times[0] ** 2) * (1 - times[0]) * point[5] + (times[0] ** 3) * point[7]
        pt2x = ((1 - times[1]) ** 3) * point[0] + 3 * times[1] * ((1 - times[1]) ** 2) * point[2]  + 3 * (times[1] ** 2) * (1 - times[1]) * point[4] + (times[1] ** 3) * point[6]
        pt2y = ((1 - times[1]) ** 3) * point[1] + 3 * times[1] * ((1 - times[1]) ** 2) * point[3]  + 3 * (times[1] ** 2) * (1 - times[1]) * point[5] + (times[1] ** 3) * point[7]
        pt3x = ((1 - times[2]) ** 3) * point[0] + 3 * times[2] * ((1 - times[2]) ** 2) * point[2]  + 3 * (times[0] ** 2) * (1 - times[2]) * point[4] + (times[2] ** 3) * point[6]
        pt3y = ((1 - times[2]) ** 3) * point[1] + 3 * times[2] * ((1 - times[2]) ** 2) * point[3]  + 3 * (times[0] ** 2) * (1 - times[2]) * point[5] + (times[2] ** 3) * point[7]
        x.append([point[0], point[1], pt1x, pt1y, pt2x, pt2y, pt3x, pt3y, point[6], point[7]])
        y.append([point[2], point[3], point[4], point[5]])
        X = np.array(x)
        Y = np.array(y)
        ypred = self.model.predict(X)
        print(Y)
        print(ypred)
        num = 20
        xs = [point[0], point[2], point[4], point[6]]
        ys = [point[1], point[3], point[5], point[7]]
        b_xs = []
        b_ys = []
        bezier_curve(xs, ys, num, b_xs, b_ys)  # 将计算结果加入到列表中
        plt.figure()
        plt.plot(b_xs, b_ys, 'r')  # bezier曲线
        plt.plot(xs, ys, '.r')  # 控制点

        b_xs = []
        b_ys = []
        xs = [point[0], ypred[0][0], ypred[0][2], point[6]]
        ys = [point[1], ypred[0][1], ypred[0][3], point[7]]
        bezier_curve(xs, ys, num, b_xs, b_ys)  # 将计算结果加入到列表中
        plt.plot(b_xs, b_ys, 'y')  # bezier曲线
        plt.plot(xs, ys, '.y')  # 控制点
        plt.show()

        print('test end!')

if __name__ == '__main__':
    net = AnnNet()
    net.Train()
    net.Test()

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值