小白谈计算机图形学(一)画线篇之DDA算法,中点画线法,Bresenham画线法及相关改进详解

小白谈计算机图形学(一)画线篇之DDA算法,中点画线法,Bresenham画线法及相关改进详解

  • 引言
  • 如何画线
    • 基本思想
    • 数值微分法(DDA算法)
      • 数值微分基本思路
      • 数值微分改进
    • 中点画线法
      • 中点画线引言
      • 中点画线改进
    • Bresenham画线法
      • Bresenham基本思路
      • Bresenham画线改进
    • 小结
  • 超链接

引言

大家好,众所周知,计算机的图像显示是由一个一个像素组成,正如分子组成了世界,当像素合理分布,同样可以还原很多真实世界的场景。

如何画线

基本思想

已知过端点 p 0 ( x 0 , y 0 ) p_0(x_0,y_0) p0(x0,y0) p 1 ( x 1 , y 1 ) p_1(x_1,y_1) p1(x1,y1)的直线:
y = k x + b y=kx+b y=kx+b
直观的做法是把每个 x x x的值代入直线方程求出相应的 y y y值。取像素点 ( x , i n t ( y ) ) (x, int(y)) (x,int(y))作为当前点坐标。光栅直线算法属于图形学最底层的算法,因此要精益求精。

数值微分法(DDA算法)

数值微分基本思路

增量算法变乘法为加法,这里利用斜截式,首先 y i + 1 = y i + k Δ x y_{i+1}= y_i+ k\Delta x yi+1=yi+kΔx,当 Δ x = 1 \Delta x=1 Δx=1时:
y i + 1 = y i + k y_{i+1}= y_i+ k yi+1=yi+k

数值微分改进

  • 此处,我们做细节处理,将像素格划分为上半和下半, 用 i n t ( y + 0.5 ) int(y+0.5) int(y+0.5)判断是上方还是下方涂色。
    小白谈计算机图形学(一)画线篇之DDA算法,中点画线法,Bresenham画线法及相关改进详解_第1张图片
  • 同时该算法只能画 ∣ k ∣ ≤ 1 |k| \leq1 k1,超过则会出现离散的点,失真。可以采用:
    { y i + 1 = y i + k ( ︱ k ︱ < 1 , Δ x = 1 ) x i + 1 = x i + 1 k ( ︱ k ︱ > 1 , Δ y = 1 ) \left\{ \begin{aligned} y_{i+1} = y_i+k( ︱k︱<1,\Delta x =1)\\ \\ x_{i+1} = x_i+\frac{1}{k}( ︱k︱>1,\Delta y =1) \end{aligned} \right. yi+1=yi+k(k1Δx=1xi+1=xi+k1(k1Δy=1
  • 优点:简单直观,迭代的算法
    缺点:浮点运算,每步都需四舍五入取整。

中点画线法

中点画线引言

利用后一中点与前一中点的函数关系,采用了直线的一般式方程
F ( x , y ) = y − y 1 − y 0 x 1 − x 0 x − b F(x,y)=y-\frac{y_1-y_0}{x_1-x_0}x-b F(x,y)=yx1x0y1y0xb
认为 Δ x > 0 \Delta x>0 Δx>0,即:
F ( x , y ) = ( Δ x ) y − ( Δ y ) x − ( Δ x ) b F(x,y)=(\Delta x)y-(\Delta y)x-(\Delta x)b F(x,y)=(Δx)y(Δy)x(Δx)b
直线方程将平面分为三个区域:
{ F ( x , y ) = 0 ( 直 线 上 的 点 ) F ( x , y ) > 0 ( 直 线 上 方 的 点 ) F ( x , y ) < 0 ( 直 线 下 方 的 点 ) \left\{ \begin{aligned} F(x, y) = 0(直线上的点)\\ F(x, y) > 0(直线上方的点) \\ F(x, y) < 0(直线下方的点) \end{aligned} \right. F(x,y)=0(线)F(x,y)>0(线)F(x,y)<0(线)
小白谈计算机图形学(一)画线篇之DDA算法,中点画线法,Bresenham画线法及相关改进详解_第2张图片
M M M Q Q Q的下方,则说明 P u P_u Pu离直线近,应为下一个像素点;当 M M M Q Q Q的上方,应取 P d P_d Pd 为下一点。但是…每一个像素的计算量是4个加法,两个乘法。比DDA算法的计算量大多了,毫无可取之处!

中点画线改进

根据上一次计算的 d d d值判断接下来 d d d值的变化

  • d < 0 d<0 d<0时,则取右上方像素 p u ( x i + 1 , y i + 1 ) p_u(x_i+1, y_i+1) pu(xi+1,yi+1)。判断再下一
    像素,则要计算:
    d n e w = F ( x i + 2 , y i + 1.5 ) = a ( x i + 1 ) + b ( y i + 0.5 ) + c + a = F ( x i + 1 , y i + 0.5 ) + a + b = d o l d + a + b \begin{aligned} d_{new}&=F(x_i+2,y_i+1.5)\\ &=a(x_i+1)+b(y_i+0.5)+c+a\\ &=F(x_i+1,y_i+0.5)+a+b\\ &=d_{old}+a+b \end{aligned} dnew=F(xi+2,yi+1.5)=a(xi+1)+b(yi+0.5)+c+a=F(xi+1,yi+0.5)+a+b=dold+a+b
  • d ≥ 0 d \geq 0 d0情况,则取正右方像素 ( x i + 1 , y i ) (x_i+1, y_i) (xi+1,yi), 判断下一个像素位置要计算:
    d n e w = F ( x i + 2 , y i + 0.5 ) = a ( x i + 1 ) + b ( y i + 0.5 ) + c + a = F ( x i + 1 , y i + 0.5 ) + a = d o l d + a \begin{aligned} d_{new}&=F(x_i+2,y_i+0.5)\\ &=a(x_i+1)+b(y_i+0.5)+c+a\\ &=F(x_i+1,y_i+0.5)+a\\ &=d_{old}+a \end{aligned} dnew=F(xi+2,yi+0.5)=a(xi+1)+b(yi+0.5)+c+a=F(xi+1,yi+0.5)+a=dold+a
  • 迭代需要初始值 d 0 d_0 d0
    d 0 = F ( x 0 + 1 , y 0 + 0.5 ) = a ( x 0 + 1 ) + b ( y 0 + 0.5 ) + c = a + 0.5 b \begin{aligned} d_0&=F(x_0+1,y_0+0.5) \\&=a(x_0+1)+b(y_0+0.5)+c \\&=a+0.5b \end{aligned} d0=F(x0+1,y0+0.5)=a(x0+1)+b(y0+0.5)+c=a+0.5b
  • 由于我们只用 d d d的符号,所以使用 2 d 2d 2d摆脱小数运算更新后的公式为:
    { d 0 = 2 a + b d n e w = d o l d + 2 a + 2 b ( d < 0 ) d n e w = d o l d + 2 a ( d ≥ 0 ) \left\{ \begin{aligned} &d_0= 2a+b\\ &d_{new}=d_{old}+2a+2b(d<0) \\ &d_{new}=d_{old}+2a(d \geq 0) \end{aligned} \right. d0=2a+bdnew=dold+2a+2b(d<0)dnew=dold+2a(d0)

Bresenham画线法

Bresenham基本思路

采用增量计算,检查误差项的符号,就可以确定该列的所求像素。

  • 直线的起始点在像素中心,所以误差项d的初值
    { d 0 = 0 d n e w = d o l d + k x i + 1 = x i + 1 ( 右 移 一 格 ) y i + 1 = { y i + 1 , d = d − 1 ( d ≥ 0.5 ) ( 上 移 一 格 ) y i ( d < 0.5 ) ( 保 持 不 动 ) \left\{ \begin{aligned} &d_0=0\\ &d_{new}=d_{old}+k\\ &x_{i+1}= x_i+1(右移一格)\\ &y_{i+1}= \left\{ \begin{aligned} &y_i+1,d=d-1&(d\geq0.5)(上移一格)\\ \\ &y_{i}&(d < 0.5)(保持不动) \end{aligned} \right. \\ \end{aligned} \right. d00dnew=dold+kxi+1=xi+1()yi+1=yi+1,d=d1yi(d0.5)()(d<0.5)()
    小白谈计算机图形学(一)画线篇之DDA算法,中点画线法,Bresenham画线法及相关改进详解_第3张图片

Bresenham画线改进

  • e = d − 0.5 e=d-0.5 e=d0.5
    { e 0 = − 0.5 e n e w = e o l d + k x i + 1 = x i + 1 ( 右 移 一 格 ) y i + 1 = { y i + 1 , e = e − 1 ( e ≥ 0 ) ( 上 移 一 格 ) y i ( e < 0 ) ( 保 持 不 动 ) \left\{ \begin{aligned} &e_0=-0.5\\ &e_{new}=e_{old}+k\\ &x_{i+1}= x_i+1(右移一格)\\ &y_{i+1}= \left\{ \begin{aligned} &y_i+1,e=e-1&(e\geq0)(上移一格)\\ \\ &y_{i}&(e < 0)(保持不动) \end{aligned} \right. \\ \end{aligned} \right. e0=0.5enew=eold+kxi+1=xi+1()yi+1=yi+1,e=e1yi(e0)()(e<0)()
  • e ∗ 2 e*2 e2 e 0 e_0 e0变为整数,由于 p 0 ( x 0 , y 0 ) , p 1 ( x 1 , y 1 ) p_0(x_0,y_0),p_1(x_1,y_1) p0(x0,y0),p1(x1,y1)皆为整数,故 d ∗ Δ x d* \Delta x dΔx即为斜率乘 Δ x \Delta x Δx即为 Δ y \Delta y Δy为整数,故第二步改进令:
    e = e ∗ 2 ∗ Δ x e=e*2*\Delta x e=e2Δx
    判断 e e e的正负,更新后的公式为:
    { e = − Δ x ( 初 始 值 ) e n e w = e o l d + 2 Δ y ( 初 始 值 ) x i + 1 = x i + 1 ( 右 移 一 格 ) y i + 1 = { y i + 1 , e = e − 2 Δ x ( e ≥ 0 ) ( 上 移 一 格 ) y i ( e < 0 ) ( 保 持 不 动 ) \left\{ \begin{aligned} &e= -\Delta x(初始值)\\ &e_{new}= e_{old}+2\Delta y(初始值)\\ &x_{i+1}= x_{i}+1(右移一格)\\ &y_{i+1}= \left\{ \begin{aligned} &y_i+1,e=e-2\Delta x&(e\geq0)(上移一格)\\ \\ &y_{i}&(e < 0)(保持不动) \end{aligned} \right. \\ \end{aligned} \right. e=Δx()enew=eold+2Δy()xi+1=xi+1()yi+1=yi+1,e=e2Δxyi(e0)()(e<0)()

小结

避免浮点运算,进行整数算法判断像素点位置,就必须判断符号,如中点画线法和Bresenhanm算法,判断大小不能搞成整数加法。
wuli放几张做好的图,大家康康c语言可以画图呀!
小白谈计算机图形学(一)画线篇之DDA算法,中点画线法,Bresenham画线法及相关改进详解_第4张图片小白谈计算机图形学(一)画线篇之DDA算法,中点画线法,Bresenham画线法及相关改进详解_第5张图片小白谈计算机图形学(一)画线篇之DDA算法,中点画线法,Bresenham画线法及相关改进详解_第6张图片小白谈计算机图形学(一)画线篇之DDA算法,中点画线法,Bresenham画线法及相关改进详解_第7张图片

超链接

如果你还想了解其他内容:
小白谈计算机图形学(一)如何画线
小白谈计算机图形学(二)如何画圆
小白谈计算机图形学(三)二维图形裁剪
小白谈计算机图形学(四)二维三维图形变换—1

你可能感兴趣的:(计算机图形学)