|
import onnxruntime |
|
import argparse |
|
import os |
|
from utils import * |
|
|
|
|
|
def pre_process(img): |
|
""" |
|
Preprocessing part of YOLOv3 for scaling and padding image as input to the network. |
|
Args: |
|
img (numpy.ndarray): H x W x C, image read with OpenCV |
|
Returns: |
|
padded_img (numpy.ndarray): preprocessed image to be fed to the network |
|
""" |
|
img = letterbox(img, auto=False)[0] |
|
|
|
img = img.transpose((2, 0, 1))[::-1] |
|
img = np.ascontiguousarray(img) |
|
img = img.astype("float32") |
|
img = img / 255.0 |
|
img = img[np.newaxis, :] |
|
return img |
|
|
|
|
|
def post_process(x, conf_thres=0.1, iou_thres=0.6, multi_label=True, |
|
classes=None, agnostic=False): |
|
""" |
|
Post-processing part of YOLOv3 for generating final results from outputs of the network. |
|
Returns: |
|
pred (torch.tensor): n x 6, dets[:,:4] -> boxes, dets[:,4] -> scores, dets[:,5] -> class indices |
|
""" |
|
stride = [32, 16, 8] |
|
anchors = [[10, 13, 16, 30, 33, 23], |
|
[30, 61, 62, 45, 59, 119], |
|
[116, 90, 156, 198, 373, 326]] |
|
temp = [13, 26, 52] |
|
res = [] |
|
|
|
def create_grids(ng=(13, 13)): |
|
nx, ny = ng |
|
ng = torch.tensor(ng, dtype=torch.float) |
|
|
|
|
|
yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)]) |
|
grid = torch.stack((xv, yv), 2).view((1, 1, ny, nx, 2)).float() |
|
|
|
return grid |
|
|
|
for i in range(3): |
|
out = torch.from_numpy(x[i]) |
|
|
|
bs, _, ny, nx = out.shape |
|
|
|
anchor = torch.Tensor(anchors[2 - i]).reshape(3, 2) |
|
anchor_vec = anchor / stride[i] |
|
anchor_wh = anchor_vec.view(1, 3, 1, 1, 2) |
|
|
|
grid = create_grids((nx, ny)) |
|
|
|
out = out.view( |
|
bs, 3, 85, temp[i], temp[i]).permute( |
|
0, 1, 3, 4, 2).contiguous() |
|
|
|
io = out.clone() |
|
|
|
io[..., :2] = torch.sigmoid(io[..., :2]) + grid |
|
io[..., 2:4] = torch.exp(io[..., 2:4]) * anchor_wh |
|
io[..., :4] *= stride[i] |
|
torch.sigmoid_(io[..., 4:]) |
|
|
|
res.append(io.view(bs, -1, 85)) |
|
|
|
pred = non_max_suppression(torch.cat(res, 1), conf_thres, |
|
iou_thres, multi_label=multi_label, |
|
classes=classes, agnostic=agnostic) |
|
|
|
return pred |
|
|
|
|
|
if __name__ == '__main__': |
|
parser = argparse.ArgumentParser( |
|
prog='One image inference of onnx model') |
|
parser.add_argument( |
|
'--img', |
|
type=str, |
|
help='Path of input image') |
|
parser.add_argument( |
|
'--out', |
|
type=str, |
|
default='.', |
|
help='Path of out put image') |
|
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 seting provider_options.") |
|
parser.add_argument( |
|
"--onnx_path", |
|
type=str, |
|
default="yolov3-8.onnx", |
|
help="Path of the onnx model.") |
|
|
|
opt = parser.parse_args() |
|
with open('coco.names', 'r') as f: |
|
names = f.read() |
|
|
|
if opt.ipu: |
|
providers = ["VitisAIExecutionProvider"] |
|
provider_options = [{"config_file": opt.provider_config}] |
|
else: |
|
providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] |
|
provider_options = None |
|
|
|
onnx_path = opt.onnx_path |
|
onnx_model = onnxruntime.InferenceSession( |
|
onnx_path, providers=providers, provider_options=provider_options) |
|
|
|
path = opt.img |
|
new_path = os.path.join(opt.out, "demo_infer.jpg") |
|
|
|
conf_thres, iou_thres, classes, agnostic_nms, max_det = 0.25, \ |
|
0.45, None, False, 1000 |
|
|
|
img0 = cv2.imread(path) |
|
img = pre_process(img0) |
|
|
|
onnx_input = {onnx_model.get_inputs()[0].name: np.transpose(img, (0, 2 ,3, 1))} |
|
onnx_output = onnx_model.run(None, onnx_input) |
|
onnx_output = [np.transpose(out, (0, 3, 1, 2)) for out in onnx_output] |
|
|
|
pred = post_process(onnx_output, conf_thres, |
|
iou_thres, multi_label=False, |
|
classes=classes, agnostic=agnostic_nms) |
|
|
|
colors = [[random.randint(0, 255) for _ in range(3)] |
|
for _ in range(len(names))] |
|
det = pred[0] |
|
im0 = img0.copy() |
|
|
|
if det is None: |
|
print('No objects detected!') |
|
|
|
elif len(det): |
|
|
|
det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() |
|
|
|
|
|
for *xyxy, conf, cls in reversed(det): |
|
label = '%s %.2f' % (names[int(cls)], conf) |
|
plot_one_box(xyxy, im0, label=label, color=colors[int(cls)]) |
|
|
|
|
|
cv2.imwrite(new_path, im0) |
|
|