| |
| |
|
|
| import os |
| import sys |
| import cv2 |
| import pathlib |
| import argparse |
| import numpy as np |
| import onnxruntime as ort |
|
|
| CURRENT_DIR = pathlib.Path(__file__).parent |
| sys.path.append(str(CURRENT_DIR)) |
|
|
| from coco import COCO_CLASSES |
| from demo_utils import mkdir, multiclass_nms, demo_postprocess, vis |
|
|
|
|
| def make_parser(): |
| parser = argparse.ArgumentParser("onnxruntime inference sample") |
| parser.add_argument( |
| "-m", |
| "--model", |
| type=str, |
| default="yolox-s-int8.onnx", |
| help="Input your onnx model.", |
| ) |
| parser.add_argument( |
| "-i", |
| "--image_path", |
| type=str, |
| default='test_image.png', |
| help="Path to your input image.", |
| ) |
| parser.add_argument( |
| "-o", |
| "--output_dir", |
| type=str, |
| default='demo_output', |
| help="Path to your output directory.", |
| ) |
| parser.add_argument( |
| "-s", |
| "--score_thr", |
| type=float, |
| default=0.3, |
| help="Score threshold to filter the result.", |
| ) |
| parser.add_argument( |
| "--input_shape", |
| type=str, |
| default="640,640", |
| help="Specify an input shape for inference.", |
| ) |
| parser.add_argument( |
| "--ipu", |
| action="store_true", |
| help="Use IPU for inference.", |
| ) |
| parser.add_argument( |
| "--provider_config", |
| type=str, |
| default="vaip_config.json", |
| help="Path of the config file for setting provider_options.", |
| ) |
| return parser |
|
|
|
|
| def preprocess(img, input_shape, swap=(2, 0, 1)): |
| """ |
| Preprocessing part of YOLOX for scaling and padding image as input to the network. |
| |
| Args: |
| img (numpy.ndarray): H x W x C, image read with OpenCV |
| input_shape (tuple(int)): input shape of the network for inference |
| swap (tuple(int)): new order of axes to transpose the input image |
| |
| Returns: |
| padded_img (numpy.ndarray): preprocessed image to be fed to the network |
| ratio (float): ratio for scaling the image to the input shape |
| """ |
| if len(img.shape) == 3: |
| padded_img = np.ones((input_shape[0], input_shape[1], 3), dtype=np.uint8) * 114 |
| else: |
| padded_img = np.ones(input_shape, dtype=np.uint8) * 114 |
| ratio = min(input_shape[0] / img.shape[0], input_shape[1] / img.shape[1]) |
| resized_img = cv2.resize( |
| img, |
| (int(img.shape[1] * ratio), int(img.shape[0] * ratio)), |
| interpolation=cv2.INTER_LINEAR, |
| ).astype(np.uint8) |
| padded_img[: int(img.shape[0] * ratio), : int(img.shape[1] * ratio)] = resized_img |
| padded_img = padded_img.transpose(swap) |
| padded_img = np.ascontiguousarray(padded_img, dtype=np.float32) |
| return padded_img, ratio |
|
|
|
|
| def postprocess(outputs, input_shape, ratio): |
| """ |
| Post-processing part of YOLOX for generating final results from outputs of the network. |
| |
| Args: |
| outputs (tuple(numpy.ndarray)): outputs of the detection heads with onnxruntime session |
| input_shape (tuple(int)): input shape of the network for inference |
| ratio (float): ratio for scaling the image to the input shape |
| |
| Returns: |
| dets (numpy.ndarray): n x 6, dets[:,:4] -> boxes, dets[:,4] -> scores, dets[:,5] -> class indices |
| """ |
| outputs = [out.reshape(*out.shape[:2], -1).transpose(0,2,1) for out in outputs] |
| outputs = np.concatenate(outputs, axis=1) |
| outputs[..., 4:] = sigmoid(outputs[..., 4:]) |
| predictions = demo_postprocess(outputs, input_shape, p6=False)[0] |
| boxes = predictions[:, :4] |
| scores = predictions[:, 4:5] * predictions[:, 5:] |
| boxes_xyxy = np.ones_like(boxes) |
| boxes_xyxy[:, 0] = boxes[:, 0] - boxes[:, 2]/2. |
| boxes_xyxy[:, 1] = boxes[:, 1] - boxes[:, 3]/2. |
| boxes_xyxy[:, 2] = boxes[:, 0] + boxes[:, 2]/2. |
| boxes_xyxy[:, 3] = boxes[:, 1] + boxes[:, 3]/2. |
| boxes_xyxy /= ratio |
| dets = multiclass_nms(boxes_xyxy, scores, nms_thr=0.45, score_thr=0.1) |
| return dets |
|
|
|
|
| def sigmoid(x): |
| return 1.0 / (1.0 + np.exp(-x)) |
|
|
|
|
| if __name__ == '__main__': |
| args = make_parser().parse_args() |
| input_shape = tuple(map(int, args.input_shape.split(','))) |
| origin_img = cv2.imread(args.image_path) |
| img, ratio = preprocess(origin_img, input_shape) |
| if args.ipu: |
| providers = ["VitisAIExecutionProvider"] |
| provider_options = [{"config_file": args.provider_config}] |
| else: |
| providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] |
| provider_options = None |
| session = ort.InferenceSession(args.model, providers=providers, provider_options=provider_options) |
| |
| ort_inputs = {session.get_inputs()[0].name: np.transpose(img[None, :, :, :], (0, 2 ,3, 1))} |
| outputs = session.run(None, ort_inputs) |
| outputs = [np.transpose(out, (0, 3, 1, 2)) for out in outputs] |
| dets = postprocess(outputs, input_shape, ratio) |
| if dets is not None: |
| final_boxes, final_scores, final_cls_inds = dets[:, :4], dets[:, 4], dets[:, 5] |
| origin_img = vis(origin_img, final_boxes, final_scores, final_cls_inds, |
| conf=args.score_thr, class_names=COCO_CLASSES) |
| mkdir(args.output_dir) |
| output_path = os.path.join(args.output_dir, os.path.basename(args.image_path)) |
| cv2.imwrite(output_path, origin_img) |
|
|