如何在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
相关产品推荐
相关产品推荐

