如何从512×512栅格街道图像中提取连通的多段线街道网络
推荐直接基于骨架图做拓扑分析,比霍夫变换的方案更稳定,完全可以满足你的三个需求,步骤如下:
步骤1:生成连通无断点的1px宽骨架
既然已经确认skeletonize的输出本身连通性完好,断点只是显示伪影,完全不需要后续的膨胀操作,直接用原始骨架结果即可,避免重新出现宽度不均的问题:
from skimage import morphology, io import numpy as np # 读取并二值化街道图像(确保背景为0,街道区域为1) streets_data = io.imread("street_grid.png", as_gray=True) > 0.5 # 生成1px宽的连通骨架 skeleton = morphology.skeletonize(streets_data)
步骤2:识别交叉口
通过统计骨架像素的8邻域连通像素数,即可直接区分普通路段点和不同类型的交叉口:
- 普通路段点:8邻域内只有2个相邻骨架像素
- T型交叉口:8邻域内有3个相邻骨架像素
- 十字交叉口:8邻域内有4个相邻骨架像素
def count_neighbors(img, x, y): count = 0 for dx in (-1, 0, 1): for dy in (-1, 0, 1): if dx == 0 and dy == 0: continue if 0 <= x+dx < img.shape[0] and 0 <= y+dy < img.shape[1]: count += 1 if img[x+dx, y+dy] else 0 return count intersections = [] for x in range(skeleton.shape[0]): for y in range(skeleton.shape[1]): if not skeleton[x, y]: continue neighbor_cnt = count_neighbors(skeleton, x, y) if neighbor_cnt >= 3: intersections.append((x, y))
步骤3:提取交叉口之间的多段线
使用广度优先搜索(BFS)遍历骨架即可提取所有路段多段线:
- 将所有交叉口设为遍历起点,标记为已访问
- 从每个交叉口出发沿着路段点遍历,直到遇到下一个交叉口或者路段尽头
- 遍历过程中记录的所有坐标,就是两个交叉口之间的多段线
from collections import deque visited = np.zeros_like(skeleton, dtype=bool) polylines = [] # 8方向遍历偏移 dirs = [(-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)] for (x0, y0) in intersections: visited[x0, y0] = True for dx, dy in dirs: x1, y1 = x0 + dx, y0 + dy if 0 <= x1 < skeleton.shape[0] and 0 <= y1 < skeleton.shape[1]: if skeleton[x1, y1] and not visited[x1, y1]: # 开始遍历单条路段 cur_line = [(x0, y0)] q = deque([(x1, y1)]) visited[x1, y1] = True while q: cx, cy = q.popleft() cur_line.append((cx, cy)) next_point = None for dx2, dy2 in dirs: nx, ny = cx + dx2, cy + dy2 if 0 <= nx < skeleton.shape[0] and 0 <= ny < skeleton.shape[1]: if skeleton[nx, ny] and not visited[nx, ny]: next_point = (nx, ny) break if next_point: visited[next_point[0], next_point[1]] = True q.append(next_point) else: polylines.append(cur_line) break
可选优化
如果需要简化多段线、去除冗余采样点,可以使用Ramer-Douglas-Peucker算法对提取到的多段线做抽稀处理。
内容的提问来源于stack exchange,提问作者danvk
相关产品推荐
相关产品推荐

