生成直线的Bresenham算法

DDA算法由于在循环中涉及实型数据的加减运算,因此直线的生成速度较慢。由Bresenham在1965年提出。设直线从起点(x1, y1)到终点(x2, y2)。直线可表示为方程y=mx+b。Bresenham算法是一种基于误差判别式来生成直线的方法。

一,直线Bresenham算法描述:

设(x1,y1)和(x2,y2)分别为所求直线的起点和终点坐标,由直线的微分方程

y2 – y1 / x2 – x1 = m =直线的斜率                 (1)

可通过计算由x方向的增量△x引起y的改变来生成直线:

xi+1=xi+△x                                                (2)

yi+1=yi+△y=yi+△x·m                               (3)

也可通过计算由y方向的增量△y引起x的改变来生成直线:

yi+1=yi+△y                                                 (4)

xi+1=xi+△x=xi+△y/m                                (5)

它也是采用递推步进的办法,令每次最大变化方向的坐标步进一个象素,同时另一个方向的坐标依据误差判别式的符号来决定是否也要步进一个象素。

我们首先讨论m=△y/△x,当0≤m≤1且x1<x2时的Bresenham算法。从DDA直线算法可知这些条件成立时,公式(2)、(3)可写成:

xi+1=xi+1                                                 (6)

yi+1=yi+m                                                (7)

有两种Bresenham算法思想,它们各自从不同角度介绍了Bresenham算法思想,得出的误差判别式都是一样的。

二、直线Bresenham算法思想之一:

由于显示直线的象素点只能取整数值坐标,可以假设直线上第i个象素点坐标为(xi,yi),它是直线上点(xi,yi)的最佳近似,并且xi=xi(假设m<1),如下图所示。那么,直线上下一个象素点的可能位置是(xi+1,yi)或(xi+1,yi+1)。

由图中可以知道,在x=xi+1处,直线上点的y值是y=m(xi+1)+b,该点离象素点(xi+1,yi)和象素点(xi+1,yi+1)的距离分别是d1和d2:

d1=y-yi=m(xi+1)+b-yi                        (8)

d2=(yi+1)-y=(yi+1)-m(xi+1)-b                (9)

这两个距离差是

d1-d2=2m(xi+1)-2yi+2b-1                    (10)
我们来分析公式(10):
    (1)当此值为正时,d1>d2,说明直线上理论点离(xi+1,yi+1)象素较近,下一个象素点应取(xi+1,yi+1)。
    (2)当此值为负时,d1<d2,说明直线上理论点离(xi+1,yi)象素较近,则下一个象素点应取(xi+1,yi)。
    (3)当此值为零时,说明直线上理论点离上、下两个象素点的距离相等,取哪个点都行,假设算法规定这种情况下取(xi+1,yi+1)作为下一个象素点。

因此只要利用(d1-d2)的符号就可以决定下一个象素点的选择。为此,我们进一步定义一个新的判别式:

pi=△x×(d1-d2)=2△y·xi-2△x·yi+c         (11)
式(11)中的△x=(x2-x1)>0,因此pi与(d1-d2)有相同的符号;

这里△y=y2-y1,m=△y/△x;c=2△y+△x(2b-1)。

下面对式(11)作进一步处理,以便得出误差判别递推公式并消除常数c。

将式(11)中的下标i改写成i+1,得到:

pi+1=2△y·xi+1-2△x·yi+1+c                (12)

将式(2-12)减去(2-11),并利用xi+1=xi+1,可得:

pi+1= pi+2△y-2△x·(yi+1-yi)               (13)

再假设直线的初始端点恰好是其象素点的坐标,即满足:

y1=mx1+b                                    (14)

由式(11)和式(14)得到p1的初始值:

p1=2△y-△x                                 (15)

这样,我们可利用误差判别变量,得到如下算法表示:

初始 p1=2△y-△x

当pi≥0时:

yi+1=yi+1,

xi+1=xi+1,
       pi+1=pi+2(△y-△x)                          (16)

否则:

yi+1=yi,
       xi+1=xi+1,
       pi+1=pi+2△y

从式(16)可以看出,第i+1步的判别变量pi+1仅与第i步的判别变量pi、直线的两个端点坐标分量差△x和△y有关,运算中只含有整数相加和乘2运算,而乘2可利用算术左移一位来完成,因此这个算法速度快并易于硬件实现。

三、直线Bresenham算法思想之二:

由于象素坐标的整数性,数学点(xi,yi)与所取象素点(xi,yir)间会引起误差(εi),当xi列上已用象素坐标(xi,yir)表示直线上的点(xi,yi),下一直线点B(xi+1,yi+1),是取象素点C(xi+1,yir ),还是D(xi+1,y(i+1)r)呢?

设A为CD边的中点,正确的选择:

若B点在A点上方,选择D点; 否则,选C点。

用误差式描述为:

ε(xi+1)=BC-AC=(yi+1-yir)-0.5                                        (8')

求递推公式:

ε(xi+2)=(yi+2-y(i+1)r)-0.5 = yi+1+m-y(i+1)r-0.5          (9')

当ε(xi+1)≥0时,选D点,y(i+1)r = yir+1

ε(xi+2)= yi+1+m-yir-1-0.5=ε(xi+1)+m-1                       (10')

当ε(xi+1)﹤0时,选C点,y(i+1)r = yir

ε(xi+2)= yi+1+m-yir-0.5=ε(xi+1)+m                           (11')

初始时:

ε(xs+1)=BC-AC=m-0.5                                                   (12')

为了运算中不含实型数,同时不影响不等式的判断,将方程两边同乘一正整数。

令方程两边同乘2·Δx,即d=2·Δx·ε,则:

初始时:d = 2·Δy-Δx                                                      (13')

递推式:

当d≥0时:

{

d=d+2·(Δy-Δx);
          y++;
          x++;
       }                                                                                   (14')
     否则:

{

d=d+2·Δy;
          x++;
        }

四、直线Bresenham算法完善:

现在我们修正(16)公式,以适应对任何方向及任何斜率线段的绘制。如下图所示,线段的方向可分为八种,从原点出发射向八个区。由线段按图中所示的区域位置可决定xi+1和yi+1的变换规律。

容易证明:当线段处于①、④、⑧、⑤区时,以|△x|和|△y|代替前面公式中的△x和△y,当线段处于②、③、⑥、⑦区时,将公式中的|△x|和|△y|对换,则上述两公式仍有效。

在线段起点区分线段方向

五、直线Bresenham算法特点:

由于程序中不含实型数运算,因此速度快、效率高,是一种有效的画线算法。

六、实现代码:

/************************************************************************* Function Name: rtLine Function Action: 直线Bresenham算法实现 Input Parameter: image--图像数据 pt1--直线段的端点之一 pt2--直线段的端点之二 thickness--线段的粗细程度 color--线段的颜色 Output Parameter: image--加了直线的图像数据 Return Value: NULL Author : WangFei 2010/5/28 12:58 Remark: *************************************************************************/ void rtLine(RtImage* image, RtPoint pt1, RtPoint pt2, int thickness, unsigned char* color) { int x = 0, y = 0, stepx = 0, stepy = 0, p = 0, i = 0, j = 0, k = 0, change = 0/*表示斜率大于45度,交换了dx, dy*/; RtPoint dp; dp.x = pt2.x - pt1.x; dp.y = pt2.y - pt1.y; if (dp.x > 0) stepx = 1; if (dp.y > 0) stepy = 1; dp.x = abs(dp.x); dp.y = abs(dp.y); if (dp.y > dp.x)//斜率大于45度 { swap(&dp.x, &dp.y);//交换x,y change = 1; } //初始 p1=2△y-△x p = (dp.y << 1) - dp.x; x = pt1.x; y = pt1.y; for(i = 1;i <= dp.x; i++)//从开始点到结束点 { for (j = 0; j < image->nChannels; j++)//图像通道,保证每个通道都可以包含数据 { for (k = 0; k < thickness; k++)//直线的绘制宽度 { *(image->pData + (y * image->width + x) * image->nChannels + j) = color[j]; if (change == 0) { *(image->pData + (max(y - k, 0) * image->width + x) * image->nChannels + j) = color[j]; *(image->pData + (min(y + k, image->height - 1) * image->width + x) * image->nChannels + j) = color[j]; } else { *(image->pData + (y * image->width + max(x - k, 0)) * image->nChannels + j) = color[j]; *(image->pData + (y * image->width + min(x + k, image->width - 1)) * image->nChannels + j) = color[j]; } } } /* 当pi≥0时: yi+1=yi+1, xi+1=xi+1, pi+1=pi+2(△y-△x) 否则: yi+1=yi, xi+1=xi+1, pi+1=pi+2△y */ if(p >= 0) { if(change == 0) y = y + stepy; else x = x + stepx; p = p - (dp.x << 1); } if(change == 0) x = x + stepx; else y = y + stepy; p = p + (dp.y << 1); } }

详细知识:http://jpkc.lit.edu.cn/09/jsjtxx/zxjx/index.htm

直线Bresenham算法相关推荐

  1. 计算机图形学学习(一) 直线Bresenham算法讲解及matlab实现

    文章目录 Bresenham算法介绍 Bresenham算法实现 matlab代码实现 成果演示 最后 Bresenham算法介绍 Bresenham是计算机图形学领域使用最广泛的直线扫描转换算法,其 ...

  2. Bresenham 算法原理

    http://wenku.baidu.com/link?url=ova6h39VQ4ilLMIQ51qHpjeuuKu7yLtD1M53NQQc6rUSI9UHymh2r2V8ZZdn6R3bForx ...

  3. java 2d划线 刷子_Java图形设计中,利用Bresenham算法实现直线线型,线宽的控制(NO2DGRAPHICS)...

    Java图形设计中,利用Bresenham算法实现直线线型,线宽的控制(NO2DGRAPHICS) (2007-04-05 23:37:39) Java 2D Graphics提供了强大的画线功能,可 ...

  4. 【转】直线光栅化算法-Bresenham算法

    [转]直线光栅化算法-Bresenham算法 https://blog.csdn.net/cjw_soledad/article/details/78886117 posted on 2019-03- ...

  5. 计算机图形学E2——OpenGL Bresenham算法画直线

    其他计算机图形学实验见 链接 要求 使用Bresemham算法画直线,并且通过鼠标可以实现交互操作 参考代码: 代码1 代码2 代码3(代码好理解) 代码4(讲解很全面) #include<io ...

  6. bresenham算法_二维光栅图形的扫描:直线的DDA、Bresenham算法与圆的生成

    数值微分DDA算法 算法原理 DDA算法是一个增量算法,每一步的x.y值是用前一步的值加上一个增量来获得的,每一步在最大位移方向上加1. 优点:算法直观.易实现 缺点:有浮点数和浮点运算,效率不高 代 ...

  7. 【计算机图形学】基于OpenGL的中点Bresenham算法画直线

    学习过三种画直线的方法(DDA.中点Bresenham算法.改进的中点Bresenham算法)后,想着实际操作一下如何能够实现,OpenGL无疑是很好的选择,在老师的推荐下,我尝试着用OpenGL来实 ...

  8. 计算机图形学 学习笔记(一):概述,直线扫描转换算法:DDA,中点画线算法,Bresenham算法

    前言 本笔记基于 http://www.icourse163.org/learn/CAU-45006?tid=1001746004#/learn/announce 感谢中国农大 赵明老师的分享~ 现在 ...

  9. 计算机图形学实习教程之基本图形的生成(直线DDA算法,直线中点算法,Bresenham画圆算法),利用C#实现,附源码

    环境:Win10+Visual Studio 2022 Community 在本次实验中需要用到上一篇文章实验内容的代码及环境,详情请见:传送门 目录 一.实验目的 二.实验过程 1.生成直线的DDA ...

最新文章

  1. 敏捷的项目启动-尽早启动!
  2. TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常!...
  3. Linux程序之触摸,linux 触摸屏驱动编写
  4. mysql8 安装_MySQL8.x安装使用
  5. Java中的equals和==的差别 以及Java中等价性和同一性的讨论
  6. 逻辑运算map函数filter函数reduce函数
  7. Make WAR file 1.0
  8. keras实现DCGAN生成mnist原代码
  9. 51单片机 呼吸灯 七彩呼吸灯
  10. 《工业控制系统信息安全防护指南》产品措施匹配表
  11. Windows 11通过WSA及ADB运行安卓应用
  12. visual studio 批量注释与取消批量注释快捷键
  13. 文本CSS多行溢出隐藏显示省略号
  14. input输入框短信验证码处理
  15. 利用Matlab将任意曲线旋转任意角度
  16. latex参考文献中修改指定作者的格式来突出显示
  17. 小白打boss之路——2020fintech训练营数据赛道
  18. mastercamx9专用程序单,mastercamx9程式单
  19. JUC之ForkJoin框架
  20. 三生三世十里桃花用计算机怎么弄,三生三世十里桃花ios如何用电脑玩 三生三世十里桃花ios模拟器教程...

热门文章

  1. 数据库基础--数据库基础管理(创建库/表 以及插入修改删除表数据)
  2. Python 高级编程和异步IO并发编程 --13_6 asyncio模拟http请求
  3. wincc上位机与1200组态步骤_博途v13的wincc能组态上位机吗
  4. RoBERTa: A Robustly Optimized BERT Pretraining Approach
  5. 骨架屏技术讲解以及如何在Vue中实现骨架屏
  6. Matlab中imshow函数用法
  7. 手把手教你我是如何用H5制作工具在微信上宣传我的店铺
  8. 23计算机考研, 153所大学专业/科目变动集合!
  9. 剑三千岛湖服务器是不是维护了,剑网3千岛湖倭寇泡澡怎么完成_剑网3千岛湖倭寇泡澡任务流程_牛游戏网...
  10. FPS(farthest_point_sample) 最远点采样并可视化(附open3d python代码)