引言
大家好,众所周知,计算机的图像显示是由一个一个像素组成,正如分子组成了世界,当像素合理分布,同样可以还原很多真实世界的场景。
如何画线
基本思想
已知过端点
p0(x0,y0)和
p1(x1,y1)的直线:
y=kx+b
直观的做法是把每个
x的值代入直线方程求出相应的
y值。取像素点
(x,int(y))作为当前点坐标。光栅直线算法属于图形学最底层的算法,因此要精益求精。
数值微分法(DDA算法)
数值微分基本思路
增量算法变乘法为加法,这里利用斜截式,首先
yi+1=yi+kΔx,当
Δx=1时:
yi+1=yi+k
数值微分改进
- 此处,我们做细节处理,将像素格划分为上半和下半, 用
int(y+0.5)判断是上方还是下方涂色。
- 同时该算法只能画
∣k∣≤1,超过则会出现离散的点,失真。可以采用:
⎩⎪⎪⎪⎨⎪⎪⎪⎧yi+1=yi+k(︱k︱<1,Δx=1)xi+1=xi+k1(︱k︱>1,Δy=1)
- 优点:简单直观,迭代的算法
缺点:浮点运算,每步都需四舍五入取整。
中点画线法
中点画线引言
利用后一中点与前一中点的函数关系,采用了直线的一般式方程:
F(x,y)=y−x1−x0y1−y0x−b
认为
Δx>0,即:
F(x,y)=(Δx)y−(Δy)x−(Δx)b
直线方程将平面分为三个区域:
⎩⎪⎨⎪⎧F(x,y)=0(直线上的点)F(x,y)>0(直线上方的点)F(x,y)<0(直线下方的点)
当
M在
Q的下方,则说明
Pu离直线近,应为下一个像素点;当
M在
Q的上方,应取
Pd 为下一点。但是…每一个像素的计算量是4个加法,两个乘法。比DDA算法的计算量大多了,毫无可取之处!
中点画线改进
根据上一次计算的
d值判断接下来
d值的变化
- 若
d<0时,则取右上方像素
pu(xi+1,yi+1)。判断再下一
像素,则要计算:
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情况,则取正右方像素
(xi+1,yi), 判断下一个像素位置要计算:
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
- 迭代需要初始值
d0
d0=F(x0+1,y0+0.5)=a(x0+1)+b(y0+0.5)+c=a+0.5b
- 由于我们只用
d的符号,所以使用
2d摆脱小数运算,更新后的公式为:
⎩⎪⎨⎪⎧d0=2a+bdold=dnew+2a+2b(d<0)dold=dnew+2a(d≥0)
Bresenham画线法
Bresenham基本思路
采用增量计算,检查误差项的符号,就可以确定该列的所求像素。
- 直线的起始点在像素中心,所以误差项d的初值
⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧d0=0dnew=dold+kxi+1=xi+1(右移一格)yi+1=⎩⎪⎨⎪⎧yi+1,d=d−1yi(d≥0.5)(上移一格)(d<0.5)(保持不动)
Bresenham画线改进
- 令
e=d−0.5
⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧e0=−0.5enew=eold+kxi+1=xi+1(右移一格)yi+1=⎩⎪⎨⎪⎧yi+1,d=d−1yi(e≥0)(上移一格)(e<0)(保持不动)
-
e∗2将
e0变为整数,由于
p0(x0,y0),p1(x1,y1)皆为整数,故
d∗Δx即为斜率乘
Δx即为
Δy为整数,故第二步改进令:
e=e∗2∗Δx
判断
e的正负,更新后的公式为:
⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧e=−Δx(初始值)enew=eold+2Δy(初始值)xi+1=xi+1(右移一格)yi+1=⎩⎪⎨⎪⎧yi+1,e=e−2Δxyi(e≥0)(上移一格)(e<0)(保持不动)
小结
想避免浮点运算,进行整数算法判断像素点位置,就必须判断符号,如中点画线法和Bresenhanm算法,判断大小不能搞成整数加法。
wuli放几张做好的图,大家康康c语言可以画图呀!