多边形的扫描转换与区域填充
2012-05-17 11:38
246 查看
在计算机图形学中,多边形有两种重要的表示方法:顶点表示和点阵表示。顶点表示是用多边形的顶点序列来表示多边形。这种表示直观、几何意义强、占内存少,易于进行几何变换,但由于它没有明确指出哪些象素在多边形内,故不能直接用于面着色;点阵表示是用位于多边形内的象素集合来刻画多边形。这种表示丢失了许多几何信息,但便于帧缓冲器表示图形,是面着色所需要的图形表示形式。光栅图形的一个基本问题是把多边形的顶点表示转换为点阵表示,这种转换称为多边形的扫描转换。
区域填充则是指先将在点阵表示的多边形区域内的一点(称为种子点)赋予指定的颜色和灰度,然后将这种颜色和灰度扩展到整个区域内的过程。
(1)多边形的扫描转换
多边形扫描转换算法对多边形的形状没有限制,但多边形的边界必须是封闭的,且不自交。我们可以将多边形分为三种:凸多边形、凹多边形、含内环的多边形。
凸多边形是指任意两顶点间的连线均在多边形内;
凹多边形是指任意两顶点间的连线有不在多边形内的部分;
含内环的多边形则是指多边形内再套有多边形,多边形内的多边形也叫内环,内环之间不能相交。
图2.3.1 多边形的种类
(a)扫描线算法
扫描线算法是按扫描线顺序,计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的象素,完成转换工作。区间的端点可以通过计算扫描线与多边形边界线的交点获得。对于一条扫描线,多边形的扫描转换过程可以分为四个步骤:
求交:计算扫描线与多边形各边的交点;
排序:把所有交点按x值递增顺序排序;
配对:第一个与第二个,第三个与第四个等等;每对交点代表扫描线与多边形的一个相交区间,
着色:把相交区间内的象素置成多边形颜色,把相交区间外的象素置成背景色。
图2.3.2 一个多边形与若干扫描线
为了提高效率,在处理一条扫描线时,仅对与它相交的多边形的边进行求交运算。我们把与当前扫描线相交的边称为活性边,并把它们按与扫描线交点x坐标递增的顺序存放在一个链表中,称此链表为活性边表(AET)。
活性边表的结点应为对应边保存如下内容:第1项存当前扫描线与边的交点坐标x值;第2项存从当前扫描线到下一条扫描线间x的增量Dx;第3项存该边所交的最高扫描线号ymax。
a. 扫描线6的活性边表
b. 扫描线7的活性边表
图2.3.3活性边表(AET)
假定当前扫描线与多边形某一条边的交点的横坐标为x,则下一条扫描线与该边的交点不必要重计算,只要加一个增量△x即可,下面,我们推导这个结论。
设该边的直线方程为:ax+by+c=0,当前扫描线及下一条扫描线与边的交点分别为(xi,yi)、(xi+1,yi+1),则:
axi+byi+c=0
axi+1+byi+1+c=0
其中△x=-b/a 为常数,
另外使用增量法计算时,我们需要知道一条边何时不再与下一条扫描线相交,以便及时把它从活性边表中删除出去。
为了方便活性边表的建立与更新,我们为每一条扫描线建立一个新边表(NET),存放在该扫描线第一次出现的边。也就是说,若某边的较低端点为ymin,则该边就放在扫描线ymin的新边表中。
图2.3.4 上图所示各条扫描线的新边表NET
算法过程:
void polyfill (polygon, color)
int color;多边形 polygon;
{
for (各条扫描线i )
{ 初始化新边表头指针NET [i];
把y min = i 的边放进边表NET [i];
}
y = 最低扫描线号;
初始化活性边表AET为空;
for (各条扫描线i )
{ 把新边表NET[i]中的边结点用插入排序法插入AET表,使之按x坐标递增顺序排列;
遍历AET表,把配对交点区间(左闭右开)上的象素(x, y),
用drawpixel (x, y, color) 改写象素颜色值;
遍历AET表,把ymax= i 的结点从AET表中删除,并把ymax > i结点的x值递增Dx;
若允许多边形的边自相交,则用冒泡排序法对AET表重新排序;
}
} /* polyfill */
扫描线与多边形顶点相交时,必须正确地取舍交点,如图2.3.5所示。
图2.3.5 扫描线与多边形相交,特殊情况的处理
? 扫描线与多边形相交的边分别位于扫描线的两侧,则计一个交点,如点P5,P6。
? 扫描线与多边形相交的边分别位于扫描线同侧,且
yi<yi-1,yi<yi+1,则计2个交点(填色),如P2。若
yi>yi-1,yi>yi+1,则计0个交点(不填色),如P1。
? 扫描线与多边形边界重合 (当要区分边界和边界内区域时需特殊处理),则计1个交点。
具体实现时,只需检查顶点的两条边的另外两个端点的y值。按这两个y值中大于交点y值的个数是0,1,2来决定。
(b)边界标志算法
边界标志算法的基本思想是:在帧缓冲器中对多边形的每条边进行直线扫描转换,亦即对多边形边界所经过的象素打上标志。然后再采用和扫描线算法类似的方法将位于多边形内的各个区段着上所需颜色。对每条与多边形相交的扫描线依从左到右的顺序,逐个访问该扫描线上的象素。使用一个布尔量inside来指示当前点是否在多边形内的状态。Inside的初值为假,每当当前访问的象素为被打上边标志的点,就把inside取反。对未打标志的象素,inside不变。若访问当前象素时,inside为真,说明该象素在多边形内,则把该象素置为填充颜色。
边界标志算法:
void edgemark_fill(polydef, color)
多边形定义 polydef; int color;
{ 对多边形polydef 每条边进行直线扫描转换;
inside = FALSE;
for (每条与多边形polydef相交的扫描线y )
for (扫描线上每个象素x )
{ if(象素 x 被打上边标志)inside = ! (inside);
if(inside!= FALSE) drawpixel (x, y, color);
else drawpixel (x, y, background);
}
}
用软件实现时,扫描线算法与边界标志算法的执行速度几乎相同,但由于边界标志算法不必建立维护边表以及对它进行排序,所以边界标志算法更适合硬件实现,这时它的执行速度比有序边表算法快一至两个数量级。
(2)区域填充算法
这里讨论的区域指已经表示成点阵形式的填充图形,它是象素的集合。区域可采用内点表示和边界表示两种表示形式。
内点表示:区域内的所有象素着同一颜色。
边界表示:区域的边界点着同一颜色。区域填充指先将区域的一点赋予指定的颜色,然后将该颜色扩展到整个区域的过程。
区域填充算法要求区域是连通的,因为只有在连通区域中,才可能将种子点的颜色扩展到区域内的其它点。区域可分为4向连通区域和8向连通区域。4向连通区域指的是从区域上一点出发,可通过四个方向,即上、下、左、右移动的组合,在不越出区域的前提下,到达区域内的任意象素;8向连通区域指的是从区域内每一象素出发,可通过八个方向,即上、下、左、右、左上、右上、左下、右下这八个方向的移动的组合来到达。
图2.3.7 四连通区域和八连通区域
图2.3.8 区域的内点表示和边界表示
(a)区域填充的递归算法
以上讨论的多边形填充算法是按扫描线顺序进行的。种子填充算法假设在多边形内有一象素已知,由此出发利用连通性找到区域内的所有象素。
设(x,y)为内点表示的4连通区域内的一点,oldcolor为区域的原色,要将整个区域填充为新的颜色newcolor。
内点表示的4连通区域的递归填充算法:
void FloodFill4(int x,int y,int oldcolor,int newcolor)
{
if(getpixel(x,y)==oldcolor)
{
drawpixel(x,y,newcolor);
FloodFill4(x,y+1,oldcolor,newcolor);
FloodFill4(x,y-1,oldcolor,newcolor);
FloodFill4(x-1,y,oldcolor,newcolor);
FloodFill4(x+1,y,oldcolor,newcolor);
}
}
边界表示的4连通区域的递归填充算法:
void BoundaryFill4(int x,int y,int boundarycolor,int newcolor)
{ int color;
if(color!=newcolor && color!=boundarycolor)
{ drawpixel(x,y,newcolor);
BoundaryFill4 (x,y+1, boundarycolor,newcolor);
BoundaryFill4 (x,y-1, boundarycolor,newcolor);
BoundaryFill4 (x-1,y, boundarycolor,newcolor);
BoundaryFill4 (x+1,y, boundarycolor,newcolor);
}
}
对于内点表示和边界表示的8连通区域的填充,只要将上述相应代码中递归填充相邻的4个象素增加到递归填充8个象素即可。
区域填充则是指先将在点阵表示的多边形区域内的一点(称为种子点)赋予指定的颜色和灰度,然后将这种颜色和灰度扩展到整个区域内的过程。
(1)多边形的扫描转换
多边形扫描转换算法对多边形的形状没有限制,但多边形的边界必须是封闭的,且不自交。我们可以将多边形分为三种:凸多边形、凹多边形、含内环的多边形。
凸多边形是指任意两顶点间的连线均在多边形内;
凹多边形是指任意两顶点间的连线有不在多边形内的部分;
含内环的多边形则是指多边形内再套有多边形,多边形内的多边形也叫内环,内环之间不能相交。
图2.3.1 多边形的种类
(a)扫描线算法
扫描线算法是按扫描线顺序,计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的象素,完成转换工作。区间的端点可以通过计算扫描线与多边形边界线的交点获得。对于一条扫描线,多边形的扫描转换过程可以分为四个步骤:
求交:计算扫描线与多边形各边的交点;
排序:把所有交点按x值递增顺序排序;
配对:第一个与第二个,第三个与第四个等等;每对交点代表扫描线与多边形的一个相交区间,
着色:把相交区间内的象素置成多边形颜色,把相交区间外的象素置成背景色。
图2.3.2 一个多边形与若干扫描线
为了提高效率,在处理一条扫描线时,仅对与它相交的多边形的边进行求交运算。我们把与当前扫描线相交的边称为活性边,并把它们按与扫描线交点x坐标递增的顺序存放在一个链表中,称此链表为活性边表(AET)。
活性边表的结点应为对应边保存如下内容:第1项存当前扫描线与边的交点坐标x值;第2项存从当前扫描线到下一条扫描线间x的增量Dx;第3项存该边所交的最高扫描线号ymax。
a. 扫描线6的活性边表
b. 扫描线7的活性边表
图2.3.3活性边表(AET)
假定当前扫描线与多边形某一条边的交点的横坐标为x,则下一条扫描线与该边的交点不必要重计算,只要加一个增量△x即可,下面,我们推导这个结论。
设该边的直线方程为:ax+by+c=0,当前扫描线及下一条扫描线与边的交点分别为(xi,yi)、(xi+1,yi+1),则:
axi+byi+c=0
axi+1+byi+1+c=0
其中△x=-b/a 为常数,
另外使用增量法计算时,我们需要知道一条边何时不再与下一条扫描线相交,以便及时把它从活性边表中删除出去。
为了方便活性边表的建立与更新,我们为每一条扫描线建立一个新边表(NET),存放在该扫描线第一次出现的边。也就是说,若某边的较低端点为ymin,则该边就放在扫描线ymin的新边表中。
图2.3.4 上图所示各条扫描线的新边表NET
算法过程:
void polyfill (polygon, color)
int color;多边形 polygon;
{
for (各条扫描线i )
{ 初始化新边表头指针NET [i];
把y min = i 的边放进边表NET [i];
}
y = 最低扫描线号;
初始化活性边表AET为空;
for (各条扫描线i )
{ 把新边表NET[i]中的边结点用插入排序法插入AET表,使之按x坐标递增顺序排列;
遍历AET表,把配对交点区间(左闭右开)上的象素(x, y),
用drawpixel (x, y, color) 改写象素颜色值;
遍历AET表,把ymax= i 的结点从AET表中删除,并把ymax > i结点的x值递增Dx;
若允许多边形的边自相交,则用冒泡排序法对AET表重新排序;
}
} /* polyfill */
扫描线与多边形顶点相交时,必须正确地取舍交点,如图2.3.5所示。
图2.3.5 扫描线与多边形相交,特殊情况的处理
? 扫描线与多边形相交的边分别位于扫描线的两侧,则计一个交点,如点P5,P6。
? 扫描线与多边形相交的边分别位于扫描线同侧,且
yi<yi-1,yi<yi+1,则计2个交点(填色),如P2。若
yi>yi-1,yi>yi+1,则计0个交点(不填色),如P1。
? 扫描线与多边形边界重合 (当要区分边界和边界内区域时需特殊处理),则计1个交点。
具体实现时,只需检查顶点的两条边的另外两个端点的y值。按这两个y值中大于交点y值的个数是0,1,2来决定。
(b)边界标志算法
边界标志算法的基本思想是:在帧缓冲器中对多边形的每条边进行直线扫描转换,亦即对多边形边界所经过的象素打上标志。然后再采用和扫描线算法类似的方法将位于多边形内的各个区段着上所需颜色。对每条与多边形相交的扫描线依从左到右的顺序,逐个访问该扫描线上的象素。使用一个布尔量inside来指示当前点是否在多边形内的状态。Inside的初值为假,每当当前访问的象素为被打上边标志的点,就把inside取反。对未打标志的象素,inside不变。若访问当前象素时,inside为真,说明该象素在多边形内,则把该象素置为填充颜色。
边界标志算法:
void edgemark_fill(polydef, color)
多边形定义 polydef; int color;
{ 对多边形polydef 每条边进行直线扫描转换;
inside = FALSE;
for (每条与多边形polydef相交的扫描线y )
for (扫描线上每个象素x )
{ if(象素 x 被打上边标志)inside = ! (inside);
if(inside!= FALSE) drawpixel (x, y, color);
else drawpixel (x, y, background);
}
}
用软件实现时,扫描线算法与边界标志算法的执行速度几乎相同,但由于边界标志算法不必建立维护边表以及对它进行排序,所以边界标志算法更适合硬件实现,这时它的执行速度比有序边表算法快一至两个数量级。
(2)区域填充算法
这里讨论的区域指已经表示成点阵形式的填充图形,它是象素的集合。区域可采用内点表示和边界表示两种表示形式。
内点表示:区域内的所有象素着同一颜色。
边界表示:区域的边界点着同一颜色。区域填充指先将区域的一点赋予指定的颜色,然后将该颜色扩展到整个区域的过程。
区域填充算法要求区域是连通的,因为只有在连通区域中,才可能将种子点的颜色扩展到区域内的其它点。区域可分为4向连通区域和8向连通区域。4向连通区域指的是从区域上一点出发,可通过四个方向,即上、下、左、右移动的组合,在不越出区域的前提下,到达区域内的任意象素;8向连通区域指的是从区域内每一象素出发,可通过八个方向,即上、下、左、右、左上、右上、左下、右下这八个方向的移动的组合来到达。
图2.3.7 四连通区域和八连通区域
图2.3.8 区域的内点表示和边界表示
(a)区域填充的递归算法
以上讨论的多边形填充算法是按扫描线顺序进行的。种子填充算法假设在多边形内有一象素已知,由此出发利用连通性找到区域内的所有象素。
设(x,y)为内点表示的4连通区域内的一点,oldcolor为区域的原色,要将整个区域填充为新的颜色newcolor。
内点表示的4连通区域的递归填充算法:
void FloodFill4(int x,int y,int oldcolor,int newcolor)
{
if(getpixel(x,y)==oldcolor)
{
drawpixel(x,y,newcolor);
FloodFill4(x,y+1,oldcolor,newcolor);
FloodFill4(x,y-1,oldcolor,newcolor);
FloodFill4(x-1,y,oldcolor,newcolor);
FloodFill4(x+1,y,oldcolor,newcolor);
}
}
边界表示的4连通区域的递归填充算法:
void BoundaryFill4(int x,int y,int boundarycolor,int newcolor)
{ int color;
if(color!=newcolor && color!=boundarycolor)
{ drawpixel(x,y,newcolor);
BoundaryFill4 (x,y+1, boundarycolor,newcolor);
BoundaryFill4 (x,y-1, boundarycolor,newcolor);
BoundaryFill4 (x-1,y, boundarycolor,newcolor);
BoundaryFill4 (x+1,y, boundarycolor,newcolor);
}
}
对于内点表示和边界表示的8连通区域的填充,只要将上述相应代码中递归填充相邻的4个象素增加到递归填充8个象素即可。
相关文章推荐
- 多边形扫描转换与区域填充
- 多边形的扫描转换与区域填充算法
- 多边形的扫描转换与区域填充
- 多边形区域填充算法--改进的扫描线填充算法
- 算法系列之十二:多边形区域填充算法--改进的扫描线填充算法
- 基于扫描种子线算法的多边形区域填充实现
- 图形生成算法:多边形的扫描转换与区域填充算法
- 计算机图形学--多边形扫瞄转换与区域填充实现
- 算法系列之十二:多边形区域填充算法--改进的扫描线填充算法
- 算法系列之十二:多边形区域填充算法--改进的扫描线填充算法 .
- 算法系列之十二:多边形区域填充算法--改进的扫描线填充算法
- 算法系列之十二:多边形区域填充算法--扫描线种子填充算法
- 多边形区域填充算法一--递归种子填充
- 多边形区域填充算法--递归种子填充算法
- [计算机图形学经典算法] 多边形的扫描转换
- 多边形区域填充算法--扫描线种子填充算法
- 算法系列之十二:多边形区域填充算法--递归种子填充算法
- 区域填充_扫描线种子填充_广度优先算法种子填充
- 区域填充之扫描线算法
- AET在多边形扫描转换中的使用 Scan conversion polygon and fill red color inside