现在的计算机的图像的都是用像素表示的,无论是点、直线、圆或其他图形最终都会以点的形式显示。人们看到屏幕的直线只不过是模拟出来的,人眼不能分辨出来而已。那么计算机是如何画直线的呢,其实有比较多的算法,这里讲的是Bresenham的算法,是光栅化的画直线算法。直线光栅化是指用像素点来模拟直线,比如下图用蓝色的像素点来模拟红色的直线。

给定两个点起点P1(x1, y1), P2(x2, y2),如何画它们直连的直线呢,即是如何得到上图所示的蓝色的点。假设直线的斜率0<k>0,直线在第一象限,Bresenham算法的过程如下:

1.画起点(x1, y1).

2.准备画下一个点,X坐标加1,判断如果达到终点,则完成。否则找下一个点,由图可知要画的点要么为当前点的右邻接点,要么是当前点的右上邻接点。

  2.1.如果线段ax+by+c=0与x=x1+1的交点y坐标大于(y+*y+1))/2则选右上那个点

  2.2.否则选右下那个点。

3.画点

4.跳回第2步

5.结束

  算法的具体过程是怎样的呢,其实就是在每次画点的时候选取与实现直线的交点y坐标的差最小的那个点,例如下图:

关键是如何找最近的点,每次x都递增1,y则增1或者不增1,由上图,假设已经画了d1点,那么接下来x加1,但是选d2 还是u点呢,直观上可以知道d2与目标直线和x+1直线的交点比较近即纵坐标之差小也即与(x+1, y+1)点纵坐标差大于0.5,所当然是选d2,其他点了是这个道理。

一、             算法原理简介:

算法原理的详细描述及部分实现可参考:

http://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html

假设以(x, y)为绘制起点,一般情况下的直观想法是先求m = dy /dx(即x每增加1, y的增量),然后逐步递增x, 设新的点为x1 = x + j, 则y1 = round(y + j * m)。可以看到,这个过程涉及大量的浮点运算,效率上是比较低的(特别是在嵌入式应用中,DSP可以一周期内完成2次乘法,一次浮点却要上百个周期)。

下面,我们来看一下Bresenham算法,如Fig. 1,(x, y +ε)的下一个点为(x, y + ε + m),这里ε为累加误差。可以看出,当ε+m < 0.5时,绘制(x + 1, y)点,否则绘制(x + 1, y + 1)点。每次绘制后,ε将更新为新值:

ε = ε + m ,如果(ε + m) <0.5 (或表示为2*(ε + m) < 1)

ε = ε + m – 1, 其他情况

将上述公式都乘以dx, 并将ε*dx用新符号ξ表示,可得

ξ = ξ + dy, 如果2*(ξ + dy) < dx

ξ = ξ + dy – dx, 其他情况

可以看到,此时运算已经全变为整数了。以下为算法的伪代码:

ξ ← 0, y ← y1

For x ← x1 to x2 do

Plot Point at (x, y)

If (2(ξ + dy) < dx)

ξ ←ξ + dy

Else

y ← y + 1,ξ ←ξ + dy – dx

End If

End For

二、             算法的注意点:

在实际应用中,我们会发现,当dy > dx或出现Fig.2 右图情况时时,便得不到想要的结果,这是由于我们只考虑dx > dy, 且x, y的增量均为正的情况所致。经过分析,需要考虑8种不同的情况,如Fig. 3所示:

当然,如果直接在算法中对8种情况分别枚举, 那重复代码便会显得十分臃肿,因此在设计算法时必须充分考虑上述各种情况的共性,后面将给出考虑了所有情况的实现代码。

三、             算法的实现

以下代码的测试是利用Opencv 2.0进行的,根据需要,只要稍微修改代码便能适应不同环境

代码1:

int CEnginApp::Draw_Line(int x0, int y0, // starting position int x1, int y1, // ending positionCOLORREF color,    // color indexUNINT *vb_start, int lpitch) // video buffer and memory pitch
{// this function draws a line from xo,yo to x1,y1 using differential error// terms (based on Bresenahams work)
RECT cRect;//GetWindowRect(m_hwnd,&m_x2d_ClientRect);
GetClientRect(m_hwnd, &cRect);ClientToScreen(m_hwnd, (LPPOINT)&cRect);ClientToScreen(m_hwnd, (LPPOINT)&cRect+1);vb_start = vb_start + cRect.left + cRect.top*lpitch;int dx,             // difference in x'sdy,             // difference in y'sdx2,            // dx,dy * 2
        dy2, x_inc,          // amount in pixel space to move during drawingy_inc,          // amount in pixel space to move during drawingerror,          // the discriminant i.e. error i.e. decision variableindex;          // used for looping// pre-compute first pixel address in video buffervb_start = vb_start + x0 + y0*lpitch;// compute horizontal and vertical deltasdx = x1-x0;dy = y1-y0;// test which direction the line is going in i.e. slope angleif (dx>=0){x_inc = 1;} // end if line is moving rightelse{x_inc = -1;dx    = -dx;  // need absolute value
} // end else moving left// test y component of slopeif (dy>=0){y_inc = lpitch;} // end if line is moving downelse{y_inc = -lpitch;dy    = -dy;  // need absolute value
} // end else moving up// compute (dx,dy) * 2dx2 = dx << 1;dy2 = dy << 1;// now based on which delta is greater we can draw the lineif (dx > dy){// initialize error termerror = dy2 - dx; // draw the linefor (index=0; index <= dx; index++){// set the pixel*vb_start = color;// test if error has overflowedif (error >= 0) {error-=dx2;// move to next linevb_start+=y_inc;} // end if error overflowed// adjust the error termerror+=dy2;// move to the next pixelvb_start+=x_inc;} // end for
} // end if |slope| <= 1else{// initialize error termerror = dx2 - dy; // draw the linefor (index=0; index <= dy; index++){// set the pixel*vb_start = color;// test if error overflowedif (error >= 0){error-=dy2;// move to next linevb_start+=x_inc;} // end if error overflowed// adjust the error termerror+=dx2;// move to the next pixelvb_start+=y_inc;} // end for
} // end else |slope| > 1// return successreturn(1);} // end Draw_Line

代码2:

int CEnginApp::Draw_Line2(int x1,int y1,int x2, int y2,COLORREF color,UNINT *vb_start, int lpitch)
{RECT cRect;//GetWindowRect(m_hwnd,&m_x2d_ClientRect);
GetClientRect(m_hwnd, &cRect);ClientToScreen(m_hwnd, (LPPOINT)&cRect);ClientToScreen(m_hwnd, (LPPOINT)&cRect+1);vb_start = vb_start + cRect.left + cRect.top*lpitch;int dx = x2 - x1;int dy = y2 - y1;int ux = ((dx > 0) << 1) - 1;//x的增量方向,取或-1int uy = ((dy > 0) << 1) - 1;//y的增量方向,取或-1int x = x1, y = y1, eps;//eps为累加误差
eps = 0;dx = abs(dx); dy = abs(dy); if (dx > dy) {for (x = x1; x != x2; x += ux){Plot_Pixel_32(x,y,0,255,0,255,vb_start,lpitch);eps += dy;if ((eps << 1) >= dx){y += uy; eps -= dx;}}}else{for (y = y1; y != y2; y += uy){Plot_Pixel_32(x,y,0,255,0,255,vb_start,lpitch);eps += dx;if ((eps << 1) >= dy){x += ux; eps -= dy;}}}      return 1;
}

调用代码:

                        DD_INIT_STRUCT(ddsd);if (FAILED(lpSface[PrimarySface]->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL)))return false;int x1,y1,x2,y2;for (int i=0;i<100;i++){srand(time(0));x1=rand()%750;y1=rand()%550;x2=rand()%750;y2=rand()%550;Draw_Line2(x1,y1,x2,y2,RGB(0,255,0),(UNINT *)ddsd.lpSurface,ddsd.lPitch>>2);}if (FAILED(lpSface[PrimarySface]->Unlock(NULL)))return false;

效果图:

转自:http://www.cnblogs.com/gamesky/archive/2012/08/21/2648623.html

Bresenham快速画直线算法相关推荐

  1. 【转】Bresenham快速画直线算法

    一.             算法原理简介: 算法原理的详细描述及部分实现可参考: http://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresen ...

  2. C语言快速画直线和画圆的代码

    具体算法的原理我没有深入研究,总之用来快速画直线和画圆是目前很成熟的算法,拿来就用了^-^ 整个算法过程中只用了整数加减和移位,非常适用于运算能力有限的单片机系统. 以下代码只需要把SetPixel替 ...

  3. 图形学画直线c语言,计算机图形学:3种画直线算法(转)

    //--------------------------------------------------------------------- //绘制直线的DDA算法基本函数 //--------- ...

  4. 0.96寸OLED用两点式画直线算法思路分享—代码开源—简单易懂超详细

    这个算法是纯原创,没有任何借鉴的元素 实现原理大概就是通过两个点算出直线方程然后描点 在这个函数中OLED_DrawDot函数是描点函数,如果和自己代码里不匹配可以换成自己代码里的描点函数. 先看整个 ...

  5. photoshop 快速画直线

  6. photoshop 快速画直线 1

  7. 布兰森汉姆画圆matlab,bresenham算法画直线

    实验一名称:基本图形的生成算法 要求:(1)掌握 DDA 生成线段算法 (2)掌握 Bresenham 生成线段算法 (3)掌握生成圆弧算法 1. 代码 (1) Bresenham 画线算法 v 实验 ...

  8. 光栅图形学-画直线经典算法

    光栅图形学算法-画直线算法 如果对这些算法感兴趣,可以去查阅算法的详细介绍,这里只是用伪代码来描述这些算法. 1.DDA算法 DDA算法依赖于直线的斜截式方程 n=x2 - x1; //像素点个数k ...

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

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

最新文章

  1. MFC CMap整理
  2. oracle中有类似split的方法么,Oracle 实现拆分列数据的split()方法
  3. RabbitMQ系列教程之一:我们从最简单的事情开始!Hello World
  4. 三大特性学习目标 java 1614782356
  5. 多线程与多进程(转载)
  6. 【Python】Pycharm中plot绘图不能显示
  7. 我查这么多数据,会不会把数据库内存打爆?
  8. mysql如何导出数据脚本_MySQL 导出数据
  9. 在 After Effects 中最受欢迎的10大AE插件推荐
  10. 关键字private、static总结
  11. Postgresql源码(41)plpgsql函数编译执行流程分析
  12. CSP-M2 B - HRZ 学英语
  13. 标号法求解单源最短路径
  14. Unlawfully wed 小小新娘 | 经济学人中英双语对照精读笔记
  15. 电销外呼系统主要有哪些作用?
  16. 高校房产管理系统平台架构分析
  17. 怎么用wps抽签_怎么用WPS做活动抽签用的PPT?有模板可以给我更好!
  18. 泛微OA 修改网站标题logo及标题文字
  19. 解决Vue中的生命周期beforeDestory不触发的问题(用了keep-alive)
  20. 上海西门子培训-第二天(周一)

热门文章

  1. 前端提高篇(五十四)练习7:animation动画练习
  2. html5学生大作业,帮同学做的大一大作业:《我的家乡—郑州》 - 梦涵的帅爸爸...
  3. MATLAB | 那些你不得不知道的MATLAB小技巧(四)
  4. 芒果不能用百度了,怎么办?
  5. 手机游戏无障碍设计——猜地鼠之Android篇
  6. 她是淘宝牛年第一锦鲤,却只选择清空购物车
  7. 因《C程序设计伴侣》的争执,谈谭浩强《C程序设计》的批评
  8. 2022美赛C题题目及思路--交易策略
  9. 1677. 发票中的产品金额
  10. [Study]Vue