如何用Python+OpenCV结合easyocr绘制全文本大bounding box并裁剪文本区域
EasyOCR全局文本框裁剪实现方案
问题背景
当前使用EasyOCR检测图像中文本,可输出每个文本对应的独立边界框,现有代码已经实现了低置信度结果过滤、独立文本框标注功能,需要进一步实现包含所有检测文本的全局边界框绘制、以及按该框裁剪图像的功能。
运行依赖与现有代码
环境安装
pip install pytesseract pip install easyocr
运行命令
python main.py -i image1.jpg
现有基础代码
# 导入所需包 from pytesseract import Output import pytesseract import argparse import cv2 from matplotlib import pyplot as plt import numpy as np import os import easyocr from PIL import ImageDraw, Image def remove_lines(image): result = 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, (40,1)) remove_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) cnts = cv2.findContours(remove_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] for c in cnts: cv2.drawContours(result, [c], -1, (255,255,255), 5) # 移除竖线 vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,40)) remove_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2) cnts = cv2.findContours(remove_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] for c in cnts: cv2.drawContours(result, [c], -1, (255,255,255), 5) plt.imshow(result) plt.show() return result # 构造参数解析器 ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True, help="待OCR识别的输入图像路径") ap.add_argument("-c", "--min-conf", type=int, default=0, help="过滤低置信度文本检测结果的最小置信度阈值") args = vars(ap.parse_args()) reader = easyocr.Reader(['ch_sim','en']) # 仅需运行一次,将模型加载到内存中 # 加载输入图像预处理 image = cv2.imread(args["image"]) image = remove_lines(image) # 文本检测与低置信度结果过滤 results = reader.readtext(image) low_precision = [] for text in results: if text[2]<0.45: low_precision.append(text) for i in low_precision: results.remove(i)
功能实现代码
在上述代码末尾添加以下内容,即可完成全局边界框绘制与图像裁剪:
# 提取所有文本框的坐标极值 x_list = [] y_list = [] for box in results: for (x, y) in box[0]: x_list.append(x) y_list.append(y) min_x, max_x = int(min(x_list)), int(max(x_list)) min_y, max_y = int(min(y_list)), int(max(y_list)) # 标注独立文本框与全局边界框 image2 = Image.fromarray(image) draw = ImageDraw.Draw(image2) # 标注独立文本框(红色) for i in range(0, len(results)): p0, p1, p2, p3 = results[i][0] draw.line([*p0, *p1, *p2, *p3, *p0], fill='red', width=1) # 标注全局边界框(绿色) draw.rectangle([(min_x, min_y), (max_x, max_y)], outline='green', width=2) # 裁剪图像 cropped_img = image[min_y:max_y, min_x:max_x] # 效果展示 plt.subplot(121) plt.imshow(np.asarray(image2)) plt.title("标注结果") plt.subplot(122) plt.imshow(cropped_img) plt.title("裁剪结果") plt.show() # 结果保存(可选) cv2.imwrite("cropped_result.png", cropped_img)
说明
- 坐标取整是因为OpenCV图像裁剪需要使用整数索引
- 若需要给裁剪区域增加内边距,可根据实际需求调整四个极值:
min_x -= 5、min_y -=5、max_x +=5、max_y +=5即可
内容的提问来源于stack exchange,提问作者Asp Lab
相关产品推荐
相关产品推荐

