光栅图形学(一):直线段的扫描转换算法

前言



  在数学上,理想的直线是没有宽度的,它是由无数个点构成的集合。对直线进行光栅化时,只能在显示器说给定的有限个像素组成的矩阵中,确定最佳逼近于该直线的一组像素,并且按扫描线顺序。

  本节介绍绘制线宽为一个像素的直线的三个常用算法:数值微分中点画线Bresenham算法

数值微分法



  已知过端点 P0(x0, y0),P1(x1, y1) 的直线段 L(P0, P1);直线斜率为 k = (y1 - y0) / (x1 - x0)。

  于是 yi+1 = kxi+1 + b。

  于是,x每增加1,y就增加k。画点的时候还需要判断 int(y+0.5) 向下取整。

 1 // 数值微分法,伪代码
 2 void DDAline(int x0, int y0, int x1, int y1) {
 3     int dx, dy, x=x0, y=y0;
 4     double k;
 5     dx = x0 - x1; dy = y0 - y1;
 6     k = dy / dx;
 7     draw(x, y)
 8     while (x <= x1) {
 9         x += 1;
10         y += k;
11         draw(x, int(y+0.5));
12     }
13 }

  效果图如下(0,1)(5, 4):

  

中点画线法



  假设线段 F(M) = ax + by + c = 0。(a=y0-y1; b=x1-x0; c=x0y1-x1y0)。

  中点画线法的思想就是对于点(xp,yp)的下一个点 M(xp+1,y+0.5),拿这个中点和实际点比较,如果实际点在中点上方(F(M) < 0),则取(xp+1,yp+1)为下一个点。如果实际点在中点下方(即中点代入直线方程的值大于0,F(M) >= 0),则取(xp+1, yp)。

  为了加速计算,我们通常采用增量的方法。

  假设从(xp,yp)开始画线,d的初值d0 = F(x0+1, y0+0.5)= F(x0,y0)+a+0.5。(d = a+0.5b)

  1. 若 d>=0 , 即中点代入原直线方程中的值大于0,即中点在目标直线上方,我们应该取下面的点(xp+1, yp)。判断下一个像素的位置时,应计算 d = F(xp+2,yp+0.5) = d + a,增量为 a。
  2. 若 d < 0,即中点在目标直线的下方,即取中点上面的点(xp+1,yp+1)。判断下一个像素的位置时,应计算 d = F(xp+2, yp+1.5) = d + a + b,增量为 a+b。

  因为我们只需要知道d的正负,所以可以调整 d‘ = 2a + b。

 1 void Midpoint(int x0, int y0, int x1, int y1) {
 2     int a, b, d1, d2, d, x, y;
 3     a = y0 - y1;
 4     b = x1 - x0;
 5     d = 2*a + b;
 6     d1 = 2*a, d2 = 2 * (a+b);
 7     x = x0, y = y0;
 8     draw(x, y);
 9     while (x < x1) {
10         if (d < 0)
11             {x++, y++, d+=d2;}
12         else
13             {x++; d+=d1;}
14         draw(x, y);
15     }
16 }

   效果如下图(0,1)(5, 4):

  

Bresenham算法



  Bresenham算法也是采用增量的方法,y每次累加k,超过0.5的中点位置就取上面的点,然后增量减一。如果我们增量的起始值设置为 d-0.5。就可以直接和0比较。

  每次和0.5比较都比较麻烦,所以假设一个格子的宽度为2dx,高为2dx,那么一个 k 就是2dy。

  所以如果我们设置起始增量为 -dx(-0.5*2dx)。每次移动单位为1的长度,增量就增加2dy,然后拿着这个增量和 0 比较,如果大于0,取上面的点,然后增量要减少 2dx。

 1 void IntegerBresenham(int x0, int y0, int x1, int y1) {
 2     int x, y, dx, dy;
 3     dx = x0-x1, dy = y0 - y1, e = -dx;
 4     x = x0, y = y0;
 5     for(i=0; i<=dx; ++i) {
 6         draw(x, y);
 7         x++, e=e+2*dy;
 8         if (e >= 0) {y++; e = e-2*dx;}
 9     }
10 }

  下面是效果图:
  

  

完整代码


 1 import matplotlib.pyplot as plt
 2 from matplotlib.ticker import MultipleLocator
 3
 4 # 数值微分法
 5 def DDA(x0, y0, x1, y1):
 6     dy = y0 - y1
 7     dx = x0 - x1
 8     k = dy / dx
 9     x = x0
10     y = y0
11
12     a = []
13     b = []
14     while (x <= x1):
15         a.append(x)
16         x += 1
17         b.append(int(y+0.5))
18         y = y+k
19     plt.scatter(a, b, color=‘r‘)
20
21 # 中点画线法
22 def midpoint(x0, y0, x1, y1):
23     a = y0 - y1
24     b = x1 - x0
25     d = 2 * a + b
26     d1 = 2 * a
27     d2 = 2 * (a + b)
28     print(a, b, d1, d2, d)
29     x = x0
30     y = y0
31
32     a = [x0]
33     b = [y0]
34     while x < x1:
35         if d < 0:
36             x += 1
37             y += 1
38             d += d2
39         else:
40             x += 1
41             d += d1
42         a.append(x)
43         b.append(y)
44     plt.scatter(a, b, color=‘r‘)
45
46 def Bresenham(x0, y0, x1, y1):
47     dx = x1 - x0
48     dy = y1 - y0
49     e = -dx
50     x = x0
51     y = y0
52
53     a = []
54     b = []
55     while (x <= x1):
56         a.append(x)
57         b.append(y)
58         x += 1
59         e = e + 2 * dy
60         if e >= 0:
61             y += 1
62             e = e - 2 * dx
63     plt.scatter(a, b, color=‘r‘)
64
65 x_target = [0, 5]
66 y_target = [1, 4]
67
68 ax = plt.subplot(111);
69 plt.plot(x_target, y_target)
70 ax.xaxis.grid(True, which=‘major‘)
71 ax.yaxis.grid(True, which=‘major‘)
72 ax.xaxis.set_major_locator(MultipleLocator(1))
73 ax.yaxis.set_major_locator(MultipleLocator(1))
74
75 # DDA(0, 1, 5, 4)
76 # midpoint(0, 1, 5, 4)
77 Bresenham(0, 1, 5, 4)
78 plt.show()
时间: 2024-10-12 12:36:29

光栅图形学(一):直线段的扫描转换算法的相关文章

计算机图形学 Cohen-Sutherland直线段裁剪算法

作者 : 卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/40822977 本文通过一个完整的实例演示Cohen-Sutherland直线段裁剪算法. 1)创建类CP2 头文件:P2.h // P2.h: interface for the CP2 class. // ////////////////////////////////////////////////////////////////////// #if !defined

计算机图形学 彩色直线段的反走样(5)

作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/40083207 本文通过一个完整的例子来演示彩色直线段的反走样. 1)创建CP2类 头文件:P2.h // P2.h: interface for the CP2 class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_P2_H__DD23

计算机图形学(三种画线算法)

第二章:光栅图形学算法 1.光栅显示器:光栅扫描式图形显示器简称光栅显示器,是画点设备,可看作是一个点阵单元发生器,并可控制每个点阵单元的亮度 2.由来:随着光栅显示器的出现,为了在计算机上处理.显示图形,需要发展一套与之相适应的算法. 3.研究内容: 1>直线段的扫描转换算法 2>多边形的扫描转换与区域填充算法 3>裁剪算法 4>反走样算法 5>消隐算法 一.直线段的扫描转换算法 1.为了显示一条直线,就在光栅显示器上用离散的像素点逼近直线,所以我们就要知道这些像素点的坐标

中点Bresenham算法光栅化画直线(个人总结精简版)代码超短!速度极快!

中点Bresenham算法光栅化画直线,每次只位移一个像素,精度高!此源码借助直线 y=x 做了一些转换,简化了主位移的处理,每次移动只需要 加减操作, 不需要乘除!速度极快!! 原理在最后,下面先贴上核心代码~ void Bresenham_LineTo(CDC *pDC, int x1, int y1, int x2, int y2) //中点Bresenham算法光栅化画直线 { float k = 1.0*(y2 - y1) / (x2 - x1); //斜率 int flag = 0;

计算机图形学 直线反走样Wu算法(4)

作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/40048285 本文通过一个完整的实例来演示,直线反走样Wu算法. 1)创建CP2类 头文件:P2.h // P2.h: interface for the CP2 class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_P2_H__DD2

opencv利用hough概率变换拟合得到直线后,利用DDA算法得到直线上的像素点坐标

图片霍夫变换拟合得到直线后,怎样获得直线上的像素点坐标? 这是我今天在图像处理学习中遇到的问题,霍夫变换采用的概率霍夫变换,所以拟合得到的直线信息其实是直线的两个端点的坐标,这样一个比较直接的思路就是利用DDA算法来获取. 一.算法简介 DDA算法是计算机图形学中最简单的绘制直线算法.其主要思想是由直线公式y = kx + b推导出来的. 我们已知直线段两个端点P0(x0,y0)和P1(x1,y1),就能求出 k 和 b . 在k,b均求出的条件下,只要知道一个x值,我们就能计算出一个y值.如果

扫描转换算法——DDA、中点画线画圆、椭圆

我的理解:在光栅图形学中,由于每一个点的表示都只能是整数值,所以光栅图形学实际只是对对实际图形的近似表示. 数值微分法(DDA):以下PPT截图来自北京化工大学李辉老师 代码实现: import matplotlib.pyplot as plt import matplotlib.patches as patches from pylab import * def init(ax): #将主标签设置为1的倍数 majorLocator = MultipleLocator(1); #设置主刻度标签

计算机图形学——光栅图形学直线算法简介

本文是对 赵明老师 <计算机图形学>MOOC课程 部分章节的小总结. 直线是组成图形的基础,其算法往往被多次调用,其好坏直接影响图形的显示效果和速度.以下是一些画直线的常用算法. 1.DDA算法: 此算法基于增量思想. 对于直线的斜截式:y=kx+b,考虑每次 x 递增 1, 都有 y[i+1] = y[i] + k,这样就将 kx 部分的乘法转换成递推的加法. 由于像素点都是整数坐标,所以每次求得的 y 都要取整操作,采用加 0.5 取整数部分的方法:(int)(y[i]+0.5). 但是,

计算机图形学之光栅图形学——多边形的扫描转换之 X-扫描算法及改进

本文是对 赵明老师 <计算机图形学>MOOC课程 部分章节的小总结. 多边形有两种表示方法:顶点表示和点阵表示. X-扫描线算法: 算法步骤概括如下: 注意: 改进: 为了避免求交运算,引进一套特殊的数据结构: