{"id":16461518,"url":"https://github.com/lddl/object-detection-opencv-rust","last_synced_at":"2026-05-11T14:05:28.552Z","repository":{"id":207776808,"uuid":"720037115","full_name":"LdDl/object-detection-opencv-rust","owner":"LdDl","description":"Just set of functions to utilize YOLO v3, v4, v7 and v8 version with OpenCV's DNN module","archived":false,"fork":false,"pushed_at":"2026-04-08T20:03:40.000Z","size":7780,"stargazers_count":30,"open_issues_count":1,"forks_count":7,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-04-08T20:25:19.976Z","etag":null,"topics":["computer-vision","cuda","object-detection","onnx","onnxruntime","opencv","yolov3","yolov4","yolov7","yolov8"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LdDl.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-11-17T12:51:56.000Z","updated_at":"2026-03-16T20:31:52.000Z","dependencies_parsed_at":"2024-11-15T01:42:37.901Z","dependency_job_id":"e983225f-2b65-45d5-bee7-f21bf33112b8","html_url":"https://github.com/LdDl/object-detection-opencv-rust","commit_stats":{"total_commits":38,"total_committers":2,"mean_commits":19.0,"dds":0.07894736842105265,"last_synced_commit":"515533924b52ec312a0368db660c4b343a2de136"},"previous_names":["lddl/object-detection-opencv-rust"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/LdDl/object-detection-opencv-rust","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LdDl%2Fobject-detection-opencv-rust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LdDl%2Fobject-detection-opencv-rust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LdDl%2Fobject-detection-opencv-rust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LdDl%2Fobject-detection-opencv-rust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LdDl","download_url":"https://codeload.github.com/LdDl/object-detection-opencv-rust/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LdDl%2Fobject-detection-opencv-rust/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32897973,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-10T13:40:02.631Z","status":"online","status_checked_at":"2026-05-11T02:00:05.975Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["computer-vision","cuda","object-detection","onnx","onnxruntime","opencv","yolov3","yolov4","yolov7","yolov8"],"created_at":"2024-10-11T11:08:28.152Z","updated_at":"2026-05-11T14:05:28.542Z","avatar_url":"https://github.com/LdDl.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Crates.io](https://img.shields.io/crates/v/od_opencv.svg)](https://crates.io/crates/od_opencv)\n[![Downloads](https://img.shields.io/crates/d/od_opencv.svg)](https://crates.io/crates/od_opencv)\n[![Documentation](https://docs.rs/od_opencv/badge.svg)](https://docs.rs/od_opencv)\n\n# Object detection utilities in Rust for YOLO-based neural networks\n\nThis crate provides structures and methods for solving object detection tasks using YOLO models. It supports multiple inference backends:\n\nAlso this crate provides face detection via YuNet model.\n\n- **ORT backend** (default): Pure Rust, no OpenCV required, uses ONNX Runtime\n- **OpenCV backend**: Uses [OpenCV's DNN module](https://docs.opencv.org/4.8.0/d2/d58/tutorial_table_of_content_dnn.html), supports Darknet format\n- **TensorRT backend**: Direct TensorRT inference via [tensorrt-infer](https://crates.io/crates/tensorrt-infer), for NVIDIA GPUs and Jetson devices\n- **RKNN backend**: Rockchip NPU inference for edge devices (RV1106 tested only on LuckFox Pico Ultra W)\n\n| Network type  | ORT (ONNX) | OpenCV (ONNX) | OpenCV (Darknet) | TensorRT (.engine) |\n| ------------- | ---------- | ------------- | ---------------- | ------------------ |\n| YOLO v3 tiny  | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: | :white_check_mark: (via [darknet2onnx] + trtexec) |\n| YOLO v4 tiny  | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: | :white_check_mark: (via [darknet2onnx] + trtexec) |\n| YOLO v7 tiny  | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: | :white_check_mark: (via [darknet2onnx] + trtexec) |\n| YOLO v3       | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: | :white_check_mark: (via [darknet2onnx] + trtexec) |\n| YOLO v4       | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: | :white_check_mark: (via [darknet2onnx] + trtexec) |\n| YOLO v7       | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: (via [darknet2onnx]) | :white_check_mark: | :white_check_mark: (via [darknet2onnx] + trtexec) |\n| YOLO v5u n/s/m/l/x | :white_check_mark: (uses `Model::ort()`) | :white_check_mark: (uses `Model::opencv()`) | :x: | :white_check_mark: (uses `Model::tensorrt()`) |\n| YOLO v5 n/s/m/l/x  | :white_check_mark: (uses `Model::yolov5_ort()`) | :white_check_mark: (uses `Model::yolov5_opencv()`) | :x: | :x: |\n| YOLO v8 n/s/m/l/x | :white_check_mark: | :white_check_mark: | :x: (is it even possible?) | :white_check_mark: (uses `Model::tensorrt()`) |\n| YOLO v9 t/s/m/c/e | :white_check_mark: (uses `ModelUltralyticsOrt`) | :white_check_mark: (uses `ModelUltralyticsV8`) | :x: | :white_check_mark: (uses `Model::tensorrt()`) |\n| YOLO v11 n/s/m/l/x | :white_check_mark: (uses `ModelUltralyticsOrt`) | :white_check_mark: (uses `ModelUltralyticsV8`) | :x: | :white_check_mark: (uses `Model::tensorrt()`) |\n| **Face Detection** | | | | |\n| YuNet (OpenCV Zoo) | :white_check_mark: (uses `Model::yunet_ort()`) | :white_check_mark: (uses `Model::yunet_opencv()`) | :x: | :white_check_mark: (uses `Model::yunet_tensorrt()`) |\n\n**Note on YOLOv3/v4/v7 ONNX:** Darknet `.cfg` + `.weights` can be converted to ONNX using [darknet2onnx](https://github.com/LdDl/darknet2onnx). Use `--format yolov8` to get `[1, 84, N]` output compatible with `Model::ort()` / `Model::opencv()` / `Model::tensorrt()` or `--format yolov5` for `[1, N, 85]` compatible with `Model::yolov5_ort()` / `Model::yolov5_opencv()`. E.g. using `yolov8` format:\n```bash\ndarknet2onnx --cfg yolov4-tiny.cfg --weights yolov4-tiny.weights --output yolov4-tiny-d2o-v8.onnx --format yolov8\n```\n\nFor TensorRT inference you should prepare `.engine` file:\n```bash\ntrtexec --onnx=yolov4-tiny-d2o-v8.onnx --saveEngine=yolov4-tiny-d2o-v8.engine --fp16\n```\nAlso be aware: I've tested only `yolov8` format for TensorRT.\n\n[darknet2onnx]: https://github.com/LdDl/darknet2onnx\n\n**Note on YOLOv9/v11:** These models use the same output format as YOLOv8 (`[1, 84, 8400]`), so `ModelUltralyticsV8` works directly. For opencv-backend it is required to use OpenCV v4.11+ for best compatibility.\n\n**Note on YOLOv10:** YOLOv10's NMS-free architecture uses TopK layer which OpenCV DNN doesn't support. Use YOLOv8/v9/v11 instead, or export YOLOv10 with [patched ultralytics](https://gist.github.com/DarthSim/216551dfd58e5628290e90c1d358704b) that removes built-in NMS. For ORT backend I've not tested YOLOv10 yet.\n\n## Table of Contents\n\n- [About](#about)\n- [Backends](#backends)\n- [Prerequisites](#prerequisites)\n- [Usage](#usage)\n  - [ORT Backend (Default)](#ort-backend-default)\n  - [OpenCV Backend](#opencv-backend)\n  - [TensorRT Backend](#tensorrt-backend)\n  - [RKNN Backend](#rknn-backend)\n  - [Face Detection (YuNet)](#face-detection-yunet)\n- [Features](#features)\n- [Migration from 0.3.x](#migration-from-03x)\n- [References](#references)\n\n## About\n\n_- Why?_\n\nWell, I just tired a bit of boilerplating (model initializing, postprocessing functions and etc.) in my both private and public projects.\n\n_- When it is usefull?_\n\nWell, there are several circumstances when you may need this crate:\n\n* You need to use YOLO as your neural network base;\n* You do not want use Pytorch / Tensorflow / Jax or any other DL/ML framework (someday it may happen to use pure ONNX without OpenCV features in this crate - PR's are welcome);\n* You need to use OpenCV's DNN module to initialize neural network? Use `opencv-backend` feature;\n\n* You want a simple Rust-native solution without heavy dependencies? Use `ort-backend` feature;\n\n_- What about YOLOv5?_\n\nYOLOv5 is supported (05.02.2026 update)! There are two variants:\n\n1. **YOLOv5u** (yolov5nu, yolov5su, etc.) - Ultralytics updated models with YOLOv8-style output (`[1, 84, 8400]`). Use `Model::ort()` or `Model::opencv()` - same as YOLOv8.\n2. **Original YOLOv5** (yolov5n, yolov5s, etc.) - Classic format with objectness score (`[1, 25200, 85]`). Use `Model::yolov5_ort()` or `Model::yolov5_opencv()`.\n\nDownload scripts:\n- YOLOv5u: `scripts/download_v5u_n.sh`, `scripts/download_v5u_s.sh`, etc.\n- Original: `scripts/download_v5_n.sh`, `scripts/download_v5_s.sh`, etc.\n\n_- Why YOLOv10 doesn't work with OpenCV?_\n\nYOLOv10 introduced an \"NMS-free\" architecture where post-processing (TopK selection) is built into the model itself. Unfortunately, OpenCV's DNN module doesn't support the TopK ONNX operator, causing broken inference results. You have two options:\n1. Use YOLOv8/v9/v11 instead (recommended) - they work out of the box\n2. Export YOLOv10 with [patched ultralytics](https://gist.github.com/DarthSim/216551dfd58e5628290e90c1d358704b) that removes built-in NMS, then use `ModelUltralyticsV8` with manual NMS\n\n_- What OpenCV's version is tested for `opencv-backend`?_\n\nI've tested it with v4.11.0 - v4.12.0. Rust bindings version: v0.96.0\n\nFor YOLOv9/v11 support, OpenCV 4.11+ is recommended.\n\n_- Are wrapper structures thread safe?_\n\nI'm not sure it is intended to be used in multiple threads (PR's are welcome). But I think you should use some queue mechanism if you want to give \"async\" acces to provided structs.\n\n## Backends\n\nThis crate supports multiple inference backends:\n\n| Backend | Default | OpenCV Required | GPU Support | Models Supported |\n|---------|---------|-----------------|-------------|------------------|\n| `ort-backend` | Yes | No | CUDA, TensorRT | YOLOv5/v5u/v8/v9/v11 (ONNX), YuNet face detection |\n| `opencv-backend` | No | Yes | CUDA, OpenCL, OpenVINO | All YOLO versions, YuNet face detection |\n| `tensorrt-backend` | No | No | NVIDIA GPU (TensorRT) | YOLOv8/v9/v11 (.engine), YuNet face detection |\n| `rknn-backend` | No | No | Rockchip NPU | YOLOv8/v9/v11 (.rknn), YuNet face detection |\n\n**Warning: CUDA Conflict**\n\nDo not enable both `ort-backend` (or `ort-cuda-backend`) and `opencv-backend` simultaneously when using CUDA acceleration. The CUDA initialization from ORT and OpenCV can conflict, causing segmentation faults at runtime.\n\nAlways use `default-features = false` when enabling `opencv-backend` to disable the default ORT backend.\n\n### Choosing a Backend\n\n```toml\n# Use ORT backend (default) - no OpenCV installation needed\nod_opencv = \"0.6\"\n\n# Use ORT backend with CUDA acceleration\nod_opencv = { version = \"0.6\", features = [\"ort-cuda-backend\"] }\n\n# Use ORT backend with TensorRT acceleration. WARNING: I DID NOT TESTED IT MYSELF!\nod_opencv = { version = \"0.6\", features = [\"ort-tensorrt-backend\"] }\n\n# Use OpenCV backend (required for Darknet models)\nod_opencv = { version = \"0.6\", default-features = false, features = [\"opencv-backend\"] }\n\n# Use TensorRT backend (NVIDIA GPUs, Jetson devices)\nod_opencv = { version = \"0.8\", default-features = false, features = [\"tensorrt-backend\"] }\n\n# Use RKNN backend (Rockchip NPU devices)\nod_opencv = { version = \"0.8\", default-features = false, features = [\"rknn-backend\"] }\n```\n\n## Prerequisites\n\n### For ORT Backend (default)\n\nNo special system dependencies required. The `ort` crate will download ONNX Runtime automatically.\n\nFor GPU acceleration:\n- **CUDA**: Install CUDA toolkit and cuDNN\n- **TensorRT**: Install TensorRT (includes CUDA requirement)\n\n### For OpenCV Backend\n\nFor sure you must have OpenCV installed with DNN extra module. If you need to ulitize power of GPU/OpenVINO then you need to consider to include corresponding extra modules too.\n\nI love to use this [Makefile](https://github.com/hybridgroup/gocv/blob/release/Makefile) with little adjustment (OpenCV's version / enabling python bindings) for my needs.\n\nTested with OpenCV v4.11.0 - v4.12.0. Rust bindings version: v0.96.0\n\n### For TensorRT Backend\n\n- NVIDIA GPU with CUDA support\n- CUDA toolkit with `libcudart`\n- TensorRT (6.x, 8.x, or 10.x) with `libnvinfer`\n- C++ compiler supporting C++14\n\nEngine files must be built from ONNX using `trtexec` on the target machine. Engine files are **not portable** between GPU architectures or TensorRT versions.\n\n```bash\ntrtexec --onnx=yolov8n.onnx --saveEngine=yolov8n.engine --fp16\n```\n\nTested platforms:\n\n| Platform | TensorRT | CUDA | Architecture |\n|---|---|---|---|\n| Jetson Nano (JetPack 4.6) | 8.2 | 10.2 | aarch64 |\n| Desktop (RTX 3060, Arch Linux) | 10.15 | 12.x | x86_64 |\n\nFor non-standard CUDA/TensorRT installation paths, set environment variables `CUDA_HOME`, `CUDA_LIB_DIR`, `TENSORRT_LIB_DIR`. See [tensorrt-infer-sys](https://crates.io/crates/tensorrt-infer-sys) for details.\n\n### Getting Models\n\n* Prepare neural network: train it or get pretrained one. I provide pretty simple Bash scripts to download some versions of YOLO (located in [scripts/](scripts/) folder):\n    * Traditional: YOLO v3 tiny - [download_v3_tiny.sh](scripts/download_v3_tiny.sh); YOLO v3 - [download_v3.sh](scripts/download_v3.sh);\n    * Traditional: YOLO v4 tiny - [download_v4_tiny.sh](scripts/download_v4_tiny.sh); YOLO v4 - [download_v4.sh](scripts/download_v4.sh);\n    * Traditional: YOLO v7 tiny - [download_v7_tiny.sh](scripts/download_v7_tiny.sh); YOLO v7 - [download_v7.sh](scripts/download_v7.sh);\n    * YOLO v5u (Ultralytics updated, YOLOv8 format): [download_v5u_n.sh](scripts/download_v5u_n.sh), [download_v5u_s.sh](scripts/download_v5u_s.sh), [download_v5u_m.sh](scripts/download_v5u_m.sh), [download_v5u_l.sh](scripts/download_v5u_l.sh), [download_v5u_x.sh](scripts/download_v5u_x.sh).\n    * YOLO v5 (original format with objectness): [download_v5_n.sh](scripts/download_v5_n.sh), [download_v5_s.sh](scripts/download_v5_s.sh), [download_v5_m.sh](scripts/download_v5_m.sh), [download_v5_l.sh](scripts/download_v5_l.sh), [download_v5_x.sh](scripts/download_v5_x.sh).\n    * YOLO v8 nano (n) - [download_v8_n.sh](scripts/download_v8_n.sh).\n    * YOLO v8 small (s) - [download_v8_s.sh](scripts/download_v8_s.sh).\n    * YOLO v8 medium (m) - [download_v8_m.sh](scripts/download_v8_m.sh).\n    * YOLO v8 large (l) - [download_v8_l.sh](scripts/download_v8_l.sh).\n    * YOLO v8 extra (x) - [download_v8_x.sh](scripts/download_v8_x.sh).\n    * YOLO v9 tiny (t) - [download_v9_t.sh](scripts/download_v9_t.sh).\n    * YOLO v9 small (s) - [download_v9_s.sh](scripts/download_v9_s.sh).\n    * YOLO v9 medium (m) - [download_v9_m.sh](scripts/download_v9_m.sh).\n    * YOLO v9 compact (c) - [download_v9_c.sh](scripts/download_v9_c.sh).\n    * YOLO v9 extended (e) - [download_v9_e.sh](scripts/download_v9_e.sh).\n    * YOLO v11 nano (n) - [download_v11_n.sh](scripts/download_v11_n.sh).\n    * YOLO v11 small (s) - [download_v11_s.sh](scripts/download_v11_s.sh).\n    * YOLO v11 medium (m) - [download_v11_m.sh](scripts/download_v11_m.sh).\n    * YOLO v11 large (l) - [download_v11_l.sh](scripts/download_v11_l.sh).\n    * YOLO v11 extra (x) - [download_v11_x.sh](scripts/download_v11_x.sh).\n\n    __Notice that \"v5/v5u/v8/v9/v11\" scripts download Pytorch-based weights and convert them into ONNX via `ultralytics` package for Python.__\n    \n## Usage\n\nThere are some [examples](examples), but let me guide you step-by-step.\n\n### Running Examples\n\n```bash\n# ORT backend examples (default)\ncargo run --example yolo_v8_n_ort --release\ncargo run --example yolo_v8_n_ort_cuda --release --features=ort-cuda-backend\n\n# OpenCV backend examples - IMPORTANT: use --no-default-features to avoid CUDA conflicts\ncargo run --example yolo_v4_tiny --release --no-default-features --features=opencv-backend\ncargo run --example yolo_v8_n --release --no-default-features --features=opencv-backend\n\n# Darknet-to-ONNX examples (names contain \"d2o\") - converted via darknet2onnx\ncargo run --example yolo_v4_tiny_d2o_v8_ort --release\ncargo run --example yolo_v4_tiny_d2o_v8_opencv --release --no-default-features --features=opencv-backend\n\n# Face detection (YuNet)\ncargo run --example yunet_ort --release\ncargo run --example yunet_opencv --release --no-default-features --features=opencv-backend\ncargo run --example yunet_tensorrt --release --no-default-features --features=tensorrt-backend\ncargo run --example yunet_rknn --release --no-default-features --features=rknn-backend\n```\n\n\u003e **Note:** Examples with `d2o` in the name use ONNX models converted from Darknet `.cfg` + `.weights` via [darknet2onnx]. The suffix `v8` or `v5` indicates the output format used during conversion (`--format yolov8` or `--format yolov5`).\n\n\u003e **Note:** When running OpenCV backend examples, always use `--no-default-features` to disable the ORT backend. Without this flag, both backends will be loaded which can cause segmentation faults when using CUDA\n\n### ORT Backend (Default)\n\nThe ORT backend uses ONNX Runtime and doesn't require OpenCV. This is the recommended approach for YOLOv8/v9/v11 models.\n\n1. Add this crate to your's `Cargo.toml`:\n    ```shell\n    cargo add od_opencv\n    ```\n\n2. Download pretrained or use your own neural network.\n\n    I will use pretrained weights from [prerequisites section](#getting-models)\n\n3. Import crate in yours `main.rs` file:\n\n    ```rust\n    use od_opencv::{\n        ImageBuffer,\n        backend_ort::ModelUltralyticsOrt,\n    };\n    ```\n\n4. Prepare model\n\n    ```rust\n    // Initialize ORT runtime\n    ort::init().commit().expect(\"Failed to initialize ORT\");\n\n    // Define classes (in this case we consider 80 COCO labels)\n    let classes_labels: Vec\u003c\u0026str\u003e = vec![\"person\", \"bicycle\", \"car\", \"motorbike\", \"aeroplane\", \"bus\", \"train\", \"truck\", \"boat\", \"traffic light\", \"fire hydrant\", \"stop sign\", \"parking meter\", \"bench\", \"bird\", \"cat\", \"dog\", \"horse\", \"sheep\", \"cow\", \"elephant\", \"bear\", \"zebra\", \"giraffe\", \"backpack\", \"umbrella\", \"handbag\", \"tie\", \"suitcase\", \"frisbee\", \"skis\", \"snowboard\", \"sports ball\", \"kite\", \"baseball bat\", \"baseball glove\", \"skateboard\", \"surfboard\", \"tennis racket\", \"bottle\", \"wine glass\", \"cup\", \"fork\", \"knife\", \"spoon\", \"bowl\", \"banana\", \"apple\", \"sandwich\", \"orange\", \"broccoli\", \"carrot\", \"hot dog\", \"pizza\", \"donut\", \"cake\", \"chair\", \"sofa\", \"pottedplant\", \"bed\", \"diningtable\", \"toilet\", \"tvmonitor\", \"laptop\", \"mouse\", \"remote\", \"keyboard\", \"cell phone\", \"microwave\", \"oven\", \"toaster\", \"sink\", \"refrigerator\", \"book\", \"clock\", \"vase\", \"scissors\", \"teddy bear\", \"hair drier\", \"toothbrush\"];\n\n    // Define model's input size\n    let net_width = 640;\n    let net_height = 640;\n\n    // Initialize optional filters.\n    // E.g.: if you do want to find only dogs and cats and you can't re-train neural network,\n    // then you can just place `vec![15, 16]` to filter dogs and cats (15 - index of `cat` in class labels, 16 - `dog`)\n    // let class_filters: Vec\u003cusize\u003e = vec![15, 16];\n    let class_filters: Vec\u003cusize\u003e = vec![];\n\n    // Initialize model itself\n    let mut model = ModelUltralyticsOrt::new_from_file(\n        \"pretrained/yolov8s.onnx\",\n        (net_width, net_height),\n        class_filters,\n    ).expect(\"Failed to load model\");\n\n    // Load image using the `image` crate\n    let img = image::open(\"images/dog.jpg\").expect(\"Failed to load image\");\n    let img_buffer = ImageBuffer::from_dynamic_image(img);\n\n    // Feed forward image through the model\n    let (bboxes, class_ids, confidences) = model.forward(\n        \u0026img_buffer,\n        0.25,  // confidence threshold\n        0.4,   // NMS threshold\n    ).expect(\"Inference failed\");\n\n    // Process results\n    for (i, bbox) in bboxes.iter().enumerate() {\n        // Debug output to stdin\n        println!(\"Class: {}\", classes_labels[class_ids[i]]);\n        println!(\"\\tBBox: x={}, y={}, w={}, h={}\", bbox.x, bbox.y, bbox.width, bbox.height);\n        println!(\"\\tConfidence: {:.2}\", confidences[i]);\n    }\n    ```\n\n5. You are good to go\n    ```shell\n    cargo run\n    ```\n\n6. If anything is going wrong, feel free to [open an issue](https://github.com/LdDl/object-detection-opencv-rust/issues/new)\n\n#### ORT with CUDA\n\nIf you want to use CUDA acceleration, change your `Cargo.toml`:\n\n```toml\n[dependencies]\nod_opencv = { version = \"0.6\", features = [\"ort-cuda-backend\"] }\n```\n\nAnd use `new_from_file_cuda` instead of `new_from_file`:\n\n```rust\nlet mut model = ModelUltralyticsOrt::new_from_file_cuda(\n    \"pretrained/yolov8s.onnx\",\n    (net_width, net_height),\n    class_filters,\n).expect(\"Failed to load model\");\n```\n\n#### ORT with OpenCV I/O\n\nIf you need OpenCV for video capture or image I/O but want ORT for inference, use the `ort-opencv-compat` feature:\n\n```toml\nod_opencv = { version = \"0.6\", features = [\"ort-opencv-compat\"] }\n```\n\nThis enables `ModelTrait` which accepts `opencv::core::Mat` directly:\n\n```rust\nuse od_opencv::{Model, ModelTrait};\nuse opencv::imgcodecs;\n\nlet mut model = Model::ort(\"model.onnx\", (640, 640))?;\nlet img = imgcodecs::imread(\"image.jpg\", imgcodecs::IMREAD_COLOR)?;\nlet (bboxes, class_ids, confidences) = ModelTrait::forward(\u0026mut model, \u0026img, 0.25, 0.4)?;\n```\n\nSee full example here: [examples/yolo_v8_s_ort_opencv.rs](examples/yolo_v8_s_ort_opencv.rs)\n\n### OpenCV Backend\n\nThe OpenCV backend is required for Darknet models (v3/v4/v7) and provides access to highly optimized OpenCV's things for preprocessing and postprocessing.\n\n1. Add this crate to your's `Cargo.toml`:\n    ```shell\n    cargo add od_opencv --no-default-features --features opencv-backend\n    ```\n\n2. Add OpenCV's bindings crate to `Cargo.toml` also:\n    ```shell\n    # I'm using 0.96 version\n    cargo add opencv@0.96\n    ```\n\n3. Download pretrained or use your own neural network.\n\n    I will use pretrained weights from [prerequisites section](#getting-models)\n\n4. Import \"basic\" OpenCV stuff in yours `main.rs` file:\n\n    ```rust\n    use opencv::{\n        core::{Scalar, Vector},\n        imgcodecs::imread,\n        imgcodecs::imwrite,\n        imgproc::LINE_4,\n        imgproc::rectangle,\n    };\n    ```\n\n5. Import crate (choose one approach):\n\n    **Option A: Factory pattern (recommended)**\n    ```rust\n    use od_opencv::{\n        Model,\n        DnnBackend, // I will utilize my GPU to perform faster inference. Your way may vary\n        DnnTarget\n    };\n    ```\n\n    **Option B: Direct struct access**\n    ```rust\n    use od_opencv::{\n        model_format::ModelFormat,\n        // I'll use YOLOv8 by Ultralytics.\n        // If you prefer traditional YOLO, then import it as:\n        // model_classic::ModelYOLOClassic\n        model_ultralytics::ModelUltralyticsV8\n    };\n    use opencv::dnn::{\n        DNN_BACKEND_CUDA, // I will utilize my GPU to perform faster inference. Your way may vary\n        DNN_TARGET_CUDA\n    };\n    ```\n\n6. Prepare model\n\n    **Option A: Factory pattern (recommended)**\n    ```rust\n    // Define classes (in this case we consider 80 COCO labels)\n    let classes_labels: Vec\u003c\u0026str\u003e = vec![\"person\", \"bicycle\", \"car\", \"motorbike\", \"aeroplane\", \"bus\", \"train\", \"truck\", \"boat\", \"traffic light\", \"fire hydrant\", \"stop sign\", \"parking meter\", \"bench\", \"bird\", \"cat\", \"dog\", \"horse\", \"sheep\", \"cow\", \"elephant\", \"bear\", \"zebra\", \"giraffe\", \"backpack\", \"umbrella\", \"handbag\", \"tie\", \"suitcase\", \"frisbee\", \"skis\", \"snowboard\", \"sports ball\", \"kite\", \"baseball bat\", \"baseball glove\", \"skateboard\", \"surfboard\", \"tennis racket\", \"bottle\", \"wine glass\", \"cup\", \"fork\", \"knife\", \"spoon\", \"bowl\", \"banana\", \"apple\", \"sandwich\", \"orange\", \"broccoli\", \"carrot\", \"hot dog\", \"pizza\", \"donut\", \"cake\", \"chair\", \"sofa\", \"pottedplant\", \"bed\", \"diningtable\", \"toilet\", \"tvmonitor\", \"laptop\", \"mouse\", \"remote\", \"keyboard\", \"cell phone\", \"microwave\", \"oven\", \"toaster\", \"sink\", \"refrigerator\", \"book\", \"clock\", \"vase\", \"scissors\", \"teddy bear\", \"hair drier\", \"toothbrush\"];\n\n    // Initialize model using factory pattern\n    let mut model = Model::opencv(\n        \"pretrained/yolov8n.onnx\",\n        (640, 640),\n        DnnBackend::Cuda,\n        DnnTarget::Cuda,\n    ).unwrap();\n\n    // Read image into the OpenCV's Mat object\n    let mut frame = imread(\"images/dog.jpg\", 1).unwrap();\n\n    // Feed forward image through the model\n    let (bboxes, class_ids, confidences) = model.forward(\u0026frame, 0.25, 0.4).unwrap();\n\n    // Process results\n    for (i, bbox) in bboxes.iter().enumerate() {\n        rectangle(\u0026mut frame, *bbox, Scalar::from((0.0, 255.0, 0.0)), 2, LINE_4, 0).unwrap();\n        println!(\"Class: {}\", classes_labels[class_ids[i]]);\n        println!(\"\\tBounding box: {:?}\", bbox);\n        println!(\"\\tConfidences: {}\", confidences[i]);\n    }\n\n    imwrite(\"images/dog_yolov8_n.jpg\", \u0026frame, \u0026Vector::new()).unwrap();\n    ```\n\n    **Option B: Direct struct access**\n    ```rust\n    // Define classes (in this case we consider 80 COCO labels)\n    let classes_labels: Vec\u003c\u0026str\u003e = vec![\"person\", \"bicycle\", \"car\", \"motorbike\", \"aeroplane\", \"bus\", \"train\", \"truck\", \"boat\", \"traffic light\", \"fire hydrant\", \"stop sign\", \"parking meter\", \"bench\", \"bird\", \"cat\", \"dog\", \"horse\", \"sheep\", \"cow\", \"elephant\", \"bear\", \"zebra\", \"giraffe\", \"backpack\", \"umbrella\", \"handbag\", \"tie\", \"suitcase\", \"frisbee\", \"skis\", \"snowboard\", \"sports ball\", \"kite\", \"baseball bat\", \"baseball glove\", \"skateboard\", \"surfboard\", \"tennis racket\", \"bottle\", \"wine glass\", \"cup\", \"fork\", \"knife\", \"spoon\", \"bowl\", \"banana\", \"apple\", \"sandwich\", \"orange\", \"broccoli\", \"carrot\", \"hot dog\", \"pizza\", \"donut\", \"cake\", \"chair\", \"sofa\", \"pottedplant\", \"bed\", \"diningtable\", \"toilet\", \"tvmonitor\", \"laptop\", \"mouse\", \"remote\", \"keyboard\", \"cell phone\", \"microwave\", \"oven\", \"toaster\", \"sink\", \"refrigerator\", \"book\", \"clock\", \"vase\", \"scissors\", \"teddy bear\", \"hair drier\", \"toothbrush\"];\n\n    // Define format for OpenCV's DNN module\n    let mf = ModelFormat::ONNX;\n\n    // Define model's input size\n    let net_width = 640;\n    let net_height = 640;\n\n    // Initialize optional filters.\n    // E.g.: if you do want to find only dogs and cats and you can't re-train neural network,\n    // then you can just place `vec![15, 16]` to filter dogs and cats (15 - index of `cat` in class labels, 16 - `dog`)\n    // let class_filters: Vec\u003cusize\u003e = vec![15, 16];\n    let class_filters: Vec\u003cusize\u003e = vec![];\n\n    // Initialize model itself\n    let mut model = ModelUltralyticsV8::new_from_file(\"pretrained/yolov8n.onnx\", None, (net_width, net_height), mf, DNN_BACKEND_CUDA, DNN_TARGET_CUDA, class_filters).unwrap();\n\n    // Read image into the OpenCV's Mat object\n    // Define it as mutable since we are going to put bounding boxes onto it.\n    let mut frame = imread(\"images/dog.jpg\", 1).unwrap();\n\n    // Feed forward image through the model\n    let (bboxes, class_ids, confidences) = model.forward(\u0026frame, 0.25, 0.4).unwrap();\n\n    // Process results\n    for (i, bbox) in bboxes.iter().enumerate() {\n        // Place bounding boxes onto the image\n        rectangle(\u0026mut frame, *bbox, Scalar::from((0.0, 255.0, 0.0)), 2, LINE_4, 0).unwrap();\n        // Debug output to stdin\n        println!(\"Class: {}\", classes_labels[class_ids[i]]);\n        println!(\"\\tBounding box: {:?}\", bbox);\n        println!(\"\\tConfidences: {}\", confidences[i]);\n    }\n\n    // Finally save the updated image to the file system\n    imwrite(\"images/dog_yolov8_n.jpg\", \u0026frame, \u0026Vector::new()).unwrap();\n    ```\n\n7. You are good to go\n    ```shell\n    cargo run --no-default-features --features=opencv-backend\n    ```\n\n8. If anything is going wrong, feel free to [open an issue](https://github.com/LdDl/object-detection-opencv-rust/issues/new)\n\n### TensorRT Backend\n\nThe TensorRT backend runs inference directly on NVIDIA GPUs via [tensorrt-infer](https://crates.io/crates/tensorrt-infer). It supports TensorRT 6-8 (Jetson Nano with JetPack 4.6) and TensorRT 10+ (desktop GPUs). The C++ wrapper handles API differences at compile time.\n\n1. Build an engine file from ONNX on the target machine:\n    ```bash\n    trtexec --onnx=pretrained/yolov8n.onnx --saveEngine=pretrained/yolov8n.engine --fp16\n    ```\n\n2. Add to `Cargo.toml`:\n    ```toml\n    [dependencies]\n    od_opencv = { version = \"0.8\", default-features = false, features = [\"tensorrt-backend\"] }\n    image = \"0.25\"\n    ```\n\n3. Use the model:\n\n    **Option A: Factory pattern**\n    ```rust\n    use od_opencv::{ImageBuffer, Model};\n\n    let mut model = Model::tensorrt(\"pretrained/yolov8n.engine\")\n        .expect(\"Failed to load engine\");\n\n    let img = image::open(\"images/dog.jpg\").expect(\"Failed to load image\");\n    let img_buffer = ImageBuffer::from_dynamic_image(img);\n\n    let (bboxes, class_ids, confidences) = model.forward(\u0026img_buffer, 0.25, 0.4)\n        .expect(\"Inference failed\");\n    ```\n\n    **Option B: Direct struct access**\n    ```rust\n    use od_opencv::{ImageBuffer, backend_tensorrt::ModelUltralyticsRt};\n\n    let mut model = ModelUltralyticsRt::new_from_file(\n        \"pretrained/yolov8n.engine\",\n        vec![],   // class_filters (empty = all classes)\n    ).expect(\"Failed to load engine\");\n\n    let img = image::open(\"images/dog.jpg\").expect(\"Failed to load image\");\n    let img_buffer = ImageBuffer::from_dynamic_image(img);\n\n    let (bboxes, class_ids, confidences) = model.forward(\u0026img_buffer, 0.25, 0.4)\n        .expect(\"Inference failed\");\n    ```\n\n4. Run:\n    ```bash\n    cargo run --example yolo_v8_n_tensorrt --no-default-features --features tensorrt-backend --release\n    ```\n\n**Note:** Engine files are tied to the specific GPU architecture and TensorRT version. You must rebuild the `.engine` file on each target machine. Input dimensions are read directly from the engine bindings, so there is no need to pass them manually.\n\n#### TensorRT with OpenCV I/O\n\nIf you need OpenCV for video capture or image I/O but want TensorRT for inference, use the `tensorrt-opencv-compat` feature:\n\n```toml\nod_opencv = { version = \"0.8\", default-features = false, features = [\"tensorrt-opencv-compat\"] }\n```\n\nThis enables `ModelTrait` which accepts `opencv::core::Mat` directly:\n\n```rust\nuse od_opencv::{Model, ModelTrait};\nuse opencv::imgcodecs;\n\nlet mut model = Model::tensorrt(\"pretrained/yolov8n.engine\")?;\nlet img = imgcodecs::imread(\"image.jpg\", imgcodecs::IMREAD_COLOR)?;\nlet (bboxes, class_ids, confidences) = ModelTrait::forward(\u0026mut model, \u0026img, 0.25, 0.4)?;\n```\n\nSee full example here: [examples/yolo_v8_n_tensorrt_opencv.rs](examples/yolo_v8_n_tensorrt_opencv.rs)\n\n### RKNN Backend\n\nThe RKNN backend runs inference on Rockchip NPU using the [rknn-runtime](https://github.com/LdDl/rknn-runtime) crate. Tested on LuckFox Pico Ultra W (RV1106) with a COCO 320x320 model. For that specific size I've converted ONNX model to `.rknn` (with some preparations also) format via recommendations here: [rv1106-yolov8](https://github.com/LdDl/rv1106-yolov8).\n\n1. Add to `Cargo.toml`:\n    ```toml\n    [dependencies]\n    od_opencv = { version = \"0.6\", default-features = false, features = [\"rknn-backend\"] }\n    image = \"0.25\"\n    ```\n\n    **Note:** Use `default-features = false` to avoid pulling in ORT dependencies during cross-compilation.\n\n2. Use the model:\n\n    **Option A: Factory pattern**\n    ```rust\n    use od_opencv::{ImageBuffer, Model};\n\n    let mut model = Model::rknn(\"yolov8n.rknn\", 80).expect(\"Failed to load model\");\n\n    let img = image::open(\"image.jpg\").expect(\"Failed to load image\");\n    let img_buffer = ImageBuffer::from_dynamic_image(img);\n\n    let (bboxes, class_ids, confidences) = model.forward(\u0026img_buffer, 0.51, 0.45)\n        .expect(\"Inference failed\");\n    ```\n\n    **Option B: Direct struct access**\n    ```rust\n    use od_opencv::{ImageBuffer, ModelUltralyticsRknn};\n\n    let mut model = ModelUltralyticsRknn::new_from_file(\n        \"yolov8n.rknn\",\n        80,       // num_classes\n        vec![],   // class_filters (empty = all classes)\n    ).expect(\"Failed to load model\");\n\n    let img = image::open(\"image.jpg\").expect(\"Failed to load image\");\n    let img_buffer = ImageBuffer::from_dynamic_image(img);\n\n    let (bboxes, class_ids, confidences) = model.forward(\u0026img_buffer, 0.51, 0.45)\n        .expect(\"Inference failed\");\n    ```\n\n    Input size is auto-detected from the model (no need to specify it manually).\n\n    If `librknnmrt.so` is not at the default path (`/usr/lib/librknnmrt.so`), use `new_with_lib`:\n    ```rust\n    let mut model = ModelUltralyticsRknn::new_with_lib(\n        \"yolov8n.rknn\",\n        \"/opt/rknn/lib/librknnmrt.so\",\n        80,\n        vec![],\n    ).expect(\"Failed to load model\");\n    ```\n\n    **Note on confidence threshold:** INT8 quantization causes `sigmoid(0) = 0.5` to dequantize to ~0.502. Use a threshold \u003e 0.502 (e.g. `0.51` literally) to avoid false positives from zero-initialized outputs.\n\n    **Warning:** The RKNN backend uses `unsafe` code extensively - raw pointer arithmetic for nearest-neighbor resize, `get_unchecked` for NC1HWC2 tensor access, and FFI calls to `librknnmrt.so` via `rknn-runtime`. Use at your own risk.\n\n3. Cross-compile and deploy:\n    ```bash\n    cross build --target armv7-unknown-linux-gnueabihf --release \\\n        --example yolo_v8_n_rknn --no-default-features --features rknn-backend\n    scp target/armv7-unknown-linux-gnueabihf/release/examples/yolo_v8_n_rknn user@device:~/\n    ```\n\n### Face Detection (YuNet)\n\nThis crate supports face detection using [YuNet](https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet) from OpenCV Zoo. YuNet is an extremely lightweight model (0.083M params, 228KB ONNX) that detects faces and returns 5 facial landmarks (eyes, nose, mouth corners).\n\nThe model is available for ORT, OpenCV, TensorRT, and RKNN backends. For ORT/TensorRT/RKNN, input dimensions are read from the model automatically and decoding is implemented in pure Rust.\n\nThe OpenCV backend is a wrapper around OpenCV's built-in `FaceDetectorYN` (requires OpenCV 4.7+), which handles preprocessing, inference, decoding and NMS internally.\n\n**Compatible weights** (same 12-tensor output format, no code changes needed):\n\n| Source | File | Input | Size |\n|--------|------|-------|------|\n| [OpenCV Zoo](https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet) | `face_detection_yunet_2023mar.onnx` | 640×640 | 228 KB |\n| [libfacedetection.train](https://github.com/ShiqiYu/libfacedetection.train/tree/master/onnx) | `yunet_n_640_640.onnx` | 640×640 | 311 KB |\n| [libfacedetection.train](https://github.com/ShiqiYu/libfacedetection.train/tree/master/onnx) | `yunet_n_320_320.onnx` | 320×320 | 311 KB |\n\nDownload weights:\n```bash\n# OpenCV Zoo (228 KB, 53K params)\nwget -O pretrained/face_detection_yunet_2023mar.onnx \\\n  https://github.com/opencv/opencv_zoo/raw/main/models/face_detection_yunet/face_detection_yunet_2023mar.onnx\n\n# libfacedetection.train (311 KB, 74K params) - 640x640\nwget -O pretrained/yunet_n_640_640.onnx \\\n  https://github.com/ShiqiYu/libfacedetection.train/raw/master/onnx/yunet_n_640_640.onnx\n\n# libfacedetection.train (311 KB, 74K params) - 320x320\nwget -O pretrained/yunet_n_320_320.onnx \\\n  https://github.com/ShiqiYu/libfacedetection.train/raw/master/onnx/yunet_n_320_320.onnx\n```\n\nFor TensorRT, convert the ONNX model:\n```bash\ntrtexec --onnx=pretrained/face_detection_yunet_2023mar.onnx \\\n  --saveEngine=pretrained/face_detection_yunet_2023mar.engine --fp16\n```\n\nFor RKNN, convert via [rv1106-yunet](https://github.com/LdDl/rv1106-yunet):\n```bash\n# There is a script to download WIDER face dataset in that repo, but you can also use your own calibration images\npython onnx_to_rknn.py face_detection_yunet_2023mar.onnx --dataset calibration_images/\n```\n\nCross-compile and deploy to device:\n```bash\ncross build --target armv7-unknown-linux-gnueabihf --release \\\n    --example yunet_rknn --no-default-features --features rknn-backend\nscp target/armv7-unknown-linux-gnueabihf/release/examples/yunet_rknn user@device:~/\n```\n\n**Usage (ORT backend):**\n```rust\nuse od_opencv::{ImageBuffer, Model, FaceDetection};\n\nort::init().commit();\n\nlet mut model = Model::yunet_ort(\"pretrained/face_detection_yunet_2023mar.onnx\")\n    .expect(\"Failed to load YuNet model\");\n\nlet img = image::open(\"image.jpg\").expect(\"Failed to load image\");\nlet img_buffer = ImageBuffer::from_dynamic_image(img);\n\nlet detections = model.forward(\u0026img_buffer, 0.7, 0.3)\n    .expect(\"Inference failed\");\n\nfor det in \u0026detections {\n    println!(\"Face: confidence={:.3}, bbox=({:.1},{:.1},{:.1},{:.1})\",\n        det.confidence, det.x, det.y, det.width, det.height);\n    let names = [\"right_eye\", \"left_eye\", \"nose\", \"right_mouth\", \"left_mouth\"];\n    for (j, name) in names.iter().enumerate() {\n        println!(\"  {}: ({:.1}, {:.1})\", name, det.landmarks[j][0], det.landmarks[j][1]);\n    }\n}\n```\n\n**Usage (TensorRT backend):**\n```rust\nuse od_opencv::{ImageBuffer, Model};\n\nlet mut model = Model::yunet_tensorrt(\"pretrained/face_detection_yunet_2023mar.engine\")\n    .expect(\"Failed to load engine\");\n\nlet img = image::open(\"image.jpg\").expect(\"Failed to load image\");\nlet img_buffer = ImageBuffer::from_dynamic_image(img);\n\nlet detections = model.forward(\u0026img_buffer, 0.7, 0.3)\n    .expect(\"Inference failed\");\n```\n\n**Usage (OpenCV backend):**\n```rust\nuse od_opencv::{Model, DnnBackend, DnnTarget};\n\nlet mut model = Model::yunet_opencv(\n    \"pretrained/face_detection_yunet_2023mar.onnx\",\n    (320, 320),\n    DnnBackend::OpenCV,\n    DnnTarget::Cpu,\n)?;\n\nlet frame = opencv::imgcodecs::imread(\"image.jpg\", 1)?;\nlet detections = model.forward(\u0026frame, 0.7, 0.3)?;\n```\n\n**Usage (RKNN backend):**\n```rust\nuse od_opencv::{ImageBuffer, Model};\n\nlet mut model = Model::yunet_rknn(\"pretrained/face_detection_yunet_2023mar.rknn\")\n    .expect(\"Failed to load RKNN model\");\n\nlet img = image::open(\"image.jpg\").expect(\"Failed to load image\");\nlet img_buffer = ImageBuffer::from_dynamic_image(img);\n\nlet detections = model.forward(\u0026img_buffer, 0.7, 0.3)\n    .expect(\"Inference failed\");\n```\n\nSee full examples: [examples/yunet_ort.rs](examples/yunet_ort.rs), [examples/yunet_opencv.rs](examples/yunet_opencv.rs), [examples/yunet_tensorrt.rs](examples/yunet_tensorrt.rs), [examples/yunet_rknn.rs](examples/yunet_rknn.rs)\n\n## Features\n\n### Letterbox Preprocessing\n\nFor non-traditional YOLO models (v8/v9/v11), you can enable letterbox preprocessing which maintains aspect ratio during resize and pads with gray borders. This matches the preprocessing used during Ultralytics training.\n\nThis works for ORT, OpenCV, and TensorRT backends.\n\n```toml\n# ORT backend with letterbox\nod_opencv = { version = \"0.6\", features = [\"letterbox\"] }\n\n# OpenCV backend with letterbox\nod_opencv = { version = \"0.6\", default-features = false, features = [\"opencv-backend\", \"letterbox\"] }\n```\n\n**Without letterbox (default):** Images are stretched to the network input size. This may introduce aspect ratio distortion.\n\n**With letterbox:** Images are resized maintaining aspect ratio, then padded to the target size. This preserves the original aspect ratio and can be faster due to optimized buffer reuse.\n\n## Migration from 0.3.x\n\nIn version 0.4.0, the default backend changed from OpenCV to ORT:\n\n| Version | Default Backend | OpenCV Required |\n|---------|-----------------|-----------------|\n| 0.3.x   | opencv (implicit) | Yes |\n| 0.4.x   | ort-backend | No |\n\n**To keep using OpenCV backend after upgrading:**\n\n```toml\n# Before (0.3.x)\nod_opencv = \"0.3\"\n\n# After (0.4.x) - explicitly enable opencv-backend\nod_opencv = { version = \"0.4\", default-features = false, features = [\"opencv-backend\"] }\n```\n\nYour existing code using `ModelUltralyticsV8`, `ModelYOLOClassic`, etc. will continue to work unchanged with the `opencv-backend` feature.\n\n## References\n* YOLO v3 paper - https://arxiv.org/abs/1804.02767, Joseph Redmon, Ali Farhadi\n* YOLO v4 paper - https://arxiv.org/abs/2004.10934, Alexey Bochkovskiy, Chien-Yao Wang, Hong-Yuan Mark Liao\n* YOLO v7 paper - https://arxiv.org/abs/2207.02696, Chien-Yao Wang, Alexey Bochkovskiy, Hong-Yuan Mark Liao\n* YOLO v9 paper - https://arxiv.org/abs/2402.13616, Chien-Yao Wang, I-Hau Yeh, Hong-Yuan Mark Liao\n* YOLO v10 paper - https://arxiv.org/abs/2405.14458, Ao Wang, Hui Chen, Lihao Liu, Kai Chen, Zijia Lin, Jungong Han, Guiguang Ding\n* YuNet face detection paper - https://link.springer.com/article/10.1007/s11633-023-1423-y, Shiqi Yu, Yuanbo Xia, et al.\n* YuNet training repository (libfacedetection) - https://github.com/ShiqiYu/libfacedetection.train\n* YuNet pretrained weights (OpenCV Zoo) - https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet\n* Original Darknet YOLO repository - https://github.com/pjreddie/darknet\n* Most popular fork of Darknet YOLO - https://github.com/AlexeyAB/darknet\n* Developers of YOLOv8/v11 - https://github.com/ultralytics/ultralytics\n* ONNX Runtime - https://onnxruntime.ai/\n\n* Darknet to ONNX converter (Go CLI) - https://github.com/LdDl/darknet2onnx\n* Rust OpenCV's bindings - https://github.com/twistedfall/opencv-rust\n* Go OpenCV's bindings (for ready-to-go Makefile) - https://github.com/hybridgroup/gocv\n* RKNN Runtime (Rust bindings for Rockchip NPU) - https://github.com/LdDl/rknn-runtime\n* ONNX to RKNN conversion for RV1106 - https://github.com/LdDl/rv1106-yolov8\n* TensorRT safe Rust wrappers - https://github.com/LdDl/tensorrt-infer\n* TensorRT FFI bindings - https://github.com/LdDl/tensorrt-infer-sys\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flddl%2Fobject-detection-opencv-rust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flddl%2Fobject-detection-opencv-rust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flddl%2Fobject-detection-opencv-rust/lists"}