如何用OpenCV区分旋转字符/数字与普通线条?
区分旋转字符/数字与线条的过滤方案
先修正你当前代码的核心问题
你提供的代码存在逻辑错误:循环遍历连通组件时,所有坐标变量(x/y/w/h)会被最后一个组件的值覆盖,且统计逻辑放在循环外,导致仅处理了最后一个组件。必须将统计逻辑移入循环内部。
针对「无法裁剪、仅能旋转」的解决方案
以下是适配你场景的实用方法,核心是绕开裁剪限制,精准统计旋转区域内的像素特征:
方法1:基于旋转掩码的像素统计
既然无法直接裁剪旋转后的组件区域,可通过生成旋转矩形掩码来锁定目标区域,再统计黑白像素比:
- 对每个连通组件,用
cv2.minAreaRect()获取带旋转角度的最小包围矩形 - 根据矩形生成掩码,仅保留掩码内的有效像素
- 在掩码范围内统计黑白像素比,实现精准筛选
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
相关产品推荐
相关产品推荐

