如何去除HED检测及cv2.ximgproc.thinning细化后二值轮廓的1px突出线条
二值细化轮廓1px突出毛刺去除方案
针对经过HED边缘检测+cv2.ximgproc.thinning细化得到的单像素宽轮廓,可通过以下两种OpenCV可实现的方案去除短突出毛刺:
方案1:形态学修剪(快速实现)
适合短毛刺长度固定的场景,通过迭代击中击不中变换检测并删除端点,实现修剪指定长度内的毛刺:
import cv2 import numpy as np def morph_prune(src, prune_length=3): # 输入要求:二值图,前景255,背景0 # 定义3x3击中击不中结构元,检测端点(8邻域仅1个前景像素) kernel = [ np.array([[-1, -1, -1], [-1, 1, -1], [-1, 0, -1]], dtype=np.int8), np.array([[-1, -1, -1], [-1, 1, 0], [-1, -1, -1]], dtype=np.int8), np.array([[-1, -1, -1], [0, 1, -1], [-1, -1, -1]], dtype=np.int8), np.array([[-1, 0, -1], [-1, 1, -1], [-1, -1, -1]], dtype=np.int8), np.array([[-1, -1, 0], [-1, 1, -1], [-1, -1, -1]], dtype=np.int8), np.array([[0, -1, -1], [-1, 1, -1], [-1, -1, -1]], dtype=np.int8), np.array([[-1, -1, -1], [-1, 1, -1], [0, -1, -1]], dtype=np.int8), np.array([[-1, -1, -1], [-1, 1, -1], [-1, -1, 0]], dtype=np.int8), ] img = src.copy() for _ in range(prune_length): end_points = np.zeros_like(img) for k in kernel: hitmiss = cv2.morphologyEx(img, cv2.MORPH_HITMISS, k) end_points = cv2.bitwise_or(end_points, hitmiss) # 删除当前检测到的所有端点 img = cv2.bitwise_and(img, cv2.bitwise_not(end_points)) return img # 调用示例 src = cv2.imread("your_thin_contour.png", 0) _, binary = cv2.threshold(src, 127, 255, cv2.THRESH_BINARY) pruned = morph_prune(binary, prune_length=3) # 修剪长度<=3px的毛刺
方案2:端点追踪修剪(精准可控)
适合需要避免误删主轮廓细节的场景,通过追踪端点路径长度判断是否为需要删除的毛刺:
def trace_prune(src, max_spur_length=3): img = src.copy() # 获取所有前景像素坐标 y, x = np.where(img == 255) # 8邻域偏移 offsets = [(-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)] for i in range(len(x)): cx, cy = x[i], y[i] if img[cy, cx] == 0: continue # 统计当前点8邻域前景数 neighbor_count = 0 neighbors = [] for dx, dy in offsets: nx, ny = cx + dx, cy + dy if 0<=nx<img.shape[1] and 0<=ny<img.shape[0] and img[ny, nx] == 255: neighbor_count +=1 neighbors.append((nx, ny)) # 是端点 if neighbor_count == 1: path = [(cx, cy)] current = (cx, cy) prev = None is_spur = True for _ in range(max_spur_length): nx, ny = neighbors[0] if neighbors[0] != prev else neighbors[1] prev = current current = (nx, ny) path.append(current) # 统计当前点邻域前景数 neighbor_count = 0 neighbors = [] for dx, dy in offsets: nnx, nny = current[0]+dx, current[1]+dy if 0<=nnx<img.shape[1] and 0<=nny<img.shape[0] and img[nny, nnx] == 255: neighbor_count +=1 neighbors.append((nnx, nny)) # 走到交叉点,停止 if neighbor_count >=3: break # 走到另一个端点,说明是独立短线,也删除 if neighbor_count ==1: break else: # 长度超过阈值,不删除 is_spur = False if is_spur: # 删除毛刺路径 for (px, py) in path: img[py, px] = 0 return img
使用参考
待处理原图示例:
- 若毛刺长度多为2-3px,设置
prune_length=3即可完全去除,且不会损伤主轮廓 - 若存在较长的有效突出细节,可降低阈值或使用方案2自定义保留规则
内容的提问来源于stack exchange,提问作者Angel Arias González
相关产品推荐
相关产品推荐

