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

如何调整Python代码识别直线并裁剪图像去除直线外冗余字符?

OCR数据清洗:去除边缘直线并裁剪冗余内容

问题描述

我正在构建OCR(光学字符识别)系统,目前处于数据清洗阶段。数据集包含数万张图像,部分图像边缘存在直线(如顶部水平线、右侧垂直线),直线外侧有冗余字符。现有Python代码可去除水平和垂直直线,但去除后仍残留直线外的冗余字符,希望调整代码,在去除直线的同时裁剪图像,移除这些冗余内容。

现有代码:

def remove_lines(img_path, folder_path, img_name_with_extension):
    image = cv2.imread(img_path)

    # remove horizontal lines in the original image
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

    # Remove horizontal
    horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25,1))
    detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
    cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    for c in cnts:
        cv2.drawContours(image, [c], -1, (255,255,255), 2)

    # Repair image
    repair_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,6))
    result = 255 - cv2.morphologyEx(255 - image, cv2.MORPH_CLOSE, repair_kernel, iterations=1)

    image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)

    # remove horizontal lines in the rotated image
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

    # Remove horizontal
    horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25,1))
    detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
    cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    for c in cnts:
        cv2.drawContours(image, [c], -1, (255,255,255), 2)

    # Repair image
    repair_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,6))
    result = 255 - cv2.morphologyEx(255 - image, cv2.MORPH_CLOSE, repair_kernel, iterations=1)

    image = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE)

    os.chdir(folder_path)
    cv2.imwrite(img_name_with_extension, image)

修改后的解决方案

核心思路是先检测所有边缘直线的位置,确定有效内容的边界(直线内侧区域),裁剪图像保留有效区域后,再清理残留的直线痕迹。以下是修改后的代码:

import cv2
import os

def remove_lines_and_crop(img_path, folder_path, img_name_with_extension):
    image = cv2.imread(img_path)
    original = image.copy()
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

    # 检测水平直线
    horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 1))
    horizontal_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
    # 检测垂直直线(旋转图像复用水平检测逻辑)
    rotated_thresh = cv2.rotate(thresh, cv2.ROTATE_90_CLOCKWISE)
    vertical_lines = cv2.morphologyEx(rotated_thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
    vertical_lines = cv2.rotate(vertical_lines, cv2.ROTATE_90_COUNTERCLOCKWISE)

    # 合并水平与垂直直线的掩码
    combined_lines_mask = cv2.bitwise_or(horizontal_lines, vertical_lines)

    # 分析直线轮廓,确定裁剪边界
    cnts = cv2.findContours(combined_lines_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]

    # 初始化裁剪边界为图像原始尺寸
    h, w = image.shape[:2]
    top_bound = 0
    bottom_bound = h
    left_bound = 0
    right_bound = w

    for contour in cnts:
        x, y, cnt_w, cnt_h = cv2.boundingRect(contour)
        # 判断直线类型:水平/垂直
        if cnt_w > cnt_h:
            # 水平直线:区分顶部/底部直线,更新对应边界
            if y < h // 2:
                top_bound = max(top_bound, y + cnt_h)
            else:
                bottom_bound = min(bottom_bound, y)
        else:
            # 垂直直线:区分左侧/右侧直线,更新对应边界
            if x < w // 2:
                left_bound = max(left_bound, x + cnt_w)
            else:
                right_bound = min(right_bound, x)

    # 校验边界有效性,避免无效裁剪
    top_bound = max(top_bound, 0)
    bottom_bound = min(bottom_bound, h)
    left_bound = max(left_bound, 0)
    right_bound = min(right_bound, w)

    # 裁剪图像到有效区域
    cropped_img = original[top_bound:bottom_bound, left_bound:right_bound]

    # 清理裁剪后图像的残留水平直线
    gray_crop = cv2.cvtColor(cropped_img, cv2.COLOR_BGR2GRAY)
    thresh_crop = cv2.threshold(gray_crop, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
    detected_horizontal = cv2.morphologyEx(thresh_crop, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
    cnts_h = cv2.findContours(detected_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts_h = cnts_h[0] if len(cnts_h) == 2 else cnts_h[1]
    for c in cnts_h:
        cv2.drawContours(cropped_img, [c], -1, (255,255,255), 2)

    # 修复水平直线去除后的图像
    repair_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,6))
    cropped_img = 255 - cv2.morphologyEx(255 - cropped_img, cv2.MORPH_CLOSE, repair_kernel, iterations=1)

    # 清理裁剪后图像的残留垂直直线(旋转处理)
    rotated_crop = cv2.rotate(cropped_img, cv2.ROTATE_90_CLOCKWISE)
    gray_rot = cv2.cvtColor(rotated_crop, cv2.COLOR_BGR2GRAY)
    thresh_rot = cv2.threshold(gray_rot, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
    detected_vertical = cv2.morphologyEx(thresh_rot, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
    cnts_v = cv2.findContours(detected_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts_v = cnts_v[0] if len(cnts_v) == 2 else cnts_v[1]
    for c in cnts_v:
        cv2.drawContours(rotated_crop, [c], -1, (255,255,255), 2)

    # 修复并旋转回原方向
    rotated_crop = 255 - cv2.morphologyEx(255 - rotated_crop, cv2.MORPH_CLOSE, repair_kernel, iterations=1)
    final_img = cv2.rotate(rotated_crop, cv2.ROTATE_90_COUNTERCLOCKWISE)

    # 保存处理后的图像
    os.chdir(folder_path)
    cv2.imwrite(img_name_with_extension, final_img)

关键步骤说明

  1. 直线检测与边界计算:通过形态学操作检测水平和垂直直线,合并掩码后分析轮廓位置,区分顶部/底部水平直线、左侧/右侧垂直直线,以此确定裁剪的有效边界。
  2. 图像裁剪:根据计算出的边界直接裁剪图像,一次性移除直线外侧的冗余字符。
  3. 残留直线清理:对裁剪后的图像复用原有的直线去除逻辑,清理残留的直线痕迹,同时通过形态学修复操作还原字符完整性。
  4. 边界校验:确保边界始终在图像范围内,避免因未检测到直线导致的无效裁剪。

内容的提问来源于stack exchange,提问作者Yassin H Rassul

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 03:03:22