如何优化pytesseract视频帧文本提取性能?实现无裁剪准确识别
性能优化与文本识别问题
我一直在查找相关帖子,试图优化以下脚本的性能,但效果甚微。测试发现每次调用pytesseract.image_to_data耗时约0.2秒,请问有明显的提速方法吗?我希望无需将图像裁剪为3个独立区域就能提取所有文本,但不裁剪的话识别结果总是错误。试过适配不同字符大小的psm模式,但效果不佳。我在该领域经验不足,可能存在操作误区,恳请各位提供建议。
示例图像(裁剪后):
预处理函数代码
def preprocess(frame, xy): _frame = cv.pyrUp(frame[xy['y1']:xy['y2'], xy['x1']:xy['x2']]) _frame = cv.cvtColor(_frame, cv.COLOR_BGR2GRAY) _frame = cv.GaussianBlur(_frame, (3, 3), 0) _frame = cv.threshold(_frame, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1] kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3)) _frame = cv.morphologyEx(_frame, cv.MORPH_OPEN, kernel, iterations=1) _frame = 255 - _frame return np.dstack([_frame, _frame, _frame])
文本提取函数代码
def to_data(frame): img_data = pytesseract.image_to_data(frame, config='--oem 3 --psm 7', output_type=Output.DICT) return img_data.get('text', [-1])[-1]
主函数代码
def run(file_name, network, interval, show): file = pathlib.Path(PLAYBACK_PATH.format(str(file_name))) cap = cv.VideoCapture(str(file), 0) fps = int(cap.get(cv.CAP_PROP_FPS)) dataset = [] ix = 0 while True: ret, frame = cap.read() if frame is None: break if ix % (fps * interval) == 0: row = [] for lookup, xy in NETWORKS[network].items(): _frame = preprocess(frame, xy) _data = to_data(_frame) row.append(_data) if show: cv.imshow('frame', _frame) cv.waitKey(1) row.append(ix) dataset.append(row) else: pass ix += 1 cap.release() cv.destroyAllWindows() return dataset
优化建议与解决方案
一、性能提速方法
替换更快的OCR引擎
尝试easyocr或paddleocr,轻量模型的单区域识别耗时能压缩到0.05秒以内,比Tesseract效率更高。如果坚持用Tesseract,将--oem 3改为--oem 1(纯LSTM引擎),速度会明显提升,对清晰文本识别效果影响极小。精简预处理步骤
- Tesseract支持直接识别灰度图,删掉
np.dstack([_frame, _frame, _frame]),直接返回灰度图,节省内存和转换时间。 - 评估
pyrUp的必要性:若原裁剪区域文本足够清晰,放大操作会增加图像尺寸拖慢识别,可尝试移除或替换为更轻量的cv.resize。
- Tesseract支持直接识别灰度图,删掉
并行处理多区域
用concurrent.futures.ThreadPoolExecutor并行处理多个裁剪区域的识别,利用多核CPU资源,示例修改如下:from concurrent.futures import ThreadPoolExecutor def process_single(xy): _frame = preprocess(frame, xy) return to_data(_frame) # 替换主循环中的for循环 with ThreadPoolExecutor(max_workers=3) as executor: row = list(executor.map(process_single, NETWORKS[network].values()))
二、不裁剪实现正确识别的方法
精准配置Tesseract参数
- 明确指定字符白名单,比如仅识别数字和字母:添加
-c tessedit_char_whitelist=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ到config,缩小识别范围提升准确率和速度。 - 尝试
--psm 6(假设文本为单一均匀块)或--psm 11(稀疏文本识别),配合字符白名单使用。
- 明确指定字符白名单,比如仅识别数字和字母:添加
全局预处理+坐标筛选
不对原图裁剪,先对整图做预处理(转灰度、阈值二值化、形态学操作),调用image_to_data获取所有文本的坐标和内容,再通过原xy区域的坐标范围筛选目标文本。自动文本区域定位
用OpenCV轮廓检测自动定位文本区域,替代手动裁剪:def find_text_regions(frame): gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) blur = cv.GaussianBlur(gray, (3,3), 0) thresh = cv.threshold(blur, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1] contours, _ = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) regions = [] for cnt in contours: x,y,w,h = cv.boundingRect(cnt) if w > 20 and h > 20: # 过滤小噪声轮廓 regions.append({'x1':x, 'y1':y, 'x2':x+w, 'y2':y+h}) return regions用该函数定位所有文本区域后逐个识别,比手动裁剪更灵活。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

