Speed up easyocr

688 Views Asked by At

I developed an Android application that uses chaquopy to run easyocr and pyzbar modules, during the processing of an input image. The app goal is to be able to extract text and decode barcodes present in the input image. The problem is that the Python script takes about a minute to finish processing the image. The time it takes is essentially due to easyocr processing. How can I speed up the process?

I already run the script in a secondary thread.

Python script:


import pyzbar
from pyzbar.pyzbar import decode
import easyocr
import cv2
import numpy as np
import re
import os
import io
import base64

language = ['fr']
reader = easyocr.Reader(lang_list=language)

def getPrice(base64_image):

    YELLOW_MIN = np.array([20, 100, 100], dtype=np.uint8)
    YELLOW_MAX = np.array([40, 255, 255], dtype=np.uint8)
    
    # Converte-se o base64 numa imagem cv2.
    decoded_image = base64.b64decode(base64_image)
    np_image = np.fromstring(decoded_image, np.uint8)
    image_cv2 = cv2.imdecode(np_image, cv2.IMREAD_UNCHANGED)
    
    # Conversão da imagem RGB em HSV.
    image_cv2_hsv = cv2.cvtColor(image_cv2, cv2.COLOR_BGR2HSV)
    
    # Isolamento da região onde se encontra o preço.
    yellow_mask = cv2.inRange(image_cv2_hsv, YELLOW_MIN, YELLOW_MAX)
    contours = cv2.findContours(yellow_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
    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]
    
    # Implementação do OCR.
    results = reader.readtext(roi_cv2)
    
    # Pós-processamento da saída do OCR.
    flag = True
    output = ''
    int_part = ''
    decimal_part = ''
    price = 'None'
    for result in results:
        text = result[1]
        if re.match(r'^\d{1},\d{2}$', text):
            flag = False
            output = text
            break
        elif re.match(r'^[^\d]\d{1},\d{2}$', text):
            flag = False
            output = text
            break
        elif re.match(r'^\d{2},\d{2}$', text):
            flag = False
            output = text[1:]
            break
        elif re.match(r'^[^\d]\d{2},\d{2}$', text):
            flag = False
            output = text
            break
        elif re.match(r'^\d{3},\d{2}$', text):
            flag = False
            output = text[1:]
            break
        elif re.match(r'^[^\d]\d{1} ,\d{2}$', text):
            flag = False
            output = text
            break
        elif re.match(r'^[^\d]\d{2} ,\d{2}$', text):
            flag = False
            output = text
            break
    if flag == True:
        for result in results:
            text = result[1]
            if re.match(r'^[^\d]\d{1}$', text):
                int_part = text
            elif re.match(r'^\d{2}$', text):
                decimal_part = text
            elif re.match(r'^[^\d]\d{1},$', text):
                int_part = text
            elif re.match(r'^,\d{2}$', text):
                decimal_part = text
            elif re.match(r'^[^\d]\d{2},$', text):
                int_part = text
            elif re.match(r'^[^\d]\d{2}$', text):
                int_part = text
            elif re.match(r'^\d{3},$', text):
                int_part = text[1:]
            elif re.match(r'^\d{3}$', text):
                int_part = text[1:]
            elif re.match(r"^',\d{2}$", text):
                decimal_part = text
            if int_part != '' and decimal_part != '':
                break    
        output = int_part + decimal_part
    digits = re.findall(r'\d', output)
    if len(digits) == 3:
        price = digits[0] + ',' + digits[1] + digits[2] + ' €'
    elif len(digits) == 4:
        price = digits[0] + digits[1] + ',' + digits[2] + digits[3] + ' €'
     
    return str(price)    
    
def getProductNum(base64_image):
    
    # Converte-se o base64 numa imagem cv2.
    decoded_image = base64.b64decode(base64_image)
    np_image = np.fromstring(decoded_image, np.uint8)
    image_cv2 = cv2.imdecode(np_image, cv2.IMREAD_UNCHANGED)
    
    # Redimensionamento da imagem.
    zoom_percent = 0.2
    height, weight, _ = image_cv2.shape
    new_height = int(height * zoom_percent)
    new_weight = int(weight * zoom_percent)
    resized_image = cv2.resize(image_cv2, (new_weight, new_height))
    
    # Implementação do OCR.
    results = reader.readtext(resized_image)
    
    # Pós processamento da saída do OCR.
    product_num = 'None'
    for result in results:
        text = result[1]
        if re.match(r'^\d{7}$', text):
            product_num = text
            break
            
    return str(product_num)         
    
def getBarCodeData(base64_image):
    
    # Converte-se o base64 numa imagem cv2.
    decoded_image = base64.b64decode(base64_image)
    np_image = np.fromstring(decoded_image, np.uint8)
    image_cv2 = cv2.imdecode(np_image, cv2.IMREAD_UNCHANGED)
    
    # Binarização da imagem RGB.
    image_cv2_gray = cv2.cvtColor(image_cv2, cv2.COLOR_BGR2GRAY)
    image_cv2_binary_1 = cv2.adaptiveThreshold(
        image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 51, 1
    )
    image_cv2_binary_2 = cv2.adaptiveThreshold(
        image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 41, 1
    )
    image_cv2_binary_3 = cv2.adaptiveThreshold(
        image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 1
    )
    image_cv2_binary_4 = cv2.adaptiveThreshold(
        image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1
    )
    image_cv2_binary_5 = cv2.adaptiveThreshold(
        image_cv2_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 1
    )
    
    # Decodificação do código de barras.
    barcode_data = 'None'
    barcodes = decode(image_cv2, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
    if len(barcodes) != 0:
        for barcode in barcodes:
            barcode_data = barcode.data.decode('utf-8')
            barcode_type = barcode.type            
    elif len(barcodes) == 0:
        barcodes = decode(image_cv2_binary_1, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
        if len(barcodes) != 0:
            for barcode in barcodes:
                barcode_data = barcode.data.decode('utf-8')
                barcode_type = barcode.type                
        elif len(barcodes) == 0:
            kernel = np.ones((3, 3), np.uint8)
            eroded_image = cv2.erode(image_cv2_binary_1, kernel, iterations=1)
            dilated_image = cv2.dilate(eroded_image, kernel, iterations=1)
            barcodes = decode(dilated_image, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
            if len(barcodes) != 0:
                for barcode in barcodes:
                    barcode_data = barcode.data.decode('utf-8')
                    barcode_type = barcode.type                    
            elif len(barcodes) == 0:
                barcodes = decode(image_cv2_binary_2, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
                if len(barcodes) != 0:
                    for barcode in barcodes:
                        barcode_data = barcode.data.decode('utf-8')
                        barcode_type = barcode.type                        
                elif len(barcodes) == 0:
                    kernel = np.ones((3, 3), np.uint8)
                    eroded_image = cv2.erode(image_cv2_binary_2, kernel, iterations=1)
                    dilated_image = cv2.dilate(eroded_image, kernel, iterations=1)
                    barcodes = decode(dilated_image, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
                    if len(barcodes) != 0:
                        for barcode in barcodes:
                            barcode_data = barcode.data.decode('utf-8')
                            barcode_type = barcode.type                            
                    elif len(barcodes) == 0:
                        barcodes = decode(image_cv2_binary_3, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
                        if len(barcodes) != 0:
                            for barcode in barcodes:
                                barcode_data = barcode.data.decode('utf-8')
                                barcode_type = barcode.type                                
                        elif len(barcodes) == 0:
                            kernel = np.ones((3, 3), np.uint8)
                            eroded_image = cv2.erode(image_cv2_binary_3, kernel, iterations=1)
                            dilated_image = cv2.dilate(eroded_image, kernel, iterations=1)
                            barcodes = decode(dilated_image, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
                            if len(barcodes) != 0:
                                for barcode in barcodes:
                                    barcode_data = barcode.data.decode('utf-8')
                                    barcode_type = barcode.type                            
                            elif len(barcodes) == 0:
                                barcodes = decode(image_cv2_binary_4, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
                                if len(barcodes) != 0:
                                    for barcode in barcodes:
                                        barcode_data = barcode.data.decode('utf-8')
                                        barcode_type = barcode.type                                        
                                elif len(barcodes) == 0:
                                    kernel = np.ones((3, 3), np.uint8)
                                    eroded_image = cv2.erode(image_cv2_binary_4, kernel, iterations=1)
                                    dilated_image = cv2.dilate(eroded_image, kernel, iterations=1)
                                    barcodes = decode(dilated_image, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
                                    if len(barcodes) != 0:
                                        for barcode in barcodes:
                                            barcode_data = barcode.data.decode('utf-8')
                                            barcode_type = barcode.type                                            
                                    elif len(barcodes) == 0:
                                        barcodes = decode(image_cv2_binary_5, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
                                        if len(barcodes) != 0:
                                            for barcode in barcodes:
                                                barcode_data = barcode.data.decode('utf-8')
                                                barcode_type = barcode.type                                    
                                        elif len(barcodes) == 0:
                                            kernel = np.ones((3, 3), np.uint8)
                                            eroded_image = cv2.erode(image_cv2_binary_5, kernel, iterations=1)
                                            dilated_image = cv2.dilate(eroded_image, kernel, iterations=1)
                                            barcodes = decode(dilated_image, symbols=[pyzbar.pyzbar.ZBarSymbol.CODE128])
                                            if len(barcodes) != 0:
                                                for barcode in barcodes:
                                                    barcode_data = barcode.data.decode('utf-8')
                                                    barcode_type = barcode.type
    
    return str(barcode_data)                                                
1

There are 1 best solutions below

0
EL Amine Bechorfa On

I recommend using KerasOCR with TensorflowLITE so you can integrate the lightweight format of the model directly in your application no need to launch python scripts with Chaquopy lib, you will notice a remarkable improvement in the performance of the application.