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

如何实现双部件字母的轮廓识别?附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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:14:37