如何加速Android应用中EasyOCR的图像处理速度?
优化EasyOCR处理速度的方案
针对你在Android上用Chaquopy运行EasyOCR和pyzbar遇到的单图处理耗时问题,以下是具体的优化方向:
1. 优化EasyOCR初始化与识别参数
EasyOCR默认配置偏向精度,调整参数可大幅提升速度:
- 使用轻量识别模型:初始化时指定
recognition_network='small',小模型速度更快,足以应对数字和简单文本识别 - 限制识别字符范围:通过
allowlist参数只允许数字和逗号,减少模型计算量 - 降低返回细节:设置
detail=0只返回识别文本,无需坐标等额外信息 - 启用GPU加速:若设备支持,确保
gpu=True(Chaquopy需配置支持GPU的OpenCV和PyTorch)
修改后的初始化代码:
language = ['fr'] # 启用轻量模型+限制字符范围+仅返回文本 reader = easyocr.Reader(lang_list=language, recognition_network='small', allowlist='0123456789,', detail=0)
2. 复用图像转换逻辑,避免重复计算
你的三个函数重复实现了base64转cv2图像的逻辑,抽成公共函数减少冗余开销:
def base64_to_cv2(base64_image): """公共函数:base64转cv2图像""" decoded_image = base64.b64decode(base64_image) np_image = np.frombuffer(decoded_image, np.uint8) # 替代fromstring,更安全 return cv2.imdecode(np_image, cv2.IMREAD_UNCHANGED)
3. 简化图像预处理,缩小OCR处理区域
- 进一步压缩ROI:比如在
getPrice中,定位黄色区域后可将ROI再缩小或降低分辨率(如缩放至原尺寸的50%) - 转灰度图:EasyOCR处理灰度图比彩色图更快,传入
readtext前先转换:
roi_gray = cv2.cvtColor(roi_cv2, cv2.COLOR_BGR2GRAY) results = reader.readtext(roi_gray)
4. 优化正则表达式逻辑
getPrice中的正则判断可合并简化,减少循环次数:
# 合并匹配规则,一次覆盖所有符合价格格式的文本 price_pattern = re.compile(r'[^\d]*(\d{1,2}),(\d{2})[^\d]*') for text in results: match = price_pattern.match(text) if match: price = f"{match.group(1)},{match.group(2)} €" break
5. 简化条形码解码逻辑
原代码嵌套过深,改成循环遍历预处理方式,减少冗余判断:
def getBarCodeData(base64_image): image_cv2 = base64_to_cv2(base64_image) image_cv2_gray = cv2.cvtColor(image_cv2, cv2.COLOR_BGR2GRAY) # 定义所有预处理方式列表 preprocess_methods = [ image_cv2, cv2.adaptiveThreshold(image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 51, 1), cv2.adaptiveThreshold(image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 41, 1), cv2.adaptiveThreshold(image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 1), cv2.adaptiveThreshold(image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1), cv2.adaptiveThreshold(image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 1) ] kernel = np.ones((3, 3), np.uint8) barcode_data = 'None' # 遍历所有预处理图像,找到有效条形码 for img in preprocess_methods: barcodes = decode(img, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128]) if barcodes: barcode_data = barcodes[0].data.decode('utf-8') break # 尝试腐蚀膨胀后的图像 eroded = cv2.erode(img, kernel, iterations=1) dilated = cv2.dilate(eroded, kernel, iterations=1) barcodes = decode(dilated, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128]) if barcodes: barcode_data = barcodes[0].data.decode('utf-8') break return str(barcode_data)
6. 并行处理任务
若需同时处理价格、产品编号和条形码,可在子线程中开启多个子任务并行执行(比如用concurrent.futures.ThreadPoolExecutor),注意控制Android设备的线程数量,避免资源耗尽。
优化后的完整代码
import pyzbar from pyzbar.pyzbar import decode import easyocr import cv2 import numpy as np import re import base64 # 初始化EasyOCR,使用轻量模型+限制字符范围 language = ['fr'] reader = easyocr.Reader(lang_list=language, recognition_network='small', allowlist='0123456789,', detail=0) def base64_to_cv2(base64_image): """公共函数:base64转cv2图像""" decoded_image = base64.b64decode(base64_image) np_image = np.frombuffer(decoded_image, np.uint8) return cv2.imdecode(np_image, cv2.IMREAD_UNCHANGED) def getPrice(base64_image): YELLOW_MIN = np.array([20, 100, 100], dtype=np.uint8) YELLOW_MAX = np.array([40, 255, 255], dtype=np.uint8) image_cv2 = base64_to_cv2(base64_image) image_cv2_hsv = cv2.cvtColor(image_cv2, cv2.COLOR_BGR2HSV) # 定位价格区域 yellow_mask = cv2.inRange(image_cv2_hsv, YELLOW_MIN, YELLOW_MAX) contours = cv2.findContours(yellow_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] if not contours: return 'None' greater_contour = max(contours, key=cv2.contourArea) x, y, w, h = cv2.boundingRect(greater_contour) center_x = x + w // 2 center_y = y + h // 2 tamanho_retangulo_central = 0.90 new_x = int(center_x - w * tamanho_retangulo_central / 2) new_y = int(center_y - h * tamanho_retangulo_central / 2) new_w = int(w * tamanho_retangulo_central) new_h = int(h * tamanho_retangulo_central) roi_cv2 = image_cv2[new_y:new_y + new_h, new_x:new_x + new_w] # 转灰度图加速OCR roi_gray = cv2.cvtColor(roi_cv2, cv2.COLOR_BGR2GRAY) results = reader.readtext(roi_gray) # 简化正则匹配 price_pattern = re.compile(r'[^\d]*(\d{1,2}),(\d{2})[^\d]*') price = 'None' for text in results: match = price_pattern.match(text) if match: price = f"{match.group(1)},{match.group(2)} €" break return str(price) def getProductNum(base64_image): image_cv2 = base64_to_cv2(base64_image) # 图像缩放 zoom_percent = 0.2 height, width, _ = image_cv2.shape resized_image = cv2.resize(image_cv2, (int(width * zoom_percent), int(height * zoom_percent))) # 转灰度图 resized_gray = cv2.cvtColor(resized_image, cv2.COLOR_BGR2GRAY) results = reader.readtext(resized_gray) product_num = 'None' for text in results: if re.match(r'^\d{7}$', text): product_num = text break return str(product_num) def getBarCodeData(base64_image): image_cv2 = base64_to_cv2(base64_image) image_cv2_gray = cv2.cvtColor(image_cv2, cv2.COLOR_BGR2GRAY) preprocess_methods = [ image_cv2, cv2.adaptiveThreshold(image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 51, 1), cv2.adaptiveThreshold(image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 41, 1), cv2.adaptiveThreshold(image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 1), cv2.adaptiveThreshold(image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1), cv2.adaptiveThreshold(image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 1) ] kernel = np.ones((3, 3), np.uint8) barcode_data = 'None' for img in preprocess_methods: barcodes = decode(img, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128]) if barcodes: barcode_data = barcodes[0].data.decode('utf-8') break eroded = cv2.erode(img, kernel, iterations=1) dilated = cv2.dilate(eroded, kernel, iterations=1) barcodes = decode(dilated, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128]) if barcodes: barcode_data = barcodes[0].data.decode('utf-8') break return str(barcode_data)
内容的提问来源于stack exchange,提问作者lucaralves
相关产品推荐
相关产品推荐

