mirror of
https://github.com/RapidAI/RapidOCR.git
synced 2026-11-12 05:50:49 +08:00
170 lines
5.6 KiB
Python
170 lines
5.6 KiB
Python
# -*- encoding: utf-8 -*-
|
|
# @Author: SWHL
|
|
# @Contact: liekkaskono@163.com
|
|
import importlib
|
|
from pathlib import Path
|
|
import warnings
|
|
|
|
import cv2
|
|
import numpy as np
|
|
from onnxruntime import (GraphOptimizationLevel, InferenceSession,
|
|
SessionOptions, get_available_providers, get_device)
|
|
|
|
|
|
class OrtInferSession():
|
|
def __init__(self, config):
|
|
sess_opt = SessionOptions()
|
|
sess_opt.log_severity_level = 4
|
|
sess_opt.enable_cpu_mem_arena = False
|
|
sess_opt.graph_optimization_level = GraphOptimizationLevel.ORT_ENABLE_ALL
|
|
|
|
cuda_ep = 'CUDAExecutionProvider'
|
|
cpu_ep = 'CPUExecutionProvider'
|
|
cpu_provider_options = {"arena_extend_strategy": "kSameAsRequested", }
|
|
|
|
EP_list = []
|
|
if config['use_cuda'] and get_device() == 'GPU' \
|
|
and cuda_ep in get_available_providers():
|
|
EP_list = [(cuda_ep, config[cuda_ep])]
|
|
EP_list.append((cpu_ep, cpu_provider_options))
|
|
|
|
self._verify_model(config['model_path'])
|
|
self.session = InferenceSession(config['model_path'],
|
|
sess_options=sess_opt,
|
|
providers=EP_list)
|
|
|
|
has_cuda_ep = cuda_ep not in self.session.get_providers()
|
|
if config['use_cuda'] and has_cuda_ep:
|
|
warnings.warn(f'{cuda_ep} is not avaiable for current env,'
|
|
f'the inference part is automatically shifted to '
|
|
f'be executed under {cpu_ep}. '
|
|
f'Please ensure the installed onnxruntime-gpu '
|
|
f' version matches your cuda and cudnn version, '
|
|
f'you can check their relations from the offical web site: '
|
|
f'https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html',
|
|
RuntimeWarning)
|
|
|
|
def __call__(self, input_content: np.ndarray) -> np.ndarray:
|
|
input_dict = dict(zip(self.get_input_names(), [input_content]))
|
|
try:
|
|
return self.session.run(self.get_output_names(), input_dict)
|
|
except Exception as e:
|
|
raise ONNXRuntimeError('ONNXRuntime inferece failed.') from e
|
|
|
|
def get_input_names(self, ):
|
|
return [v.name for v in self.session.get_inputs()]
|
|
|
|
def get_output_names(self,):
|
|
return [v.name for v in self.session.get_outputs()]
|
|
|
|
def get_metadata(self):
|
|
meta_dict = self.session.get_modelmeta().custom_metadata_map
|
|
return meta_dict
|
|
|
|
@staticmethod
|
|
def _verify_model(model_path):
|
|
model_path = Path(model_path)
|
|
if not model_path.exists():
|
|
raise FileNotFoundError(f'{model_path} does not exists.')
|
|
if not model_path.is_file():
|
|
raise FileExistsError(f'{model_path} is not a file.')
|
|
|
|
|
|
class ONNXRuntimeError(Exception):
|
|
pass
|
|
|
|
|
|
def create_operators(params):
|
|
"""
|
|
create operators based on the config
|
|
|
|
Args:
|
|
params(list): a dict list, used to create some operators
|
|
"""
|
|
assert isinstance(params, list), ('operator config should be a list')
|
|
mod = importlib.import_module(__name__)
|
|
ops = []
|
|
for operator in params:
|
|
assert isinstance(operator,
|
|
dict) and len(operator) == 1, "yaml format error"
|
|
op_name = list(operator)[0]
|
|
param = {} if operator[op_name] is None else operator[op_name]
|
|
op = getattr(mod, op_name)(**param)
|
|
ops.append(op)
|
|
return ops
|
|
|
|
|
|
class ResizeImage():
|
|
def __init__(self, size=None, resize_short=None):
|
|
if resize_short is not None and resize_short > 0:
|
|
self.resize_short = resize_short
|
|
self.w, self.h = None, None
|
|
elif size is not None:
|
|
self.resize_short = None
|
|
self.w = size if isinstance(size, int) else size[0]
|
|
self.h = size if isinstance(size, int) else size[1]
|
|
else:
|
|
raise ValueError("invalid params for ReisizeImage for '\
|
|
'both 'size' and 'resize_short' are None")
|
|
|
|
def __call__(self, img: np.ndarray):
|
|
img_h, img_w = img.shape[:2]
|
|
|
|
if self.resize_short:
|
|
percent = float(self.resize_short) / min(img_w, img_h)
|
|
w = int(round(img_w * percent))
|
|
h = int(round(img_h * percent))
|
|
else:
|
|
w = self.w
|
|
h = self.h
|
|
return cv2.resize(img, (w, h))
|
|
|
|
|
|
class NormalizeImage():
|
|
def __init__(self,):
|
|
self.scale = np.float32(1.0 / 255.0)
|
|
mean = [0.485, 0.456, 0.406]
|
|
std = [0.229, 0.224, 0.225]
|
|
|
|
shape = 1, 1, 3
|
|
self.mean = np.array(mean).reshape(shape).astype('float32')
|
|
self.std = np.array(std).reshape(shape).astype('float32')
|
|
|
|
def __call__(self, img):
|
|
img = np.array(img).astype(np.float32)
|
|
img = (img * self.scale - self.mean) / self.std
|
|
return img.astype(np.float32)
|
|
|
|
|
|
class ToCHWImage():
|
|
def __init__(self):
|
|
pass
|
|
|
|
def __call__(self, img):
|
|
img = np.array(img)
|
|
return img.transpose((2, 0, 1))
|
|
|
|
|
|
class CropImage():
|
|
def __init__(self, size):
|
|
self.size = size
|
|
if isinstance(size, int):
|
|
self.size = (size, size)
|
|
|
|
def __call__(self, img):
|
|
w, h = self.size
|
|
img_h, img_w = img.shape[:2]
|
|
|
|
if img_h < h or img_w < w:
|
|
raise ValueError(
|
|
f"The size({h}, {w}) of CropImage must be greater than "
|
|
f"size({img_h}, {img_w}) of image."
|
|
)
|
|
|
|
w_start = (img_w - w) // 2
|
|
h_start = (img_h - h) // 2
|
|
|
|
w_end = w_start + w
|
|
h_end = h_start + h
|
|
return img[h_start:h_end, w_start:w_end, :]
|