diff --git a/examples/README.md b/examples/README.md index 2c3367d..b8aaf39 100644 --- a/examples/README.md +++ b/examples/README.md @@ -2,9 +2,10 @@ This is a list of real-world applications and walkthroughs. These can be folders ## Ultralytics YOLO example applications -| Title | Format | Contributor | -| --------------------------------------------------------------- | -------- | ------------------------------------------------- | -| [Yolov8/yolov5 ONNX Inference with C++](./Yolov8_CPP_Inference) | C++/ONNX | [Justas Bartnykas](https://github.com/JustasBart) | +| Title | Format | Contributor | +| --------------------------------------------------------------- | ------------------ | --------------------------------------------------- | +| [Yolov8/yolov5 ONNX Inference with C++](./Yolov8_CPP_Inference) | C++/ONNX | [Justas Bartnykas](https://github.com/JustasBart) | +| [YOLOv8-OpenCV-ONNX-Python](./YOLOv8-OpenCV-ONNX-Python) | OpenCV/Python/ONNX | [Farid Inawan](https://github.com/frdteknikelektro) | ## How can you contribute ? diff --git a/examples/YOLOv8-OpenCV-ONNX-Python/README.md b/examples/YOLOv8-OpenCV-ONNX-Python/README.md new file mode 100644 index 0000000..604dcfe --- /dev/null +++ b/examples/YOLOv8-OpenCV-ONNX-Python/README.md @@ -0,0 +1,19 @@ +# YOLOv8 - OpenCV + +Implementation YOLOv8 on OpenCV using ONNX Format. + +Just simply clone and run + +```bash +pip install -r requirements.txt +python main.py +``` + +If you start from scratch: + +```bash +pip install ultralytics +yolo export model=yolov8n.pt imgsz=640 format=onnx opset=12 +``` + +_\*Make sure to include "opset=12"_ diff --git a/examples/YOLOv8-OpenCV-ONNX-Python/main.py b/examples/YOLOv8-OpenCV-ONNX-Python/main.py new file mode 100644 index 0000000..410c908 --- /dev/null +++ b/examples/YOLOv8-OpenCV-ONNX-Python/main.py @@ -0,0 +1,74 @@ +import cv2.dnn +import numpy as np + +from ultralytics.yolo.utils import ROOT, yaml_load +from ultralytics.yolo.utils.checks import check_yaml + +CLASSES = yaml_load(check_yaml('coco128.yaml'))['names'] + +colors = np.random.uniform(0, 255, size=(len(CLASSES), 3)) + + +def draw_bounding_box(img, class_id, confidence, x, y, x_plus_w, y_plus_h): + label = f'{CLASSES[class_id]} ({confidence:.2f})' + color = colors[class_id] + cv2.rectangle(img, (x, y), (x_plus_w, y_plus_h), color, 2) + cv2.putText(img, label, (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) + + +def main(): + model: cv2.dnn.Net = cv2.dnn.readNetFromONNX('yolov8n.onnx') + original_image: np.ndarray = cv2.imread(str(ROOT / 'assets/bus.jpg')) + [height, width, _] = original_image.shape + length = max((height, width)) + image = np.zeros((length, length, 3), np.uint8) + image[0:height, 0:width] = original_image + scale = length / 640 + + blob = cv2.dnn.blobFromImage(image, scalefactor=1 / 255, size=(640, 640)) + model.setInput(blob) + outputs = model.forward() + + outputs = np.array([cv2.transpose(outputs[0])]) + rows = outputs.shape[1] + + boxes = [] + scores = [] + class_ids = [] + + for i in range(rows): + classes_scores = outputs[0][i][4:] + (minScore, maxScore, minClassLoc, (x, maxClassIndex)) = cv2.minMaxLoc(classes_scores) + if maxScore >= 0.25: + box = [ + outputs[0][i][0] - (0.5 * outputs[0][i][2]), outputs[0][i][1] - (0.5 * outputs[0][i][3]), + outputs[0][i][2], outputs[0][i][3]] + boxes.append(box) + scores.append(maxScore) + class_ids.append(maxClassIndex) + + result_boxes = cv2.dnn.NMSBoxes(boxes, scores, 0.25, 0.45, 0.5) + + detections = [] + for i in range(len(result_boxes)): + index = result_boxes[i] + box = boxes[index] + detection = { + 'class_id': class_ids[index], + 'class_name': CLASSES[class_ids[index]], + 'confidence': scores[index], + 'box': box, + 'scale': scale} + detections.append(detection) + draw_bounding_box(original_image, class_ids[index], scores[index], round(box[0] * scale), round(box[1] * scale), + round((box[0] + box[2]) * scale), round((box[1] + box[3]) * scale)) + + cv2.imshow('image', original_image) + cv2.waitKey(0) + cv2.destroyAllWindows() + + return detections + + +if __name__ == '__main__': + main()