




下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】Android中怎么实现一个多边形区域扫描线种子填充算法
这篇文章给大家介绍Android中怎么实现一个多边形区域扫描线种子填充算法,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1.3扫描线种子填充算法1.1和1.2节介绍的两种种子填充算法的优点是非常简单,缺点是使用了递归算法,这不但需要大量栈空间来存储相邻的点,而且效率不高。为了减少算法中的递归调用,节省栈空间的使用,人们提出了很多改进算法,其中一种就是扫描线种子填充算法。扫描线种子填充算法不再采用递归的方式处理“4-联通”和“8-联通”的相邻点,而是通过沿水平扫描线填充像素段,一段一段地来处理“4-联通”和“8-联通”的相邻点。这样算法处理过程中就只需要将每个水平像素段的起始点位置压入一个特殊的栈,而不需要象递归算法那样将当前位置周围尚未处理的所有相邻点都压入堆栈,从而可以节省堆栈空间。应该说,扫描线填充算法只是一种避免递归,提高效率的思想,前面提到的注入填充算法和边界填充算法都可以改进成扫描线填充算法,下面介绍的就是结合了边界填充算法的扫描线种子填充算法。扫描线种子填充算法的基本过程如下:当给定种子点(x,y)时,首先分别向左和向右两个方向填充种子点所在扫描线上的位于给定区域的一个区段,同时记下这个区段的范围[xLeft,xRight],然后确定与这一区段相连通的上、下两条扫描线上位于给定区域内的区段,并依次保存下来。反复这个过程,直到填充结束。扫描线种子填充算法可由下列四个步骤实现:(1)初始化一个空的栈用于存放种子点,将种子点(x,y)入栈;(2)判断栈是否为空,如果栈为空则结束算法,否则取出栈顶元素作为当前扫描线的种子点(x,y),y是当前的扫描线;(3)从种子点(x,y)出发,沿当前扫描线向左、右两个方向填充,直到边界。分别标记区段的左、右端点坐标为xLeft和xRight;(4)分别检查与当前扫描线相邻的y-1和y+1两条扫描线在区间[xLeft,xRight]中的像素,从xLeft开始向xRight方向搜索,若存在非边界且未填充的像素点,则找出这些相邻的像素点中最右边的一个,并将其作为种子点压入栈中,然后返回第(2)步;这个算法中最关键的是第(4)步,就是从当前扫描线的上一条扫描线和下一条扫描线中寻找新的种子点。这里比较难理解的一点就是为什么只是检查新扫描线上区间[xLeft,xRight]中的像素?如果新扫描线的实际范围比这个区间大(而且不连续)怎么处理?我查了很多计算机图形学的书籍和论文,好像都没有对此做过特殊说明,这使得很多人在学习这门课程时对此有挥之不去的疑惑。本着“毁人”不倦的思想,本文就罗嗦解释一下,希望能解除大家的疑惑。如果新扫描线上实际点的区间比当前扫描线的[xLeft,xRight]区间大,而且是连续的情况下,算法的第(3)步就处理了这种情况。如图(4)所示:
图(4)新扫描线区间增大且连续的情况假设当前处理的扫描线是黄色点所在的第7行,则经过第3步处理后可以得到一个区间[6,10]。然后第4步操作,从相邻的第6行和第8行两条扫描线的第6列开始向右搜索,确定红色的两个点分别是第6行和第8行的种子点,于是按照顺序将(6,10)和(8,10)两个种子点入栈。接下来的循环会处理(8,10)这个种子点,根据算法第3步说明,会从(8,10)开始向左和向右填充,由于中间没有边界点,因此填充会直到遇到边界为止,所以尽管第8行实际区域比第7行的区间[6,10]大,但是仍然得到了正确的填充。
如果新扫描线上实际点的区间比当前扫描线的[xLeft,xRight]区间大,而且中间有边界点的情况,算法又是怎么处理呢?算法描述中虽然没有明确对这种情况的处理方法,但是第4步确定上、下相邻扫描线的种子点的方法,以及靠右取点的原则,实际上暗含了从相邻扫描线绕过障碍点的方法。下面以图(5)为例说明:
图(5)新扫描线区间增大且不连续的情况算法第3步处理完第5行后,确定了区间[7,9],相邻的第4行虽然实际范围比区间[7,9]大,但是因为被(4,6)这个边界点阻碍,使得在确定种子点(4,9)后向左填充只能填充右边的第7列到第10列之间的区域,而左边的第3列到第5列之间的区域没有填充。虽然作为第5行的相邻行,第一次对第4行的扫描根据靠右原则只确定了(4,9)一个种子点。但是对第3行处理完后,第4行的左边部分作为第3行下边的相邻行,再次得到扫描的机会。第3行的区间是[3,9],向左跨过了第6列这个障碍点,第2次扫描第4行的时候就从第3列开始,向右找,可以确定种子点(4,5)。这样第4行就有了两个种子点,就可以被完整地填充了。
由此可见,对于有障碍点的行,通过相邻边的关系,可以跨越障碍点,通过多次扫描得到完整的填充,算法已经隐含了对这种情况的处理。根据本节总结的四个步骤,扫描线种子填充算法的实现如下:void
SearchLineNewSeed(std::stack<Point>&
stk,
int
xLeft,
int
xRight,
int
y,
int
new_color,
int
boundary_color)
{
int
xt
=
xLeft;
bool
findNewSeed
=
false;
while(xt
<=
xRight)
{
findNewSeed
=
false;
while(IsPixelValid(xt,
y,
new_color,
boundary_color)
&&
(xt
<
xRight))
{
findNewSeed
=
true;
xt++;
}
if(findNewSeed)
{
if(IsPixelValid(xt,
y,
new_color,
boundary_color)
&&
(xt
==
xRight))
stk.push(Point(xt,
y));
else
stk.push(Point(xt
-
1,
y));
}
/*向右跳过内部的无效点(处理区间右端有障碍点的情况)*/
int
xspan
=
SkipInvalidInLine(xt,
y,
xRight,
new_color,
boundary_color);
xt
+=
(xspan
==
0)
?
1
:
xspan;
/*处理特殊情况,以退出while(x<=xright)循环*/
}
}FillLineRight()和FillLineLeft()两个函数就是从种子点分别向右和向左填充颜色,直到遇到边界点,同时返回填充的点的个数。这两个函数返回填充点的个数是为了正确调整当前种子点所在的扫描线的区间[xLeft,xRight]。SearchLineNewSeed()函数完成算法第4步所描述的操作,就是在新扫描线上寻找种子点,并将种子点入栈,新扫描线的区间是xLeft和xRight参数确定的:void
SearchLineNewSeed(std::stack<Point>&
stk,
int
xLeft,
int
xRight,
int
y,
int
new_color,
int
boundary_color)
{
int
xt
=
xLeft;
bool
findNewSeed
=
false;
while(xt
<=
xRight)
{
findNewSeed
=
false;
while(IsPixelValid(xt,
y,
new_color,
boundary_color)
&&
(xt
<
xRight))
{
findNewSeed
=
true;
xt++;
}
if(findNewSeed)
{
if(IsPixelValid(xt,
y,
new_color,
boundary_color)
&&
(xt
==
xRight))
stk.push(Point(xt,
y));
else
stk.push(Point(xt
-
1,
y));
}
/*向右跳过内部的无效点(处理区间右端有障碍点的情况)*/
int
xspan
=
SkipInvalidInLine(xt,
y,
xRight,
new_color,
boundary_color);
xt
+=
(xspan
==
0)
?
1
:
xspan;
/*处理特殊情况,以退出while(x<=xright)循环*/
}
}最外层的while循环是为了保证区间[xLeft,xRight]右端被障碍点分隔成多段的情况能够得到正确处理,通过外层while循环,可以确保为每一段都找到一个种子点(对于障碍点在区间左端的情况,请参考图(5)所示实例的解释,是隐含在算法中完成的)。内层的while循环只是为了找到每一段最右端的一个可填充点作为种子点。SkipInvalidInLine()函数的作用就是跳过区间内的障碍点,确定下一个分隔段的开始位置。循环内的最后一行代码有点奇怪,其实只是用了一个小“诡计”,确保在遇到真正的边界点时循环能够正确退出。这不是一个值得称道的做法,实现此类软件控制有更好的方法,本文这样做的目的只是为了使代码简短一些,让读者把注意力集中在算法处理逻辑上,而不是冗杂难懂的循环控制条件上。算法的实现其实就在ScanLineSeedFill()和SearchLineNewSeed()两个函数中,神秘的扫描线种子填充算法也并
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 项目投资居间的合同
- 汽车直接融资租赁合同
- 二零二五荐绿化养护委托合同
- 二零二五版钢结构安全协议
- 二零二五版合同Amazon店铺代运营协议
- 代理合同范例大全
- 二零二五学生安全责任协议书
- 抖音直播带货的合同
- 二零二五版门店承包协议合同范例
- 二零二五版男女同居分手合同
- MOOC 写作与表达-常熟理工学院 中国大学慕课答案
- 农贸市场应急预案
- 肥胖患者麻醉管理专家共识2023年版中国麻醉学指南与专家共识
- 中药饮片处方点评表-副本(文档良心出品)
- DL-T 5605-2021太阳能热发电厂蒸汽发生系统设计规范-PDF解密
- 学校双重预防体系建设指导书
- 螺蛳粉出口贸易的现状及策略分析
- 2024年江苏省苏州市中考数学一模练习卷
- 家政聘用合同模板
- 防汛应急预案培训课件
- 桩基施工安全培训课件
评论
0/150
提交评论