You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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)遍历骨架即可提取所有路段多段线:

  1. 将所有交叉口设为遍历起点,标记为已访问
  2. 从每个交叉口出发沿着路段点遍历,直到遇到下一个交叉口或者路段尽头
  3. 遍历过程中记录的所有坐标,就是两个交叉口之间的多段线
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 17:06:04