OpenCV同色连通图形场景下的线段检测方法咨询
现有实现与问题

待检测图像-线段与图形异色
针对上图这类线段为蓝色、与连接图形颜色不同的场景,可通过HSV颜色掩码提取线段轮廓,核心代码如下:
img = cv2.imread("./more5.png")#"https://i.sstatic.net/LiLPv.png" blueLower = np.array([50,50,50]) blueUpper = np.array([130,255,255]) hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) blue_mask = cv2.inRange(hsv, blueLower, blueUpper) blue = cv2.bitwise_and(img ,img ,mask=blue_mask) contours, hierarchy = cv2.findContours(preprocess(blue), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

线段检测效果
完整可运行实现代码如下:
import numpy as np import cv2 def preprocess(img): img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_blur = cv2.GaussianBlur(img_gray, (5, 5), 1) img_canny = cv2.Canny(img_blur, 50, 50) # edge cascade kernel = np.ones((3, 3)) img_dilate = cv2.dilate(img_canny, kernel, iterations=1) img_erode = cv2.erode(img_dilate, kernel, iterations=1) return img_erode def find_tip(points, convex_hull): length = len(points) indices = np.setdiff1d(range(length), convex_hull) for i in range(2): j = indices[i] + 2 if j > length - 1: j = length - j if np.all(points[j] == points[indices[i - 1] - 2]): return tuple(points[j]) img = cv2.imread("./more5.png") blueLower = np.array([50,50,50]) blueUpper = np.array([130,255,255]) hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) blue_mask = cv2.inRange(hsv, blueLower, blueUpper) blue = cv2.bitwise_and(img ,img ,mask=blue_mask) contours, hierarchy = cv2.findContours(preprocess(blue), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) print(f"Contours size {len(contours)}") for cnt in contours: peri = cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, 0.004 * peri, True) hull = cv2.convexHull(approx, returnPoints=False) sides = len(hull) if 6 > sides > 3 and sides + 2 == len(approx): arrow_tip = find_tip(approx[:,0,:], hull.squeeze()) if arrow_tip: cv2.drawContours(img, [cnt], -1, (0, 255, 0), 3) cv2.circle(img, arrow_tip, 3, (0, 0, 255), cv2.FILLED) cv2.imshow("Image", img) cv2.waitKey(0)
上述方案依赖颜色差异分割线段,当线段与其连接的图形颜色完全一致时,颜色掩码无法分离线段和主体图形,方法直接失效,同色测试场景如下图:
待检测图像-线段与图形同色
同色场景线段检测可行思路
- 骨架提取筛选法:对整个同色连通域做细化(骨架提取)操作,将所有填充图形、线段压缩为单像素宽度的连通线条,再基于拓扑特征筛选线段:线段有且仅有一个端点和主体图形的骨架连接,另一端为自由端点,且线段本身无分叉、曲率极低,和封闭图形的骨架特征差异明显。OpenCV可通过
cv2.ximgproc.thinning接口实现快速骨架提取。 - 距离变换分割法:对二值化后的同色连通域做距离变换,计算每个前景像素到最近背景像素的距离。线段区域的距离值稳定等于线段宽度的1/2,而主体填充图形内部的距离值会远大于该数值,通过阈值即可把窄条状的线段区域从大连通域中分割出来,后续再复用原有轮廓检测逻辑即可。
- 霍夫直线校验法:对边缘检测结果做概率霍夫直线检测,筛选出符合长度阈值的候选线段,再对每个候选线段做邻域校验:如果线段其中一端的邻域是大面积同色填充区域、另一端邻域为背景,且线段两侧的像素一侧为前景、一侧为背景,即可判定为连接在图形上的目标线段。
- 角点切分法:用Shi-Tomasi角点检测接口识别同色连通域轮廓上的所有强角点,这类角点就是线段和主体图形的连接分界位置,沿角点把整个连通域轮廓切分为独立片段,再根据片段的长宽比筛选:线段对应的轮廓片段长宽比远大于主体图形的常规边,可直接通过阈值过滤。
内容的提问来源于stack exchange,提问作者Yong
相关产品推荐
相关产品推荐

