如何实现双部件字母的轮廓识别?附OpenCV代码咨询
解决双部件字母的OpenCV轮廓识别问题
嘿,我来帮你搞定这个双部件字母(比如i、j、g、q这类有分离部分的字母)的轮廓识别难题!
你当前的代码只提取了外部轮廓,并且仅通过面积筛选,这就导致像i的“点”和主体、g的外圈和内部小部分会被当成独立的轮廓,没法识别成同一个字母区域。下面给你几个实用的解决方案,你可以根据自己的图像情况选择:
方法1:形态学闭操作预处理(简单高效)
这个方法适合部件之间缝隙不大的字母,通过闭操作(先膨胀后腐蚀)填补字母部件之间的空隙,让它们变成一个连通的区域,这样findContours就能直接识别成一个轮廓了。
修改你的代码,在阈值处理后添加闭操作:
MIN_CONTOUR_AREA = 10 img = cv2.imread("alphabets.png") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blured = cv2.blur(gray, (5,5), 0) img_thresh = cv2.adaptiveThreshold(blured, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) # 新增:创建结构元素,用闭操作填补双部件缝隙 # 注意:kernel的尺寸要根据你图像中字母的大小调整,比如字母大就用(5,5),小就用(3,3) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) img_thresh_closed = cv2.morphologyEx(img_thresh, cv2.MORPH_CLOSE, kernel) # 基于处理后的图像重新查找轮廓 imgContours, Contours, Hierarchy = cv2.findContours(img_thresh_closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 后续的轮廓筛选逻辑不变,现在双部件字母会被识别成单个轮廓了 for contour in Contours: if cv2.contourArea(contour) > MIN_CONTOUR_AREA: x, y, w, h = cv2.boundingRect(contour) cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2) cv2.imshow("Detected Letters", img) cv2.waitKey(0) cv2.destroyAllWindows()
方法2:基于外接矩形的轮廓合并(灵活适配)
如果形态学操作没法解决(比如字母部件距离太远),可以通过判断轮廓外接矩形的位置关系,把属于同一个字母的独立轮廓合并成一个区域。
示例代码如下:
MIN_CONTOUR_AREA = 10 MIN_DISTANCE = 15 # 可调整:两个部件的最大允许距离 MAX_CENTER_OFFSET = 10 # 可调整:两个部件的中心水平偏移最大值 img = cv2.imread("alphabets.png") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blured = cv2.blur(gray, (5,5), 0) img_thresh = cv2.adaptiveThreshold(blured, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) imgContours, Contours, Hierarchy = cv2.findContours(img_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 第一步:收集所有符合面积要求的轮廓的外接矩形 valid_rects = [] for contour in Contours: area = cv2.contourArea(contour) if area > MIN_CONTOUR_AREA: x, y, w, h = cv2.boundingRect(contour) # 存储矩形的左上角、右下角坐标,以及中心坐标 valid_rects.append({ "rect": (x, y, x+w, y+h), "center": (x + w//2, y + h//2) }) # 第二步:合并属于同一个字母的矩形 merged_rects = [] while valid_rects: current = valid_rects.pop(0) curr_x1, curr_y1, curr_x2, curr_y2 = current["rect"] curr_center_x, curr_center_y = current["center"] # 寻找需要合并的矩形 to_merge = [] for idx, rect_data in enumerate(valid_rects): rect_x1, rect_y1, rect_x2, rect_y2 = rect_data["rect"] rect_center_x, rect_center_y = rect_data["center"] # 判断条件:水平中心偏移小,且垂直方向距离近(比如i的点在主体上方) horizontal_offset = abs(curr_center_x - rect_center_x) vertical_distance = min(curr_y1, rect_y1) - max(curr_y2, rect_y2) if horizontal_offset < MAX_CENTER_OFFSET and abs(vertical_distance) < MIN_DISTANCE: to_merge.append(idx) # 合并所有找到的矩形 for idx in reversed(to_merge): rect_data = valid_rects.pop(idx) rx1, ry1, rx2, ry2 = rect_data["rect"] curr_x1 = min(curr_x1, rx1) curr_y1 = min(curr_y1, ry1) curr_x2 = max(curr_x2, rx2) curr_y2 = max(curr_y2, ry2) # 转成x,y,w,h格式加入合并列表 merged_rects.append((curr_x1, curr_y1, curr_x2 - curr_x1, curr_y2 - curr_y1)) # 绘制合并后的字母区域 for rect in merged_rects: x, y, w, h = rect cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2) cv2.imshow("Merged Letter Regions", img) cv2.waitKey(0) cv2.destroyAllWindows()
注意事项
- 所有参数(比如kernel尺寸、
MIN_DISTANCE、MAX_CENTER_OFFSET)都需要根据你实际的图像调整,比如字母越大,参数值就要相应调大。 - 如果你的图像是黑底白字还是白底黑字,要确保阈值操作的
THRESH_BINARY_INV设置正确,保证字母区域是白色的(这样轮廓提取才准确)。
内容的提问来源于stack exchange,提问作者M.Mehranian
相关产品推荐
相关产品推荐

