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

如何加速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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 00:08:09