Bresenham 算法由 Bresenham 在 1965 年提出,是计算机图形学领域中使用最为广泛的线段光栅化算法。该算法最初是为数字绘图仪设计的,由于它也适用于光栅图形显示器,后来被广泛应用于直线的光栅化与其他一些应用。
为方便讨论,这里假设直线斜率在(0,1)之间
假设直线方程为y = kx+b ,当前扫描转换得到的像素点为 Pi,则下一个与直
线最近的像素只能是正右方的或者右上方的 。
要想知道是正右方还是右上方,只需要知道d1和d2哪个大即可。因此我们的目标转换为判断d1-d2是否大于0.
ei = d1 - d2 = ||QQ1|| - ||QQ2||
= [k(xi + 1) + b - yi] - [yi + 1 - (k(xi + 1) + b)]
= 2kxi - 2yi + 2b + 2k -1
2b + 2k -1是一个常数,因此,类似于 DDA 算法的思想,在计算下一个像素点的误差 时,可以基于当前误差 计算误差的增量,从而简化这一常数的计算,即:
e(i+1) = 2kx(i+1) - 2y(i+1) + 2b + 2k -1
= 2k (xi + 1) - 2y(i+1) + 2b + 2k -1 //因为k为(0,1)因此x(i+1) = xi + 1
= 2kxi - 2yi + 2b + 2k - 1 - 2y(i+1) + 2yi + 2k
= ei - 2(y(i+1) - yi) + 2k
其中 k = dy / dx 仍然是一个浮点数,因为dx>0 ,因此dx*(d1 - d2)并不会改变符号,我们也只需要知道结果是否大于0,上式两边同时乘以dx:
dxe(i+1) = dxei - 2(y(i+1) - yi)dx +2dy
重新记ei = dxei :
e(i+1) = ei - 2(y(i+1) - yi)dx + 2dy
由ei的定义以及上式我们可以分析得到:
(1) 若 ei >= 0,即 d1>=d2,选取右上方的点,则 y(i+1) = yi +1,因此 e(i+1) = ei +2dy -2dx;
(2) 若 ei < 0,即 d1<d2,选取正右方的点,则 y(i+1) = yi,因此 e(i+1) = ei +2dy ;
e1 = dx( 2kx1 - 2y1 + 2b + 2k -1),直线过(x1, y1)因此:
e1 = dx(d1 - d2) = dx(2k -1) = 2dy - dx
按照这个描述我们可以写出代码:
# 仅使用于斜率小于1并且dx = x2 - x1 > 0的情况
def BresenhamLine(x1, y1, x2, y2, color):
dx = x2 - x1
dy = y2 - y1
# e1 的值
e = 2 * dy - dx
x = x1
y = y1
for i in range(0, int(dx + 1)):
plt.plot(x, y, color)
# 如果e >= 0 ,选取右上方的点,y(i+1) = yi + 1,否则y(i+1) = yi
# 若 ei >= 0, e(i+1) = ei +2dy -2dx,否则 e(i+1) = ei +2dy
if e >= 0:
y += 1
e -= 2 * dx
e += 2 * dy
x += 1
plt.show()
通用的Bresenham算法:
# 通用的Bresenham算法
def GenericBresenhamLine(x1, y1, x2, y2, color):
dx = abs(x2 - x1)
dy = abs(y2 - y1)
# 根据直线的走势方向,设置变化的单位是正是负
s1 = 1 if ((x2 - x1) > 0) else -1
s2 = 1 if ((y2 - y1) > 0) else -1
# 根据斜率的大小,交换dx和dy,可以理解为变化x轴和y轴使得斜率的绝对值为(0,1)
boolInterChange = False
if dy > dx:
np.swapaxes(dx, dy)
boolInterChange = True
# 初始误差
e = 2 * dy - dx
x = x1
y = y1
for i in range(0, int(dx + 1)):
plt.plot(x, y, color)
if e >= 0:
# 此时要选择横纵坐标都不同的点,根据斜率的不同,让变化小的一边变化一个单位
if boolInterChange:
x += s1
else:
y += s2
e -= 2 * dx
# 根据斜率的不同,让变化大的方向改变一单位,保证两边的变化小于等于1单位,让直线更加均匀
if boolInterChange:
y += s2
else:
x += s1
e += 2 * dy
plt.show()
算法特点:
(1) 不必计算直线之斜率,因此不必做除法;
(2) 不用浮点数,只用整数;
(3) 只做整数加减法和乘 2 运算,而乘 2 运算可以用硬件移位实现。
因此整个算法速度很快,并适合于用硬件实现。