|
import math |
|
import sys |
|
from argparse import ArgumentParser |
|
from pathlib import Path |
|
|
|
import cv2 |
|
import onnxruntime |
|
from config import (CLASS_COLORS, CLASS_NAMES, ModelType, YOLOv5_ANCHORS, |
|
YOLOv7_ANCHORS) |
|
from cv2_nms import non_max_suppression |
|
from numpy_coder import Decoder |
|
from preprocess import Preprocess |
|
from tqdm import tqdm |
|
|
|
|
|
sys.path.append(str(Path(__file__).resolve().parents[0])) |
|
|
|
IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif', |
|
'.tiff', '.webp') |
|
|
|
|
|
def path_to_list(path: str): |
|
path = Path(path) |
|
if path.is_file() and path.suffix in IMG_EXTENSIONS: |
|
res_list = [str(path.absolute())] |
|
elif path.is_dir(): |
|
res_list = [ |
|
str(p.absolute()) for p in path.iterdir() |
|
if p.suffix in IMG_EXTENSIONS |
|
] |
|
else: |
|
raise RuntimeError |
|
return res_list |
|
|
|
|
|
def parse_args(): |
|
parser = ArgumentParser() |
|
parser.add_argument( |
|
'img', help='Image path, include image file, dir and URL.') |
|
parser.add_argument('onnx', type=str, help='Onnx file') |
|
parser.add_argument('--type', type=str, help='Model type') |
|
parser.add_argument( |
|
'--img-size', |
|
nargs='+', |
|
type=int, |
|
default=[640, 640], |
|
help='Image size of height and width') |
|
parser.add_argument( |
|
'--out-dir', default='./output', type=str, help='Path to output file') |
|
parser.add_argument( |
|
'--show', action='store_true', help='Show the detection results') |
|
parser.add_argument( |
|
'--score-thr', type=float, default=0.3, help='Bbox score threshold') |
|
parser.add_argument( |
|
'--iou-thr', type=float, default=0.7, help='Bbox iou threshold') |
|
args = parser.parse_args() |
|
return args |
|
|
|
|
|
def main(): |
|
args = parse_args() |
|
out_dir = Path(args.out_dir) |
|
model_type = ModelType(args.type.lower()) |
|
|
|
if not args.show: |
|
out_dir.mkdir(parents=True, exist_ok=True) |
|
|
|
files = path_to_list(args.img) |
|
session = onnxruntime.InferenceSession( |
|
args.onnx, providers=['CPUExecutionProvider']) |
|
preprocessor = Preprocess(model_type) |
|
decoder = Decoder(model_type, model_only=True) |
|
if model_type == ModelType.YOLOV5: |
|
anchors = YOLOv5_ANCHORS |
|
elif model_type == ModelType.YOLOV7: |
|
anchors = YOLOv7_ANCHORS |
|
else: |
|
anchors = None |
|
|
|
for file in tqdm(files): |
|
image = cv2.imread(file) |
|
image_h, image_w = image.shape[:2] |
|
img, (ratio_w, ratio_h) = preprocessor(image, args.img_size) |
|
features = session.run(None, {'images': img}) |
|
decoder_outputs = decoder( |
|
features, |
|
args.score_thr, |
|
num_labels=len(CLASS_NAMES), |
|
anchors=anchors) |
|
nmsd_boxes, nmsd_scores, nmsd_labels = non_max_suppression( |
|
*decoder_outputs, args.score_thr, args.iou_thr) |
|
for box, score, label in zip(nmsd_boxes, nmsd_scores, nmsd_labels): |
|
x0, y0, x1, y1 = box |
|
x0 = math.floor(min(max(x0 / ratio_w, 1), image_w - 1)) |
|
y0 = math.floor(min(max(y0 / ratio_h, 1), image_h - 1)) |
|
x1 = math.ceil(min(max(x1 / ratio_w, 1), image_w - 1)) |
|
y1 = math.ceil(min(max(y1 / ratio_h, 1), image_h - 1)) |
|
cv2.rectangle(image, (x0, y0), (x1, y1), CLASS_COLORS[label], 2) |
|
cv2.putText(image, f'{CLASS_NAMES[label]}: {score:.2f}', |
|
(x0, y0 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, |
|
(0, 255, 255), 2) |
|
if args.show: |
|
cv2.imshow('result', image) |
|
cv2.waitKey(0) |
|
else: |
|
cv2.imwrite(f'{out_dir / Path(file).name}', image) |
|
|
|
|
|
if __name__ == '__main__': |
|
main() |
|
|