Bezier曲线原理

article/2025/11/9 19:54:48
一、原理:

       贝塞尔曲线于1962年,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由Paul de Casteljau 于1959年运用de Casteljau 算法开发,以稳定数值的方法求出贝塞尔曲线。

线性贝塞尔曲线

给定点 P0P1,线性贝塞尔曲线只是一条两点之间的直线。这条线由下式给出:

mathbf{B}(t)=mathbf{P}_0 + (mathbf{P}_1-mathbf{P}_0)t=(1-t)mathbf{P}_0 + tmathbf{P}_1 mbox{ , } t in [0,1]

且其等同于线性插值。

二次方贝塞尔曲线的路径由给定点 P0P1P2 的函数B(t) 追踪:

mathbf{B}(t) = (1 - t)^{2}mathbf{P}_0 + 2t(1 - t)mathbf{P}_1 + t^{2}mathbf{P}_2 mbox{ , } t in [0,1]

TrueType 字型就运用了以贝塞尔样条组成的二次贝塞尔曲线。

P0P1P2P3 四个点在平面或在三维空间中定义了三次方贝塞尔曲线。曲线起始于P0 走向 P1,并从 P2 的方向来到P3。一般不会经过 P1P2;这两个点只是在那里提供方向资讯。P0P1 之间的间距,决定了曲线在转而趋进 P3 之前,走向 P2 方向的“长度有多长”。

曲线的参数形式为:

mathbf{B}(t)=mathbf{P}_0(1-t)^3+3mathbf{P}_1t(1-t)^2+3mathbf{P}_2t^2(1-t)+mathbf{P}_3t^3 mbox{ , } t in [0,1]

现代的成象系统,如 PostScript、Asymptote 和Metafont,运用了以贝塞尔样条组成的三次贝塞尔曲线,用来描绘曲线轮廓。

一般化

P0P1、…、Pn,其贝塞尔曲线即

mathbf{B}(t)=sum_{i=0}^n {nchoose i}mathbf{P}_i(1-t)^{n-i}t^i =mathbf{P}_0(1-t)^n+{nchoose 1}mathbf{P}_1(1-t)^{n-1}t+cdots+mathbf{P}_nt^n mbox{ , } t in [0,1]

例如 :

mathbf{B}(t)=mathbf{P}_0(1-t)^5+5mathbf{P}_1t(1-t)^4+10mathbf{P}_2t^2(1-t)^3+10mathbf{P}_3t^3(1-t)^2+5mathbf{P}_4t^4(1-t)+mathbf{P}_5t^5 mbox{ , } t in [0,1]

如上公式可如下递归表达: 用 mathbf{B}_{mathbf{P}_0mathbf{P}_1ldotsmathbf{P}_n} 表示由点P0P1、…、Pn 所决定的贝塞尔曲线。则

mathbf{B}(t) = mathbf{B}_{mathbf{P}_0mathbf{P}_1ldotsmathbf{P}_n}(t) = (1-t)mathbf{B}_{mathbf{P}_0mathbf{P}_1ldotsmathbf{P}_{n-1}}(t) + tmathbf{B}_{mathbf{P}_1mathbf{P}_2ldotsmathbf{P}_n}(t)

用平常话来说, 阶贝塞尔曲线之间的插值。

一些关于参数曲线的术语,有

mathbf{B}(t) = sum_{i=0}^n mathbf{P}_imathbf{b}_{i,n}(t),quad tin[0,1]

即多项式

mathbf{b}_{i,n}(t) = {nchoose i} t^i (1-t)^{n-i},quad i=0,ldots n

又称作 n 阶的伯恩斯坦基底多项式,定义 00 = 1。

Pi 称作贝塞尔曲线的控制点。多边形以带有线的贝塞尔点连接而成,起始于P0 并以 Pn 终止,称作贝塞尔多边形(或控制多边形)。贝塞尔多边形的凸包(convex hull)包含有贝塞尔曲线。

 
 

线性贝塞尔曲线函数中的 t 会经过由 P0P1B(t) 所描述的曲线。例如当 t=0.25 时,B(t) 即一条由点P0P1 路径的四分之一处。就像由 0 至 1 的连续tB(t) 描述一条由 P0P1 的直线。

线性贝塞尔曲线演示动画,t in [0,1]

为建构二次贝塞尔曲线,可以中介点 Q0Q1 作为由 0 至 1 的t

  • P0P1 的连续点 Q0,描述一条线性贝塞尔曲线。
  • P1P2 的连续点 Q1,描述一条线性贝塞尔曲线。
  • Q0Q1 的连续点 B(t),描述一条二次贝塞尔曲线。
  •  
二次贝塞尔曲线的结构 二次贝塞尔曲线演示动画,t in [0,1]
   

为建构高阶曲线,便需要相应更多的中介点。对于三次曲线,可由线性贝塞尔曲线描述的中介点 Q0Q1Q2,和由二次曲线描述的点R0R1 所建构:

三次贝塞尔曲线的结构 三次贝塞尔曲线演示动画,t in [0,1]
   

对于四次曲线,可由线性贝塞尔曲线描述的中介点 Q0Q1Q2Q3,由二次贝塞尔曲线描述的点R0R1R2,和由三次贝塞尔曲线描述的点S0S1 所建构:

四次贝塞尔曲线的结构 四次贝塞尔曲线演示动画,t in [0,1]
   

P(t)=(1-t)P0+tP1 ,
矩阵表示为:

P(t)=(1-t)2P0+2t(1-t)P1+t2P2,
矩阵表示为:

P(t)=(1-t)3P0+3t(1-t)2P1+3t2(1-t)P2+t3P3
矩阵表示为:



在(6-3-2)式中,Mn+1是一个n+1阶矩阵,称为n次Bezier矩阵。

其中,

利用(6-3-3)式,我们可以得到任意次Bezier矩阵的显式表示,例如4次和5次Bezier矩阵为:
 
可以证明,n次Bezier矩阵还可以表示为递推的形式:

下列程式码为一简单的实际运用范例,展示如何使用C标出三次方贝塞尔曲线。注意,此处仅简单的计算多项式系数,并读尽一系列由0至1的t值;实践中一般不会这么做,递归求解通常会更快速——以更多的内存为代价,花费较少的处理器时间。不过直接的方法较易于理解并产生相同结果。以下程式码已使运算更为清晰。实践中的最佳化会先计算系数一次,并在实际计算曲线点的循环中反复使用。此处每次都会重新计算,损失了效率,但程式码更清楚易读。

曲线的计算可在曲线阵列上将相连点画上直线——点越多,曲线越平滑。

在部分架构中,下以程式码也可由动态规划进行最佳化。举例来说,dt是一个常数,cx * t则等同于每次反复就修改一次常数。经反复应用这种最佳化后,循环可被重写为没有任何乘法(虽然这个过程不是稳定数值的)。

/*產生三次方貝茲曲線的程式碼
*/typedef struct
{float x;float y;
}
Point2D;/*cp在此是四個元素的陣列:cp[0]為起始點,或上圖中的P0cp[1]為第一個控制點,或上圖中的P1cp[2]為第二個控制點,或上圖中的P2cp[3]為結束點,或上圖中的P3t為參數值,0 <= t <= 1
*/Point2D PointOnCubicBezier( Point2D* cp, float t )
{float   ax, bx, cx;float   ay, by, cy;float   tSquared, tCubed;Point2D result;/*計算多項式係數*/cx = 3.0 * (cp[1].x - cp[0].x);bx = 3.0 * (cp[2].x - cp[1].x) - cx;ax = cp[3].x - cp[0].x - cx - bx;cy = 3.0 * (cp[1].y - cp[0].y);by = 3.0 * (cp[2].y - cp[1].y) - cy;ay = cp[3].y - cp[0].y - cy - by;/*計算位於參數值t的曲線點*/tSquared = t * t;tCubed = tSquared * t;result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;return result;
}/*ComputeBezier以控制點cp所產生的曲線點,填入Point2D結構的陣列。呼叫者必須分配足夠的記憶體以供輸出結果,其為<sizeof(Point2D) numberOfPoints>
*/void ComputeBezier( Point2D* cp, int numberOfPoints, Point2D* curve )
{float   dt;int     i;dt = 1.0 / ( numberOfPoints - 1 );for( i = 0; i < numberOfPoints; i++)curve[i] = PointOnCubicBezier( cp, i*dt );
}

德卡斯特里奥算法(De Casteljau’s Algorithm)绘制贝塞尔曲线

德卡斯特里奥算法可以计算贝塞尔曲线上的点C(u),u∈[0,1]。因此,通过给定一组u的值,便可以计算出贝塞尔曲线上的坐标序列,从而绘制出贝塞尔曲线。

德卡斯特里奥算法的基础就是在向量AB上选择一个点C,使得C分向量AB为u:1-u(也就是∣AC∣:∣AB∣= u)。给定点A、B的坐标以及u(u∈[0,1])的值,点C的坐标便为:C = A + (B - A) * u = (1 - u) * A + B * u。

       定义贝塞尔曲线的控制点Pi编号为0i,其中,0表示是第0次迭代。当第一、二、三……次迭代时,0将会被123……替换。

       德卡斯特里奥算法的思想如下:为了计算n次贝塞尔曲线上的点C(u), u∈[0,1],首先将控制点连接形成一条折线00-01-02……0(n - 1)-0n。利用上述方法,计算出折线中每条线段0j-0(j+1)上的一个点1j,使得点1j分该线段的比为u:1-u。然后在折线10-11-……-1(n-1)上递归调用该算法,以此类推。最终,求得最后一个点n0。德卡斯特里奥证明了,点n0一定是曲线上的点。

如上图,曲线控制点是000102030405。线段00-01上取点1010分该线段的比为u:1-u,类似地取点11、12、13、14,然后第二次迭代在线段10-11上取点20,点20分该线段的比为u:1-u,类似地取点21、22、23。然后进行下一次迭代,依次类推,直到最后在线段40-41上取点50,50是最终惟一的点,也是在曲线上的点。

上述直观的算法描述可以表达成一个计算方法。

 

首先,将所有给定的控制点排列成一列,在上图中,即为最左边的一列。每一对相邻的控制点可以伸出两个箭头,分别指向右下方和右上方。在相邻箭头的交叉处,生成一个新的控制点。例如,控制点iji(j +1)生成新的控制点(i + 1)j。指向右下方的箭头表示乘以(1 - u),指向右上方的箭头表示乘以u

因此,通过第0列,可以求出第1列,然后求出第2列……,最终,在n次迭代后,可以到达惟一的一个点n0,这个点就是曲线上的点。

该计算过程算法如下:

Input: array P[0:n] of n+1 points and real number u in [0,1] Output: point on curve, C(u) Working: point array Q[0:n] for i := 0 to n do

Q[i] := P[i]; // save input

for k := 1 to n do

for i := 0 to n - k do

Q[i] := (1 - u)Q[i] + u Q[i + 1];

return Q[0];

 

该计算方法可以推导出一个递归关系:

 

但是,直接通过递归方法计算Pi,j效率低下,其原因与通过递归方法计算斐波那契数列一样:递归方法有大量的重复计算。

德卡斯特里奥算法还有一个有趣的性质。对于同一列中的连续的一组控制点,对其应用德卡斯特里奥算法,那么由这些控制点确定的曲线上的点,就是以这组控制点为边的等边三角形中,与这些控制点相对的顶点。

例如:由控制点02030405确定的曲线上的,对应u的点是32,正如下图中蓝色的等边三角形所表示的。同样,控制点111213确定的曲线上的,对应u的点是31,如图,黄色三角形所示。

根据上面所述,通过给定一组u值,便可以计算出贝塞尔曲线上的坐标序列,从而绘制出贝塞尔曲线。

[csharp] view plain copy print ?
  1. // arrayCoordinate为控制点   
  2.   
  3. void CChildView::DrawBezier(CDC *pDC, const CArray<CPoint, CPoint>& arrayCoordinate)  
  4.   
  5. {  
  6.   
  7.     int n = 0;  
  8.   
  9.     if((n = arrayCoordinate.GetSize()) < 2)  
  10.   
  11.         return;  
  12.   
  13.   
  14.   
  15.     double *xarray = new double[n - 1];  
  16.   
  17.     double *yarray = new double[n - 1];  
  18.   
  19.   
  20.   
  21.     double x = arrayCoordinate.GetAt(0).x;  
  22.   
  23.     double y = arrayCoordinate.GetAt(0).y;  
  24.   
  25.   
  26.   
  27.     for(double t = 0.0; t <=1; t += 0.05 / n) // 调整参数t,计算贝塞尔曲线上的点的坐标,t即为上述u   
  28.   
  29.     {  
  30.   
  31.         for(int i = 1; i < n; ++i)  
  32.   
  33.         {  
  34.   
  35.             for(int j = 0; j < n - i; ++j)  
  36.   
  37.             {  
  38.   
  39.                 if(i == 1) // i==1时,第一次迭代,由已知控制点计算   
  40.   
  41.                 {  
  42.   
  43.                     xarray[j] = arrayCoordinate.GetAt(j).x * (1 - t) + arrayCoordinate[j + 1].x * t;  
  44.   
  45.                     yarray[j] = arrayCoordinate.GetAt(j).y * (1 - t) + arrayCoordinate[j + 1].y * t;  
  46.   
  47.                     continue;  
  48.   
  49.                 }  
  50.   
  51.   
  52.   
  53.                 // i != 1时,通过上一次迭代的结果计算   
  54.   
  55.                 xarray[j] = xarray[j] * (1 - t) + xarray[j + 1] * t;  
  56.   
  57.                 yarray[j] = yarray[j] * (1 - t) + yarray[j + 1] * t;  
  58.   
  59.             }  
  60.   
  61.         }  
  62.   
  63.   
  64.   
  65.         pDC->MoveTo(x, y);  
  66.   
  67.         pDC->LineTo(xarray[0], yarray[0]);  
  68.   
  69.         x = xarray[0];  
  70.   
  71.         y = yarray[0];  
  72.   
  73.     }  
  74.   
  75.   
  76.   
  77.     delete [] xarray;  
  78.   
  79.     delete [] yarray;  
  80.   





http://chatgpt.dhexx.cn/article/rK1LUCUa.shtml

相关文章

如何将多张图片合成一个pdf?

如何将多张图片合成一个pdf&#xff1f;平时我们都喜欢将word或者ppt文件转换成pdf后再使用&#xff0c;除此之外&#xff0c;我们还会将多张图片合并转换成pdf文件&#xff0c;大家会用什么方法将图片合并成pdf呢&#xff1f;我相信有很多小伙伴会使用这个方法&#xff0c;先将…

怎么把四个图片合成一个图片?

怎么把四个图片合成一个图片&#xff1f;关于图片的合成&#xff0c;我们一般都会用到图片处理软件来进行。但是对于一些职场新人来说&#xff0c;他根本不会用一些专业的图片处理软件&#xff0c;那么这个问题对他来说就是非常棘手的。其实遇到这样的问题&#xff0c;新人朋友…

python将多张图片合并成一张图片

文章目录 说明&#xff1a;合并图片的三个过程1、参考原博主的&#xff1a;2、优化第一个数量问题&#xff1a;3、优化俩个问题&#xff08;数量不限性状按比例变小&#xff09;4、优化黑行高度问题5、合成图片不清晰问题&#xff1a;总结下&#xff1a; 说明&#xff1a; 今天…

如何把一张图片分割成几张

把一张图片分割成几张的方法&#xff1a; 工具/原料&#xff1a;硬件&#xff1a;电脑、软件&#xff1a;Photoshop 7.0、系统&#xff1a;Windows10专业版64位操作系统。 1、打开平PS&#xff0c;进入新建文档里面&#xff0c;然后把图片直接拉到界面中。或者直接打开图片。 2…

jpg怎么合成一份_如何将多张图片合成一个文件

大家好&#xff0c;我是时间财富网智能客服时间君&#xff0c;上述问题将由我为大家进行解答。 将多张图片合成一个文件的方法是&#xff1a; 1、将所有图片拖到一个文件夹里&#xff0c;鼠标右键点击“添加压缩”。 2、点击确定&#xff0c;这样就成了一个文件。 计算机(compu…

怎样能把两张照片拼成一张图片,5种工具分享

怎样能把两张照片拼成一张图片&#xff1f;图片拼合的应用场景是很多的。比如将几张相册中的照片拼成一张合影、将多个地图截图拼合在一起形成一个更大的区域地图、将多个漫画图像合并成一本漫画册等。这项技术可以方便地将多张图片整合为一张&#xff0c;节省时间和精力。 因此…

怎么将几张照片合成一张图片,简单步骤易学

怎么将几张照片合成一张图片&#xff1f;在当代社会&#xff0c;图片已经成为了人们生活和工作中不可或缺的重要元素。无论是在网上浏览、社交媒体、电商平台、还是在企业营销、科研教育、娱乐创作等各种场合中&#xff0c;都有着广泛的应用。而将不同的图片进行合并&#xff0…

多张图片怎么合成一个pdf?

多张图片怎么合成一个pdf&#xff1f;相信大家和我一样&#xff0c;每天的工作或者生活学习都离不开pdf文件&#xff0c;因为pdf文件拥有更好的稳定性和安全性&#xff0c;不管是在电脑还是在其他设备上&#xff0c;都能正常的打开&#xff0c;而且pdf文件不易编辑的特性&#…

如何把两张图片拼在一起?

如何把两张图片拼在一起&#xff1f;一般来说&#xff0c;如果我们的照片只是简单处理的话&#xff0c;我们在手机上使用一些小软件就能完成&#xff0c;比如我们常使用的秀秀。但是如果说我们需要合成的照片是比较大的&#xff0c;那种专业相机拍出来的像素比较高。这种情况下…

多张图片合成一张jpg工具_如何将两张图片合成一张图片?

您可能感兴趣的话题&#xff1a; 美图秀秀 核心提示&#xff1a;图片叠加的方法也有几种&#xff0c;小编认为最好用、效果最好的是美图秀秀抠图叠加法。 看到许多网友焦急的询问一些图片处理方面的问题&#xff0c;一时又没人给点温馨的帮助&#xff0c;一向助人为乐的小编就坐…

多张图片怎么合成一个pdf文件?

小编作为一个上班族&#xff0c;每天会涉及到很多的图片文件&#xff0c;日积月累图片文件的整理和保存是一个任务艰巨的工作。那么如何更好的管理这些图片文件呢&#xff1f;小编有个好方法就是将有关系的某些图片文件全部整理到一个PDF文件内&#xff0c;这样一个类别的PDF包…

三张图片怎么拼成一张?

三张图片怎么拼成一张图片&#xff1f;相信大家平时都有往朋友圈分享图片的经历&#xff0c;朋友圈的九宫格是大部分人分享日常的常用方式&#xff0c;那如果大家想要分享的照片超过九张&#xff0c;就需要将图片拼接一下再发&#xff0c;这样就可以分享多张照片了。比如我将三…

怎么把多张图片合成为一张?

将多张图片合成为一张图片是在很多场合下都非常有必要的&#xff0c;例如设计制作等。其中&#xff0c;合成图片的关键性和重要性主要包括以下几点&#xff1a;首先&#xff0c;保证合并后的图片质量。在进行多张图片合成时&#xff0c;需要保证图片大小和分辨率的统一&#xf…

Python实现多张图片合成一张马赛克图片

前言 最近有网友私信我&#xff0c;问如何把多张图片合成一张马赛克图片的样子 说是女儿从出生到现在&#xff0c;所有的照片&#xff0c;大概有上百张&#xff0c;所以想使用这些照片合成一张&#xff0c;当做生日礼物 那我们今天就用上次爬表情包的图片来做一次马赛克图片…

两张图片怎样合成一张左右拼图?

相信很多小伙伴的手机和电脑上都储存了一定数量的图片&#xff0c;在使用这些图片的时候&#xff0c;因为一些需要有时候我们要将图片拼在一起使用&#xff0c;数量多的时候我们可以拼成长竖图或者长横图&#xff0c;当然也可以借助拼接软件里面的模板进行自由选择拼接。但是如…

怎么将三张图片合成一张图片?

怎么将三张图片合成一张图片&#xff1f;遇到这个问题&#xff0c;我们其实有很多方法来处理。我们首当其冲想到的是其中最常见的&#xff0c;可以使用我们手机的APP来处理&#xff0c;比如某秀秀等。但是此方法比较适合于尺寸比较小的图片进行合并&#xff0c;如果图片比较大的…

如何拼接多张图片,多张图片拼接成一张

如何拼接多张图片&#xff0c;多张图片拼接成一张&#xff1f;小编作为一名互联网行业的从业者&#xff0c;每天都需要使用到很多的图片&#xff0c;那么自然也需要对图片做各种不同的处理&#xff0c;例如格式转换、修改尺寸等。除了这些之外我还经常需要对图片进行拼接&#…

如何将两张图片上下合成一张?

如何将两张图片上下合成一张&#xff1f;不知道大家有没有遇到过这样的情况&#xff0c;工作中需要将两张图片上传到某个网站上&#xff0c;但是网站只能允许上传一张图片&#xff0c;相信很多小伙伴都有过这样的经历吧。这个时候大家会怎么办呢&#xff1f;有什么方法可以解决…

PhotoShop简单案例(3)——利用ps实现多图合成(多张小图片拼成一张大图片)

目录 一、项目介绍二、预处理2.1 图片裁剪2.2 多图裁剪2.3.1 新建动作2.3.2 图片裁剪2.3.3 批量裁剪 三、基本流程3.1 图像裁剪3.2 联系表3.3 图案填充3.4 其他 四、效果演示 一、项目介绍 本文将介绍利用ps实现多图合成&#xff08;多张小图片拼成一张大图片&#xff09;&…

如何把几张图片整合到一张图片?

如何把几张图片整合到一张图片&#xff1f;整合图片&#xff0c;也就是把几张图片拼接到一起&#xff0c;关于这样的方法&#xff0c;我想各位小伙伴或多或少都有一些自己的整合方法&#xff0c;鉴于每一种方法的转换效果和效率不同&#xff0c;可能有些小伙伴不再满足自己所使…