如何在2D numpy数组中查找水平、垂直线的边界点
2D numpy数组水平/垂直线段检测与过滤方案
核心需求拆解
- 识别二值(示例中0为背景、255为前景)numpy数组中所有水平、垂直线段的边界端点
- 输出格式为线段列表,每个线段由两个端点坐标组成,坐标格式为
[行索引, 列索引],和给定示例格式对齐 - 过滤短边:仅保留两端点间距大于2的线段
实现逻辑
- 第一步:二值化归一,将所有非0值统一标记为前景,排除灰度值差异干扰
- 第二步:逐行扫描检测水平线段:遍历每一行,定位连续前景像素块的起始、结束列位置,记录水平线段两端点
- 第三步:逐列扫描检测垂直线段:遍历每一列,定位连续前景像素块的起始、结束行位置,记录垂直线段两端点
- 第四步:长度过滤:计算每条线段两端点的距离(水平/垂直线段距离直接等于行/列坐标差的绝对值),剔除距离≤2的短线段
可直接运行的实现代码
import numpy as np def detect_lines(gray_img, min_len=2): # 二值化:非0值标记为前景 bin_img = (gray_img != 0).astype(np.uint8) lines = [] h, w = bin_img.shape # 逐列扫描检测垂直线段 for col in range(w): col_data = bin_img[:, col] # 定位前后景跳变位置 diff = np.diff(np.concatenate(([0], col_data, [0]))) start_rows = np.where(diff == 1)[0] end_rows = np.where(diff == -1)[0] - 1 for s, e in zip(start_rows, end_rows): # 仅保留长度大于阈值的线段 if (e - s) > min_len: lines.append([[s, col], [e, col]]) # 逐行扫描检测水平线段 for row in range(h): row_data = bin_img[row, :] diff = np.diff(np.concatenate(([0], row_data, [0]))) start_cols = np.where(diff == 1)[0] end_cols = np.where(diff == -1)[0] - 1 for s, e in zip(start_cols, end_cols): if (e - s) > min_len: lines.append([[row, s], [row, e]]) return lines # 给定测试数组 gray_img = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 255, 255, 255, 255, 255, 255, 255, 0], [0, 255, 255, 255, 255, 255, 255, 255, 0], [0, 255, 255, 0, 0, 0, 0, 0, 0], [0, 255, 255, 0, 0, 0, 0, 0, 0], [0, 255, 255, 0, 0, 0, 0, 0, 0], [0, 255, 255, 0, 0, 255, 255, 255, 255], [0, 255, 255, 0, 0, 255, 255, 255, 255], [0, 255, 255, 0, 0, 0, 0, 0, 0], [0, 255, 255, 0, 0, 0, 0, 0, 0], [0, 255, 255, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]]) result = detect_lines(gray_img, min_len=2) print(result)
效果说明
- 针对给定测试数组,输出前两项与示例完全匹配:
[[1,1],[10,1]]、[[1,2],[10,2]] - 长度≤2的短线段(比如行3位置列1到列2长度为1的水平段)会被自动过滤
- 纯numpy实现无额外第三方依赖,基于数组差分跳变检测逻辑运行稳定,适配任意尺寸的2D灰度/二值数组
内容的提问来源于stack exchange,提问作者guiMarzo
相关产品推荐
相关产品推荐

