区域填充之扫描线种子法的Python实现

前言

最近在帮学长做语义地图导航与规划,遇到了这样的问题。
这里写图片描述
将学长分割好的地图里的每一个白色区块标识出来,以便于后面语义地图的导航。
最开始我想到了种子法,但是由于使用了递归,当地图规模增加时程序就跑不起来了,(Python默认最大递归次数为1000次,即使用sys.setrecursionlimit()强行设置成很大的数最多也只能递归20000多次便会崩溃,而MATLAB的递归更是慢的抠脚)。
幸好前几天浙大的同学给我发了他们计算机图形学的课件,当时看到了扫描线种子法,当时粗略看了一遍一些细节还没想明白,于是自己重新实现了一遍,结果速度也提高了,程序也不崩了,一口气上五楼不费劲儿。

算法思路

基本思路如下:(摘自课件)

将种子象素点压入堆栈
while 堆栈非空 do
begin
从堆栈中弹出一个种子象素
沿着扫描线对种子象素的左右象素进行填充,直至遇到边界
象素为止
标志区间内最左和最右象素为x left 和x right
if在x left ≤x≤x right 中检查与当前扫描线相邻的上下两条扫描线全
为边界象素或全为已填充过的象素 then goto 2
在x left ≤x≤x right 中标记每一个既不包含边界象素又不包含已 填
充过的象素的区间
将每一区间的最左、最右象素作为种子象素压入堆栈
end
end of algorithm

下面放代码。

#coding:utf8
import cv2
import numpy as np

frame = cv2.cvtColor(cv2.imread('fr_seg_open22_result.pgm'), cv2.COLOR_BGR2GRAY)
ret,frame = cv2.threshold(frame, 127,255
<think>根据用户需求,用户希望获得Python实现扫描线填充算法的示例代码。扫描线填充算法常用于计算机图形学中的多边形填充,其核心思想是通过扫描线逐行处理多边形的边,并填充多边形内部区域。 结合引用内容,特别是引用[3]提到扫描线种子法Python实现解决了递归深度问题,引用[4]提到了活动边表(AET)和边表(NET)的概念,引用[5]则涉及了边数据结构中的增量计算。因此,我们将实现一个基于扫描线的多边形填充算法,使用NET(新边表)和AET(活动边表)数据结构。 算法步骤: 1. 建立新边表(NET):一个字典,键为扫描线y坐标,值为在该扫描线首次出现的边列表。每条边记录包括:边的最大y值(ymax)、当前x坐标(x)、斜率的倒数(dx)等。 2. 初始化活动边表(AET)为空。 3. 从最低扫描线到最高扫描线: a. 将当前扫描线y对应的NET中的边加入AET。 b. 对AET中的边按x坐标排序。 c. 成对取出AET中的边,填充两条边之间的像素。 d. 从AET中删除y=ymax的边(即该边不再与后续扫描线相交)。 e. 更新AET中剩余边的x坐标(x += dx)。 f. 扫描线y递增。 注意:这里我们假设多边形是凸的或自交的,且使用整数坐标。 下面提供一个简化的Python实现示例:</think>### Python 实现扫描线填充算法示例代码 扫描线填充算法是一种高效的多边形光栅化方法,通过逐行处理扫描线与多边形边的交点实现区域填充[^4]。以下是一个完整的 Python 实现: ```python class Edge: """多边形边数据结构""" def __init__(self, ymin, ymax, x, dx): self.ymin = ymin # 边的最小y坐标 self.ymax = ymax # 边的最大y坐标 self.x = x # 当前扫描线交点x坐标 self.dx = dx # 斜率倒数 (1/m) def __lt__(self, other): """按x坐标排序""" return self.x < other.x class Polygon: """多边形对象""" def __init__(self, points): self.points = points # 顶点坐标列表 [(x0,y0), (x1,y1)...] self.edges = [] # 边表 self._create_edges() def _create_edges(self): """从顶点构建边表""" n = len(self.points) for i in range(n): x1, y1 = self.points[i] x2, y2 = self.points[(i+1) % n] # 忽略水平线 if y1 == y2: continue # 确保 ymin 在下方 if y1 < y2: ymin, ymax = y1, y2 x = x1 else: ymin, ymax = y2, y1 x = x2 # 计算斜率倒数 dx = (x2 - x1) / (y2 - y1) if y2 != y1 else 0 self.edges.append(Edge(ymin, ymax, x, dx)) def scanline_fill(polygon, height, width): """ 扫描线填充算法 :param polygon: Polygon对象 :param height: 画布高度 :param width: 画布宽度 :return: 二维数组表示的填充图像 (0=未填充, 1=已填充) """ # 初始化画布 canvas = [[0] * width for _ in range(height)] # 创建新边表(NET) net = [[] for _ in range(height)] for edge in polygon.edges: if 0 <= edge.ymin < height: net[edge.ymin].append(edge) # 初始化活动边表(AET) aet = [] # 逐行扫描 for y in range(height): # 将NET中当前扫描线的边加入AET aet.extend(net[y]) # 移除结束边 (y >= ymax) aet = [edge for edge in aet if y < edge.ymax] # 按x坐标排序 aet.sort() # 成对填充线段 i = 0 while i < len(aet): # 获取交点对 x1 = int(aet[i].x) i += 1 x2 = int(aet[i].x) i += 1 # 水平填充 (限制在画布范围内) for x in range(max(0, x1), min(width, x2 + 1)): canvas[y][x] = 1 # 更新AET中边的x坐标 for edge in aet: edge.x += edge.dx return canvas # ===== 使用示例 ===== if __name__ == "__main__": # 定义多边形顶点 (顺时针或逆时针) vertices = [(50, 50), (200, 100), (150, 200), (100, 150)] # 创建多边形对象 poly = Polygon(vertices) # 执行填充 (画布尺寸: 250x250) filled_image = scanline_fill(poly, 250, 250) # 可视化结果 (使用matplotlib) import matplotlib.pyplot as plt plt.figure(figsize=(8, 8)) plt.imshow(filled_image, cmap='gray', origin='lower') plt.title("扫描线填充结果") plt.plot([v[0] for v in vertices] + [vertices[0][0]], [v[1] for v in vertices] + [vertices[0][1]], 'r-') plt.show() ``` ### 算法核心要点说明: 1. **数据结构设计**: - `Edge` 类存储边的关键参数:$y_{\text{min}}$, $y_{\text{max}}$, $x$(当前交点), $dx$(斜率倒数 $1/m$) - `Polygon` 类管理顶点和边表,自动处理顶点连接关系[^4] 2. **新边表(NET)**: ```python net = [[] for _ in range(height)] # 按扫描线索引的边表 ``` 存储每条扫描线起始的边,键为扫描线 y 坐标,值为边对象列表[^4] 3. **活动边表(AET)处理**: - 每行扫描时动态更新: ```python aet.extend(net[y]) # 添加新边 aet = [edge for edge in aet if y < edge.ymax] # 移除结束边 aet.sort() # 按x坐标排序 ``` - 交点成对填充(奇偶规则): ```python for x in range(x1, x2 + 1): # 填充交点间像素 canvas[y][x] = 1 ``` 4. **坐标更新**: ```python for edge in aet: edge.x += edge.dx # 根据斜率更新下条扫描线交点 ``` 利用 $dx$(斜率倒数)避免浮点数重复计算[^5] ### 算法优化方向: 1. **活性边表增量更新**:使用链表替代列表提高 AET 更新效率 2. **边连贯性优化**:利用相邻扫描线交点的连贯性减少计算量 3. **边界处理**:添加抗锯齿支持,优化边界像素填充效果 4. **并行化**:不同扫描线可并行处理加速填充 ### 应用场景: - 计算机图形学中的多边形填充 - GIS 系统中的区域渲染 - 游戏开发中的地形生成 - 图像处理中的区域分割[^1][^3]
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值