本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、直线段的扫描转换算法
1.描述
数学上画一条直线需要无穷多的点,但计算机光栅显示器由像素点构成,故用屏幕上的点进行逼近。
为了在显示器上用离散的像素点逼近这条直线,首先需要知道这些像素点的(x,y)坐标
用的是斜截式方程: 其中
画直线的过程:已知起点P0(x0,y0)与k和b,然后让x1 = x0 +1,进而求y1,然后用同样的方法求y2,y3......
[注]:像素只能是整数,故为了减少误差,求出的y值采取四舍五入,如假设求出P1(1.8,0.8)则转化成(2,1)。
2.算法效率的提高
由于求y只是一个乘法和加法,且计算机做加法快,如果能够将乘法用一定的方法转换成加法,则可以提升算法的效率。下面是三个基于乘法换成加法这一思想的常用改进方法。
2.1数值微分法(DDA)
a.算法的基本思想
由于x每一次最小的变化是以一个像素点为单位,故我们可以得到在这条直线上的相邻两个坐标的递推式:
【注】:当|k| < 1时,点取得较密集,但是,当|k| >>1 时,这个直线上的点就很稀疏了。
b.算法的改进
一般情况下k与y都是小数,而且每一步运算都要对y进行四舍五入取整,唯一改进途径是把浮点运算变成整数加法。
2.2 中点画线法
a基本思想
采用直线的一般是f(x,y) = ax + by +c = 0;根据点与直线的关系:
f(x0,y0) > 0 则(x0,y0)在直线上方
f(x0,y0) < 0 则(x0,y0)在直线下方
f(x0,y0) = 0 则(x0,y0)在直线上
我们记 f(x0+1,y0+0.5) = d,根据: 若 d<0,点在直线下方,则下一个点取(x0+1,y0+1);否则,取(x0+1,y0);
用式子来描述就是
b中点画线算法的改进
根据上面的式子看出,中点画线法计算量明显比DDA多,那么如何改进?能不能也采用增量的方式弄出个?
我们只是想知道下一个点是还是
下面贴出推导:
当<0时
=
+ A + B
当>0时
也就是说,根据的正负可以判断选择哪个点,根据这个递推关系
可以判断下一个点选啥。
那么初始值:
综上:
c.总结:
采用直线一般式
只通过判断中点的符号,最终可以只进行整数加法
2.3 Bresenham算法
a.算法基本思想
由于上述算法都限定在了直线的范围,BBresenham算法相当于中点画线算法的扩展。
该算法思想是通过各行各列像素中心构造一组虚拟网络网格线,按照直线起点到终点的顺序,计算直线与个垂直网格线的交点,然后根据误差项的符号判断该列像素中与此交点最近像素。
用图表示就是这样:
每次x+1,y要吗加1要么加0,取决于实际直线与最近光栅网格点的距离,这个距离的最大误差为0.5(当实际直线正好在
与
的中点时)。
误差项 =
+k,其中由图可以看出
为0。
当d>1时,为保证d的相对性,且在0、1之间,令d = d - 1。
将此算法进行改进到整数加法:
可以理解为:e>0,y方向递增1;e<0,y方向不递增
e = 0 时,可任取上、下光栅点显示
e初 = -0.5,每走一步有e = e+k,if (e>0) then e=e-1
改进2:由于算法中只用到误差项的符号,于是可以用e2△x来替换e。
e初 = -△x,
每走一步有:e = e+2△y。(k = 2△xk = 2△y)
if (e>0) then e = e-2△x 此时取(x+1,y+1),否则取(x+1,y)
另一种思想:
举个例子:
Bresenham算法和DDA算法很像,都是加斜率,但Bresenham只是判断符号决定上下两个点,无需求出新y后取整,故应用范围广泛。
任意斜率中点画线算法matlab实现
首先推导各个斜率下与
以及
的关系
当 0<k<1时
if
else
其中 d0 = A +0.5B
当 k>1 时(y轴加一,看x轴的正负)画图一目了然
if
else
其中 d0 = 0.5A +B
当 k>-1 且k<0 时
if
else
其中 d0 = A - 0.5B
当k<-1时这里就不再推了,大家可以自己去尝试,
function midpointline(x0,y0,x1,y1)
k = (y1-y0)/(x1-x0);
x=x0;y=y0;
b=x1-x0;a=y0 - y1; %这个式子是用已知直线两个点,求一般式画出来的
if(k<1 && k>0)
grid on;hold on;
plot(x,y,'o');
d0=2*a+b;
d1=2*a;
d2=2*(a+b);
while (x<x1)
if(d0 >=0)
x=x+1;
d0 =d0+d1;
elseif(d0 < 0)
x=x+1;y=y+1;d0=d0+d2;
end
hold on;
plot(x,y,'o');
end
elseif(k>1)
grid on;hold on;
plot(x,y,'o');
d0=a+2*b;
d1=2*(a+b);
d2=2*b;
while (y<y1)
if(d0 >=0)
x = x + 1;
y = y + 1;
d0 =d0 + d1;
elseif(d0 < 0)
y=y+1;d0=d0+d2;
end
hold on;
plot(x,y,'o');
end
elseif(k>-1 && k<0)
grid on;hold on;
plot(x,y,'o');
d0=2*a-b;
d1=2*(a-b);
d2=2*a;
while (x<x1)
if(d0 >=0)
x = x + 1;
y = y - 1;
d0 =d0 + d1;
elseif(d0 < 0)
x=x+1;d0=d0+d2;
end
hold on;
plot(x,y,'o');
end
elseif(k<-1)
grid on;hold on;
plot(x,y,'o');
d0=a-2*b;
d1=-2*b;
d2=2*(a-b);
while (x<x1)
if(d0 >=0)
y = y - 1;
d0 =d0 + d1;
elseif(d0 < 0)
x=x+1;y=y-1;d0=d0+d2;
end
hold on;
plot(x,y,'o');
end
end
end