• 主要为大家详细介绍了python使用插值法画出平滑曲线，具有一定的参考价值，感兴趣的小伙伴们可以参考一下
• 使用插值法画出平滑曲线。能够简单实现。 希望对各位有需要的朋友有所帮助
• canvas出来的线条存在锯齿，不够平滑。这篇文章主要介绍了canvas进阶之如何画出平滑曲线，小编觉得挺不错的，现在分享给大家，也给大家做个参考。一起跟随小编过来看看吧
• ## swing 画平滑曲线

千次阅读 2017-07-16 22:41:52
swing 画平滑曲线
package zhipu.trial.graph;

import zhipu.main.Entrance;

import javax.swing.*;

import java.awt.*;
import java.awt.geom.GeneralPath;
import java.util.ArrayList;
import java.util.List;

public class DrawChartDemo extends JPanel {
private Float[] values =  new Float[]{0.00476401629000442f ,
0.0063234711479510904f,
0.021695992320743099f,
0.0087923714104826394f,
0.016055573626994599f,
0.013452284007208701f,
0.0055611602146519801f,
0.0069146150381687596f,
0.0036230541986219198f,
0.0061674043426179301f,
0.00434440023492552f,
0.035138205238166999f,
0.0143897055961933f,
0.016811934089353098f,
0.0178861993959042f,
0.0087641654315109407f,
0.0102057457561573f,
0.0073624585142180602f,
0.272971583614874f,
0.0548574538534378f,
0.016955049412583498f,
0.0051184965677307202f,
0.0033135295393096199f,
0.0059344633867462002f,
0.0039347395484018001f,
0.00348367923743807f,
0.026377286849230099f,
0.036832070301518f,
0.0056683752431168398f,
0.0047084728862943504f,
0.0050807108798568996f,
0.0105448869266738f,
0.0056977138353234702f,
0.085602792538286607f,
0.0043054151148011997f,
0.0061197850778468496f,
0.0144032602561065f,
0.0098497881084309603f,
0.0065389022201078504f,
0.0079793910312075996f,
0.15023645197019f,
0.0068558337838472202f,
0.00388789967772707f,
0.0019588905560046599f,
0.00813157867268848f,
0.0181800097326743f,
0.0179981531868081f,
0.120687865774082f,
0.031901241417862901f,
0.0059096372433688803f,
0.039816888009691f,
0.0022180602796087298f,
0.0020421521163729701f,
0.0029398192573330999f,
0.0090383331308239393f,
0.069211309213069394f,
0.111332699808443f,
0.044655161421859497f,
0.0057869308391771297f,
0.0041646558052810603f,
0.0019861723474547599f,
0.0038429991850212901f,
0.0064167275578309001f,
0.0583319986899676f,
0.029744027162729499f,
0.0120586137993033f,
0.13488486713846501f,
0.046035790422276901f,
0.015785314062179999f,
0.0039932783490598603f,
0.0081173362329025698f,
0.101646122607811f,
0.27943278350252698f,
0.0150728510109874f,
0.013116721411450901f,
0.0092261367320127692f,
0.026218708859473899f,
0.00282953555265384f,
0.0044117373389137102f,
0.00260404985014934f,
0.0019293731880499201f,
0.00190464973226343f,
0.0038443276152136602f,
0.034056811633866202f,
1f,
0.094481973471835803f,
0.056033417554237797f,
0.018825637176542499f,
0.012730403947311f,
0.0065964488004084604f,
0.0126633133100138f,
0.0080601022249829398f,
0.0089431644768543598f,
0.025988444047573799f,
0.025109531649443f,
0.113067555237683f,
0.026435961558734799f,
0.070132172326724307f,
0.0044758225616537703f,
0.0059336269122534204f,
0.0036456993373522898f,
0.0118958563883495f,
0.0575133588137191f,
0.015350604576100499f,
0.0040318661392891499f,
0.0032193573469880901f,
0.0088850481743988092f,
0.023877330732745498f,
0.011155327017979f,
0.0083402368409935708f,
0.0573569045895874f,
0.69517440147232901f,
0.094371184910862896f,
0.071074104420728201f,
0.036956650045186501f,
0.0173215382293214f,
0.0082548025110114592f,
0.00575279184699701f,
0.0212456696437636f,
0.0090010269608339806f,
0.016338080136423599f,
0.102902209055831f,
0.0078924297946662402f,
0.0074607529655075604f,
0.0091213387724318404f,
0.0021516241375805099f,
0.043235898066084501f,
0.0025994439364933199f,
0.020705025675201501f,
0.0032286088255712199f,
0.0050739272892518896f,
0.0077606155122827997f,
0.24031502163576099f,
0.0361153446322387f,
0.010647914836661301f,
0.0034358292189724002f,
0.0034736207897978801f,
0.00342349287658111f,
0.0027815949551543298f,
0.21694338263132201f,
0.026700254130092999f,
0.0247184156591739f,
0.019277156255502199f,
0.061541706635920297f,
0.014204979551463199f,
0.098758600131271204f,
0.0109810452672438f,
0.011093174362075801f,
0.0035773478807027402f,
0.024341837124427598f,
0.095577421992731795f,
0.068092147724430493f,
0.025021579201069202f,
0.126686929940758f,
0.0274313458782336f,
0.0021874701261044402f,
0.0018053147965141801f,
0.0047045163060877001f,
0.060906978228009202f,
0.013506145600343401f,
0.057883280380810802f,
0.0135282913118019f,
0.133110570121451f,
0.0196209073352617f,
0.0081105463525148799f,
0.0166649644250235f,
0.119949170146833f,
0.35597758971746102f,
0.086355513768921199f,
0.020482876765933199f,
0.014151643764207401f,
0.0080725779012815208f,
0.0038027676021578499f,
0.015995267888023499f,
0.0024399349293019101f,
0.0065235374981799004f,
0.0051175119611385602f,
0.051700471945563202f,
0.0116097754442507f,
0.024850592780722301f,
0.0073334465479829398f,
0.0282795436228921f,
0.0071780000763853003f,
0.0047777663463222002f,
0.0073803493784771702f,
0.0043306186181200097f,
0.0064184788227479601f};

List<GeneralPath> paths =new ArrayList<GeneralPath>();
int maxindex=0;
float maxvalue=-1;
int heith=100;
public DrawChartDemo() {

int startY=0;
int endY=0;
for (int j = 0; j <5; j++) {

Float[] points=values.clone();
startY=j*heith;
endY=(j+1)*heith;

GeneralPath path = new GeneralPath();
//        path.lineTo(0,100);
//        path.lineTo(0, heith-points[0]);
int index = 0;
int indexnext = 0;
for (int i = 0; i < points.length - 1; ++i) {
points[i] *= heith;
if (points[i] > maxvalue) {
maxvalue = points[i];
maxindex = i;
}
}
path.moveTo(0, endY - points[0]);
for (int i = 0; i < points.length - 1; ++i) {
index = i * 5;
indexnext = (i + 1) * 5;
float sp = points[i];
float ep = points[i + 1];
//            Point c1 = new Point((i + i+1)/2, sp);
//            Point c2 = new Point((i + i+1)/2, ep);
path.curveTo((index + indexnext) / 2, endY - sp, (index + indexnext) / 2, endY - ep, (index + 5), endY - ep);
if (maxindex == i) {

//                path.lineTo((index+indexnext)/2,100);
//                path.lineTo((index+indexnext)/2, heith-ep);
}
}
}
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(1));
g2d.translate(40, 40);
int gsize = paths.size();
for (int j = 0; j < gsize; j++) {
g2d.setColor(Color.blue);
g2d.draw(paths.get(j));
g2d.setColor(Color.red);
g2d.drawLine(maxindex*5,heith,maxindex*5,0);
}

//        for (int i = 0; i < points.length; ++i) {
//            g2d.setColor(Color.GRAY);
//            g2d.fillOval(points[i].x-4, points[i].y-4, 8, 8);
//            g2d.setColor(Color.BLACK);
//            g2d.drawOval(points[i].x-4, points[i].y-4, 8, 8);
//        }
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Smooth Curve");
frame.setContentPane(new DrawChartDemo());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(820, 280);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Entrance.startTime=System.currentTimeMillis();   //获取开始时间
createAndShowGui();

Entrance.endTime=System.currentTimeMillis();   //获取开始时间
System.out.println("程序启动时间： " + (Entrance.endTime - Entrance.startTime) + "ms");
}
});
}
}
展开全文
• 画平滑曲线（插值）： values = spcrv([[x(1) x x(end)];[y(1) y y(end)]],3); plot(values(1,:),values(2,:)) 曲线加粗： plot(values1(1,:),values1(2,:),'LineWidth',3);

画平滑曲线（插值）：

values = spcrv([[x(1) x x(end)];[y(1) y y(end)]],3);
plot(values(1,:),values(2,:))

曲线加粗：

plot(values1(1,:),values1(2,:),'LineWidth',3);

展开全文
• 实现所需的库 numpy、scipy、matplotlib 实现所需的方法 ...quadratic、cubic：2、3阶B样条曲线插值 ...简单来说，插值就是根据原有数据...拟合是通过原有数据，调整曲线系数，使得曲线与已知点集的差别（最小二乘...

### 实现所需的库

numpy、scipy、matplotlib

### 实现所需的方法

#### 插值

• nearest：最邻近插值法
• zero：阶梯插值
• slinear：线性插值

### 拟合和插值的区别

简单来说，插值就是根据原有数据进行填充，最后生成的曲线一定过原有点。

拟合是通过原有数据，调整曲线系数，使得曲线与已知点集的差别（最小二乘）最小，最后生成的曲线不一定经过原有点。

### 代码实现

# -*- coding: utf-8 -*-

# 调用模块
# 调用数组模块
import numpy as np
# 实现插值的模块
from scipy import interpolate
# 画图的模块
import matplotlib.pyplot as plt
# 生成随机数的模块
import random

# random.randint(0, 10) 生成0-10范围内的一个整型数
# y是一个数组里面有10个随机数，表示y轴的值
y = np.array([random.randint(0, 10) for _ in range(10)])
# x是一个数组，表示x轴的值
x = np.array([num for num in range(10)])

# 插值法之后的x轴值，表示从0到9间距为0.5的18个数
xnew = np.arange(0, 9, 0.5)

"""
kind方法：
实现函数func
"""
func = interpolate.interp1d(x, y, kind='cubic')
# 利用xnew和func函数生成ynew，xnew的数量等于ynew数量
ynew = func(xnew)

# 画图部分
# 原图
plt.plot(x, y, 'ro-')
# 拟合之后的平滑曲线图
plt.plot(xnew, ynew)
plt.show()

### 注意事项

• x, y为原来的数据（少量）
• xnew为一个数组，条件：xxnew
• 如：x的最小值为-2.931，最大值为10.312；则xnew的左边界要小于-2.931，右边界要大于10.312。当然也最好注意一下间距，最好小于x中的精度
• func为函数，里面的参数x、y、kind，x，y就是原数据的x，y，kind为需要指定的方法
• ynew需要通过xnew数组和func函数来生成
• 理论上xnew数组内的值越多，生成的曲线越平滑

参考博客

展开全文
• 画出平滑曲线，其实也是有方法的， lineTo 靠不住那我们可以采用canvas的另一个绘图API—— quadraticCurveTo ，它用于绘制二次贝塞尔曲线。 二次贝塞尔曲线 quadraticCurveTo(cp1x, cp1y, x, y) 调用 ...

### 背景概要

相信大家平时在学习canvas 或 项目开发中使用canvas的时候应该都遇到过这样的需求：实现一个可以书写的画板小工具。

嗯，相信这对canvas使用较熟的童鞋来说仅仅只是几十行代码就可以搞掂的事情，以下demo就是一个再也简单不过的例子了：

<!DOCTYPE html>
<html>
<style type="text/css">
canvas {
border: 1px blue solid;
}
</style>
<body>
<canvas id="canvas" width="800" height="500"></canvas>
<script type="text/javascript">
let isDown = false;
let beginPoint = null;
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');

// 设置线条颜色
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';

function down(evt) {
isDown = true;
beginPoint = getPos(evt);
}

function move(evt) {
if (!isDown) return;
const endPoint = getPos(evt);
drawLine(beginPoint, endPoint);
beginPoint = endPoint;
}

function up(evt) {
if (!isDown) return;

const endPoint = getPos(evt);
drawLine(beginPoint, endPoint);

beginPoint = null;
isDown = false;
}

function getPos(evt) {
return {
x: evt.clientX,
y: evt.clientY
}
}

function drawLine(beginPoint, endPoint) {
ctx.beginPath();
ctx.moveTo(beginPoint.x, beginPoint.y);
ctx.lineTo(endPoint.x, endPoint.y);
ctx.stroke();
ctx.closePath();
}
</script>
</body>
</html>

它的实现逻辑也很简单：

1. 我们在canvas画布上主要监听了三个事件：mousedownmouseupmousemove，同时我们也创建了一个isDown变量；
2. 当用户按下鼠标（mousedown，即起笔）时将isDown置为true，而放下鼠标（mouseup）的时候将它置为false，这样做的好处就是可以判断用户当前是否处于绘画状态；
3. 通过mousemove事件不断采集鼠标经过的坐标点，当且仅当isDowntrue（即处于书写状态）时将当前的点通过canvas的lineTo方法与前面的点进行连接、绘制；

通过以上几个步骤我们就可以实现基本的画板功能了，然而事情并没那么简单，仔细的童鞋也许会发现一个很严重的问题——通过这种方式画出来的线条存在锯齿，不够平滑，而且你画得越快，折线感越强。表现如下图所示：

为什么会这样呢？

### 问题分析

出现该现象的原因主要是：

• 我们是以canvas的lineTo方法连接点的，连接相邻两点的是条直线，非曲线，因此通过这种方式绘制出来的是条折线；
• 受限于浏览器对mousemove事件的采集频率，大家都知道在mousemove时，浏览器是每隔一小段时间去采集当前鼠标的坐标的，因此鼠标移动的越快，采集的两个临近点的距离就越远，故“折线感越明显“；

### 如何才能画出平滑的曲线?

#### 二次贝塞尔曲线

更多详细的信息可移步MDN

既然要使用贝塞尔曲线，很显然我们的数据是不够用的，要完整描述一个二次贝塞尔曲线，我们需要：起始点、控制点和终点，这些数据怎么来呢？

有一个很巧妙的算法可以帮助我们获取这些信息

#### 获取二次贝塞尔关键点的算法

这个算法并不难理解，这里我直接举例子吧：

1. 假设我们在一次绘画中共采集到6个鼠标坐标，分别是A, B, C, D, E, F
3. 接下来，计算得出CD点的中点C1，以B1为起点、C为控制点、C1为终点继续绘制曲线；
4. 依次类推不断绘制下去，当到最后一个点F时，则以DE的中点D1为起点，以E为控制点，F为终点结束贝塞尔曲线。

OK，算法就是这样，那我们基于该算法再对现有代码进行一次升级改造：

let isDown = false;
let points = [];
let beginPoint = null;
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');

// 设置线条颜色
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';

function down(evt) {
isDown = true;
const { x, y } = getPos(evt);
points.push({x, y});
beginPoint = {x, y};
}

function move(evt) {
if (!isDown) return;

const { x, y } = getPos(evt);
points.push({x, y});

if (points.length > 3) {
const lastTwoPoints = points.slice(-2);
const controlPoint = lastTwoPoints[0];
const endPoint = {
x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2,
y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2,
}
drawLine(beginPoint, controlPoint, endPoint);
beginPoint = endPoint;
}
}

function up(evt) {
if (!isDown) return;
const { x, y } = getPos(evt);
points.push({x, y});

if (points.length > 3) {
const lastTwoPoints = points.slice(-2);
const controlPoint = lastTwoPoints[0];
const endPoint = lastTwoPoints[1];
drawLine(beginPoint, controlPoint, endPoint);
}
beginPoint = null;
isDown = false;
points = [];
}

function getPos(evt) {
return {
x: evt.clientX,
y: evt.clientY
}
}

function drawLine(beginPoint, controlPoint, endPoint) {
ctx.beginPath();
ctx.moveTo(beginPoint.x, beginPoint.y);
ctx.stroke();
ctx.closePath();
}

在原有的基础上，我们创建了一个变量points用于保存之前mousemove事件中鼠标经过的点，根据该算法可知要绘制二次贝塞尔曲线起码需要3个点以上，因此我们只有在points中的点数大于3时才开始绘制。接下来的处理就跟该算法一毛一样了，这里不再赘述。

代码更新后我们的曲线也变得平滑了许多，如下图所示：

本文到这里就结束了，希望大家在canvas画板中“画”得愉快~我们下次再见：）

感兴趣的童鞋可戳这里关注我的博客，任何新鲜好玩的博文将会第一时间分享到这儿哦~

展开全文
• 关于平滑曲线，相信很多人在网上提过这个问题，如何画出平滑曲线？我也很想知道答案，究竟如何才能在MouseMove事件里画出真正平滑又柔和的曲线？注意本文讨论的重点是在MouseMove事件里，并非相对固定的几个点 针对...
• ## Qt画平滑曲线

千次阅读 2013-12-23 13:01:40
初学Qt绘图，使用drawling（）绘制的直线在两端点间距离较小时总是出现折点（锯齿），非常不美观。...//平滑直线 pen.setPen(QPen(Qt::black,1,Qt::SolidLine,Qt::RoundCap,Qt::MiterJoin));
• 有两种方法可以画平滑曲线，第一种是拟合的方法，第二种是用spcrv，其实原理应该都一样就是插值。下面是源程序，大家可以根据需要自行选择，更改拟合的参数。 clc,clear; a = 1:1:6; %横坐标 b = [8.0 9.0 10.0 ...
• 本附件是一个Excel文档 ...里面的公开的VBA代码可以计算贝塞尔曲线的任意插值，即EXCEL画平滑曲线散点图的方法 附件并详细描述了这一算法，用户可以自行在其他语言实现。 本附件原创作者为 EXCELHOME.NET 的 海底眼
• Qt 中可以使用 QPainterPath::cubicTo() 函数绘制如下的平滑曲线 函数原型：void QPainterPath::​cubicTo(const QPointF &amp; c1, const QPointF &amp; c2, const QPointF &amp; endPoint) 使用C1...
• 因最近需要对多个无规则的点规划一条圆滑曲线，现找到的方法是使用贝塞尔曲线进行规划。在此，先简单了解了一下贝塞尔曲线的知识，具体知识转至：...
• 有两种方法可以画平滑曲线，第一种是拟合的方法，第二种是用spcrv，其实原理应该都一样就是插值。下面是源程序，大家可以根据需要自行选择，更改拟合的参数。 clc,clear; a = 1:1:6; %横坐标 b = [8.0 9.0 10.0 ...
• ## 画平滑的roc曲线

千次阅读 2018-07-15 19:16:16
使用matlab画roc曲线本来malab曲线的平滑有2种方法clc,clear; a = 1:1:6; %横坐标 b = [8.0 9.0 10.0 15.0 35.0 40.0];...%第一种，画平滑曲线的方法 c = polyfit(a, b, 2); %进行拟合，c为2次拟合后的系数 d = poly...
• //计算指定个点,将他们练成一条直线,使其开起来像是曲线 void GetPathPoints ( ) { point = new List < Vector3 > ( ) ; float pointNumber = 50 ; for ( int i = 0 ; i ( ...
• 关于贝塞尔曲线知识（请具体阅读...直接拿三阶贝塞尔曲线为例，首先观察下图： 从图中可以看出，只有四个点是保持不变的,分别是P0,P1,P2,P3，这四个点两两相连得到三个线段 （1）在上四点构成的三个线段中，p
• 请看：https://blog.csdn.net/qq_40194498/article/details/79672908
• 直接拿三阶贝塞尔曲线为例，首先观察下图： 从图中可以看出，只有四个点是保持不变的,分别是P0,P1,P2,P3，这四个点两两相连得到三个线段 （1）在上四点构成的三个线段中，p0-p1上有到一个点，
• Matlab画平滑曲线的两种方法 拟合或插值后再用plot即可

...