yolov5_onnx_infer.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import onnxruntime
  2. import numpy as np
  3. import cv2
  4. def letterbox(im, new_shape=(640, 640), color=(114, 114, 114)):
  5. """Resize image and pad to meet stride multiple."""
  6. shape = im.shape[:2] # current shape [height, width]
  7. if isinstance(new_shape, int):
  8. new_shape = (new_shape, new_shape)
  9. r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
  10. new_unpad = (int(round(shape[1] * r)), int(round(shape[0] * r)))
  11. dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]
  12. dw /= 2
  13. dh /= 2
  14. im_resized = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR)
  15. top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
  16. left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
  17. im_padded = cv2.copyMakeBorder(im_resized, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)
  18. return im_padded, r, (dw, dh)
  19. def preprocess(image_path, input_shape=(640, 640)):
  20. img0 = cv2.imread(image_path)
  21. assert img0 is not None, f"Image not found: {image_path}"
  22. img, ratio, (dw, dh) = letterbox(img0, new_shape=input_shape)
  23. img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3xHxW
  24. img = np.ascontiguousarray(img, dtype=np.float32) / 255.0 # normalize to 0-1
  25. return img0, img, ratio, dw, dh
  26. def xywh2xyxy(x):
  27. y = np.zeros_like(x)
  28. y[:, 0] = x[:, 0] - x[:, 2] / 2 # x1
  29. y[:, 1] = x[:, 1] - x[:, 3] / 2 # y1
  30. y[:, 2] = x[:, 0] + x[:, 2] / 2 # x2
  31. y[:, 3] = x[:, 1] + x[:, 3] / 2 # y2
  32. return y
  33. def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45):
  34. """Performs Non-Maximum Suppression on inference results."""
  35. # Adapted from https://github.com/ultralytics/yolov5/blob/master/utils/general.py
  36. boxes = prediction[:, :4]
  37. scores = prediction[:, 4] * prediction[:, 5:].max(axis=1)
  38. classes = prediction[:, 5:].argmax(axis=1)
  39. # Filter by confidence threshold
  40. mask = scores > conf_thres
  41. boxes = boxes[mask]
  42. scores = scores[mask]
  43. classes = classes[mask]
  44. if boxes.shape[0] == 0:
  45. return np.empty((0, 6))
  46. # Convert boxes to x1,y1,x2,y2
  47. boxes = xywh2xyxy(boxes)
  48. # Compute areas
  49. areas = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
  50. order = scores.argsort()[::-1]
  51. keep = []
  52. while order.size > 0:
  53. i = order[0]
  54. keep.append(i)
  55. xx1 = np.maximum(boxes[i, 0], boxes[order[1:], 0])
  56. yy1 = np.maximum(boxes[i, 1], boxes[order[1:], 1])
  57. xx2 = np.minimum(boxes[i, 2], boxes[order[1:], 2])
  58. yy2 = np.minimum(boxes[i, 3], boxes[order[1:], 3])
  59. w = np.maximum(0.0, xx2 - xx1)
  60. h = np.maximum(0.0, yy2 - yy1)
  61. inter = w * h
  62. ovr = inter / (areas[i] + areas[order[1:]] - inter)
  63. inds = np.where(ovr <= iou_thres)[0]
  64. order = order[inds + 1]
  65. return np.concatenate([
  66. boxes[keep],
  67. scores[keep, None],
  68. classes[keep, None].astype(np.float32)
  69. ], axis=1)
  70. def infer_onnx(onnx_path, image_path, input_size=(640, 640), conf_thres=0.25, iou_thres=0.45):
  71. # 1. 预处理
  72. img0, img, ratio, dw, dh = preprocess(image_path, input_size)
  73. img_input = np.expand_dims(img, axis=0) # batch size 1
  74. # 2. 加载 ONNX 模型
  75. session = onnxruntime.InferenceSession(onnx_path, providers=['CPUExecutionProvider'])
  76. input_name = session.get_inputs()[0].name
  77. outputs = session.run(None, {input_name: img_input})
  78. pred = outputs[0] # shape (1, N, 85) for COCO 80 classes + 5
  79. # 3. NMS 处理
  80. dets = non_max_suppression(pred[0], conf_thres, iou_thres)
  81. print("dets:", dets) # NMS后的最终框
  82. print("ratio, dw, dh:", ratio, dw, dh) # 预处理返回的缩放和偏移
  83. # 4. 恢复坐标到原图
  84. if dets.shape[0]:
  85. dets[:, [0, 2]] -= dw # x padding
  86. dets[:, [1, 3]] -= dh # y padding
  87. dets[:, :4] /= ratio
  88. CLASS_NAMES = ['0', '1', '2', 'B2']
  89. # 5. 打印结果
  90. for *box, conf, cls in dets:
  91. print(f"Raw class index from model: {cls}")
  92. x1, y1, x2, y2 = map(int, box)
  93. class_id = int(cls)
  94. class_name = CLASS_NAMES[class_id] if class_id < len(CLASS_NAMES) else str(class_id)
  95. label = f"{class_name} {conf:.2f}"
  96. print(f"Class: {class_name}, Conf: {conf:.2f}, Box: [{x1}, {y1}, {x2}, {y2}]")
  97. cv2.rectangle(img0, (x1, y1), (x2, y2), (0, 255, 0), 2)
  98. cv2.putText(img0, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
  99. # 6. 显示图片(可注释掉)
  100. cv2.imshow("result", img0)
  101. cv2.waitKey(0)
  102. cv2.destroyAllWindows()
  103. return dets
  104. if __name__ == "__main__":
  105. import sys
  106. if len(sys.argv) != 3:
  107. print("Usage: python yolov5_onnx_infer.py model.onnx image.jpg")
  108. exit(1)
  109. onnx_path = sys.argv[1]
  110. image_path = sys.argv[2]
  111. infer_onnx(onnx_path, image_path)