如何调整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)
关键步骤说明
- 直线检测与边界计算:通过形态学操作检测水平和垂直直线,合并掩码后分析轮廓位置,区分顶部/底部水平直线、左侧/右侧垂直直线,以此确定裁剪的有效边界。
- 图像裁剪:根据计算出的边界直接裁剪图像,一次性移除直线外侧的冗余字符。
- 残留直线清理:对裁剪后的图像复用原有的直线去除逻辑,清理残留的直线痕迹,同时通过形态学修复操作还原字符完整性。
- 边界校验:确保边界始终在图像范围内,避免因未检测到直线导致的无效裁剪。
内容的提问来源于stack exchange,提问作者Yassin H Rassul
相关产品推荐
相关产品推荐

