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

扫描图像手写标记图形分类问题求助:SVM模型优化需求

问题描述

我正在实现扫描图像中的标记图形分类,需区分以下类别:

  • 划叉方块
  • 完全涂黑方块
  • 空白方块
  • 划叉/涂黑圆圈
  • 空白圆圈

当前实现流程:

  1. 识别外部黑边框
  2. 对齐图像以补偿扫描偏移
  3. 提取ID条形码
  4. 将图像分割为小方块,每个方块包含一个圆圈或方块
  5. 对每个方块分类(划叉方块标绿、涂黑方块标蓝、划叉/涂黑圆圈标红,空白图形无需处理)

核心实现代码(evaluator.py中的detect_answers函数):

def detect_answers(bgr_image: np.array, bgr_img_for_debug: np.array,
                   x_cut_positions: List[int], y_cut_positions: Tuple[int],
                   is_60_question_sim, debug: str):
    question_multiplier: int = 15 if is_60_question_sim else 20

    letter: Tuple[str, ...] = ("L", "", "A", "B", "C", "D", "E")
    user_answer_dict: Dict[int, str] = {i: "" for i in range(1, 61 - 20 * int(not is_60_question_sim))}

    gr_image: np.array = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2GRAY)

    # load SVM model
    load_path = os.getcwd()
    clf = load(os.path.join(load_path, "reduced.joblib"))

    for y_index in range(len(y_cut_positions) - 1):
        for x_index in range(len(x_cut_positions) - 1):

            # if you are on a column with only numbers, skip it
            if not (x_index - 1) % 7:
                continue

            x_top_left = int(not x_index % 7) * 7 + x_cut_positions[x_index]
            x_bottom_right = int(not x_index % 7) * 2 + x_cut_positions[x_index + 1]

            y_top_left: int = y_cut_positions[y_index]
            y_bottom_right: int = y_cut_positions[y_index + 1]

            crop_for_prediction: np.array = gr_image[y_top_left:y_bottom_right, x_top_left:x_bottom_right]
            crop_for_prediction: np.array = cv2.resize(crop_for_prediction, (18, 18))

            # category = ("QB", "QS", "QA", "CB", "CA")
            #               0     1     2     3     4

            crop_for_prediction: np.array = np.append(crop_for_prediction,
                                                      [x_index % 7, int(np.mean(crop_for_prediction))])
            predicted_category_index: int = clf.predict([crop_for_prediction])[0]
    return user_answer_dict

当前存在的问题:

  • 依赖像素均值、黑像素计数等简单特征的SVM模型,无法可靠处理手写差异
  • 分类错误频发,例如第1题D选项(涂黑方块)未被正确标记,最后一列图形几乎全部识别错误
  • 需要满足高效性要求,每次需处理500-800份测试卷
优化建议

1. 特征工程优化

  • 增加形状与纹理特征:
    • 用cv2.findContours提取轮廓,计算轮廓面积、周长、近似多边形顶点数,区分方块(4个顶点)和圆圈(近似圆形的顶点数)的形状差异
    • 统计目标区域(方块/圆圈的固定范围)内的黑像素占比,比如涂黑方块中心区域黑像素占比接近100%,划叉方块则有明显的线条分布
    • 提取HOG(方向梯度直方图)特征,捕捉手写划叉的纹理方向,比单纯像素均值更鲁棒
  • 移除冗余特征:当前代码中加入的x_index%7列索引特征可能引入偏差(导致最后一列识别全错),建议先移除该特征,验证分类效果是否改善

2. 模型改进

  • 替换为轻量CNN模型:SVM对复杂手写特征拟合能力有限,改用3-4层卷积+池化的自定义小CNN,或MobileNetV2精简版,自动提取更有效的视觉特征
    • 训练时加入数据增强:对标注数据做±5度旋转、小范围平移、轻微缩放、灰度扰动,模拟扫描偏移和手写差异,提升模型泛化性
  • 模型量化:对训练好的CNN做INT8量化,在几乎不损失精度的前提下提升推理速度,满足批量处理需求

3. 预处理优化

  • 自适应二值化:用cv2.adaptiveThreshold替代单纯灰度转换,应对扫描时的光照不均问题,确保手写标记与背景的分割更准确
  • 分割区域校准:最后一列识别全错可能是x_cut_positions的分割逻辑有偏差,打印分割后的裁剪图,验证最后一列的区域是否正确包含目标图形,调整x_top_left和x_bottom_right的计算逻辑

4. 后处理逻辑

  • 规则校验:结合题目选项的分布逻辑(通常每题仅一个标记选项),对分类结果做校验,若同一题目出现多个高置信度标记,保留置信度最高的结果,或标记为异常待人工复核
  • 置信度过滤:使用clf.predict_proba获取分类置信度,只保留置信度高于阈值(如0.8)的结果,低置信度样本暂存后批量人工处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 16:01:17