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

如何用OpenCV区分旋转字符/数字与普通线条?

区分旋转字符/数字与线条的过滤方案

先修正你当前代码的核心问题

你提供的代码存在逻辑错误:循环遍历连通组件时,所有坐标变量(x/y/w/h)会被最后一个组件的值覆盖,且统计逻辑放在循环外,导致仅处理了最后一个组件。必须将统计逻辑移入循环内部。


针对「无法裁剪、仅能旋转」的解决方案

以下是适配你场景的实用方法,核心是绕开裁剪限制,精准统计旋转区域内的像素特征:

方法1:基于旋转掩码的像素统计

既然无法直接裁剪旋转后的组件区域,可通过生成旋转矩形掩码来锁定目标区域,再统计黑白像素比:

  1. 对每个连通组件,用cv2.minAreaRect()获取带旋转角度的最小包围矩形
  2. 根据矩形生成掩码,仅保留掩码内的有效像素
  3. 在掩码范围内统计黑白像素比,实现精准筛选
import cv2
import numpy as np

# 假设rotated_without_box是已旋转后的二值图像(0为黑,255为白)
analysis_of_single_groups = cv2.connectedComponentsWithStats(rotated_without_box, 4, cv2.CV_32S)
(totalLabels_s_g, label_ids_s_g, values_s_g, centroid_s_g) = analysis_of_single_groups

for i in range(1, totalLabels_s_g):
    # 获取连通组件的外接矩形
    x = values_s_g[i, cv2.CC_STAT_LEFT]
    y = values_s_g[i, cv2.CC_STAT_TOP]
    w = values_s_g[i, cv2.CC_STAT_WIDTH]
    h = values_s_g[i, cv2.CC_STAT_HEIGHT]
    
    # 提取当前组件的轮廓,用于计算最小旋转矩形
    component_mask = (label_ids_s_g == i).astype(np.uint8) * 255
    contours, _ = cv2.findContours(component_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    rect = cv2.minAreaRect(contours[0])
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    
    # 生成旋转矩形的掩码(仅保留矩形内区域)
    mask = np.zeros_like(rotated_without_box)
    cv2.drawContours(mask, [box], 0, 255, -1)
    
    # 提取掩码内的有效像素
    masked_img = cv2.bitwise_and(rotated_without_box, mask)
    
    # 统计黑白像素(避免除以0的异常)
    black_pix = np.sum(masked_img == 0)
    white_pix = np.sum(masked_img == 255)
    bw_ratio = black_pix / white_pix if white_pix != 0 else 0
    
    # 过滤逻辑:线条类组件黑白比接近1,字符/数字黑白比更低
    if bw_ratio < 0.9:
        print(f"保留组件{i},黑白比:{round(bw_ratio, 2)}")
        # 后续可将该组件送入Tesseract OCR
    else:
        print(f"过滤组件{i},黑白比:{round(bw_ratio, 2)}")

方法2:结合形状特征提升准确率

仅靠黑白比易出现误判,可叠加以下形状特征进一步筛选:

  • 轮廓面积与旋转矩形面积的比值:实心线条的比值接近1,字符(如0、8)因内部有空白,比值更低
  • 宽高比:线条多为细长型(宽高比远大于1或远小于1),字符宽高比更接近1
  • 欧拉数:字符的欧拉数(轮廓数-孔洞数)通常不为0,实心线条欧拉数为1

示例:在上述代码中加入面积比判断

# 计算轮廓面积与旋转矩形面积的比值
contour_area = cv2.contourArea(contours[0])
rect_area = rect[1][0] * rect[1][1]
area_ratio = contour_area / rect_area

# 结合黑白比+面积比的过滤逻辑
if bw_ratio < 0.9 and area_ratio < 0.8:
    print(f"保留组件{i},黑白比:{round(bw_ratio,2)},面积比:{round(area_ratio,2)}")
else:
    print(f"过滤组件{i},黑白比:{round(bw_ratio,2)},面积比:{round(area_ratio,2)}")

方法3:批量场景下的轻量模型分类

如果处理的图片数量极大,可训练一个轻量级CNN(如MobileNet),输入旋转后的组件图像直接分类为「字符」或「线条」,准确率和效率都优于规则筛选。

内容的提问来源于stack exchange,提问作者Alessandro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:45:35