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

如何在Python中准确提取图片线段的端点坐标与直/曲线类型信息

问题描述

我需要在Python中提取图片内每条线段的详细信息,包括两个端点坐标,以及线段是直线还是曲线。例如输入指定图片后,期望得到类似这样的结构化输出:

{
    1: {"start": (92, 162), "end": (92, 5), "type": "straight"},
    2: {"start": (x1, y1), "end": (x2, y2), "type": "curve"},
    ...
}

我尝试过用cv2.HoughLinesP方法,但识别结果不准确,而且无法识别曲线。以下是我的测试代码:

import cv2
import numpy as np

img = cv2.imread(path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 100)
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100)
counts = 0
for line in lines:
    counts += 1
    for x1, y1, x2, y2 in line:
        print(counts, (x1, y1, x2, y2))
        cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.imencode('lines.jpg', img)[1].tofile('lines.jpg')
解决方案

核心思路

  • 提取图片中的轮廓,作为识别线段(含曲线)的基础
  • 对每个轮廓做多边形逼近,通过逼近后的顶点数量和拟合误差判断线段类型
  • 提取线段首尾端点,整理为目标结构化格式

实现代码

import cv2
import numpy as np

def extract_segments(img_path):
    # 读取并预处理图片
    img = cv2.imread(img_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 二值化+边缘检测,可根据图片明暗调整阈值
    _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
    edges = cv2.Canny(binary, 50, 150)
    
    # 提取外部轮廓
    contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    segments = {}
    segment_id = 1
    
    for cnt in contours:
        # 过滤过短的无效线段
        perimeter = cv2.arcLength(cnt, closed=False)
        if perimeter < 10:
            continue
        
        # 多边形逼近,epsilon控制拟合精度(取周长的1%)
        epsilon = 0.01 * perimeter
        approx = cv2.approxPolyDP(cnt, epsilon, closed=False)
        
        # 判断线段类型
        if len(approx) == 2:
            seg_type = "straight"
            start = tuple(approx[0][0])
            end = tuple(approx[1][0])
        else:
            seg_type = "curve"
            # 曲线取轮廓首尾点作为端点
            start = tuple(cnt[0][0])
            end = tuple(cnt[-1][0])
        
        segments[segment_id] = {
            "start": start,
            "end": end,
            "type": seg_type
        }
        segment_id += 1
    
    return segments

# 测试调用
if __name__ == "__main__":
    result = extract_segments("your_image_path.jpg")
    for seg_id, info in result.items():
        print(f"线段{seg_id}: {info}")

关键说明

  • 轮廓提取:用cv2.RETR_EXTERNAL只取最外层轮廓,CHAIN_APPROX_SIMPLE压缩轮廓点减少计算量
  • 拟合精度调整:epsilon值越小,逼近结果越贴近原轮廓,可根据线条复杂度调整
  • 阈值适配:二值化和Canny的阈值需根据图片实际明暗、线条粗细调整,确保边缘检测准确

内容的提问来源于stack exchange,提问作者Louis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 12:57:27