Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions samples/linux/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ The following table lists all available sample models with descriptions and exec
| wideresnet50 | WideResNet50 image classification | `python wideresnet50/wideresnet50.py` |
| xlsr | XLSR super-resolution | `python xlsr/xlsr.py` |
| yolov8_det | YOLOv8 object detection | `python yolov8_det/yolov8_det.py` |
| yolo26n_det | YOLO26n object detection | `python yolov26n_det/yolo26n_det.py` |

> **Note:** Ensure you are in the `samples/linux/python` directory before running any example. Each sample will automatically download its required model on first run.

Expand Down
59 changes: 59 additions & 0 deletions samples/linux/python/yolo26n_det/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# yolo26n_det Sample Code

## Introduction
This is sample code for using AppBuilder to load yolo26n_det QNN model to HTP and execute inference to predicts bounding boxes and classes of objects in an image. The yolo26n_det.py file corresponds to the qai_appbuilder version. Additionly, we provide both the ultralytics version and onnxruntime version scripts. The ultralytics version script can be used to export an .onnx model.

## How to get the QNN format model
### 1. Export .onnx format model using ultralytics version script
```bash
python ultralytics_version.py
```

### 2. Set QNN related Environment Variables:
```bash
export QNN_SDK_ROOT=<path_to_your_qnn_sdk_root>
export LD_LIBRARY_PATH=$QNN_SDK_ROOT/lib/aarch64-oe-linux-gcc11.2:$LD_LIBRARY_PATH
export PYTHONPATH=${QNN_SDK_ROOT}/lib/python
export PATH=${QNN_SDK_ROOT}/bin/x86_64-linux-clang/:$PATH
export CPLUS_INCLUDE_PATH=/usr/include/c++/9:/usr/include/x86_64-linux-gnu/c++/9
export LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9
```

### 3. Model Conversion
```bash
$QNN_SDK_ROOT/bin/x86_64-linux-clang/qnn-onnx-converter \
-i ./yolo26n.onnx \
--preserve_io layout \
--preserve_io datatype \
--output_path ./yolo26n.cpp
```

### 4. Model Lib Generation
```bash
$QNN_SDK_ROOT/bin/x86_64-linux-clang/qnn-model-lib-generator \
-c ./yolo26n.cpp \
-b ./yolo26n.bin \
-t aarch64-oe-linux-gcc11.2 \
-o ./
```
At this stage, a .so model library is generated. This library can be used on both the QNN CPU and HTP backends.

### 5. Context Binary Generation
```bash
$QNN_SDK_ROOT/bin/x86_64-linux-clang/qnn-context-binary-generator \
--model ./x86_64-linux-clang/libyolo26n.so \
--soc_model 77 \
--backend ${QNN_SDK_ROOT}/lib/x86_64-linux-clang/libQnnHtp.so \
--binary_file cntx_yolo26n_soc77_fp16
```
At this stage, a context binary (.bin) is generated, which can only be used on the HTP backend.

For more information, please refer to the QAIRT SDK documentation.

## Notes
- When running the `yolo26n_det/yolo26n_det.py` script, make sure to replace the `model_path` with your own model path generated in the previous step.

## References
[1] https://docs.qualcomm.com/nav/home/general_tools.html?product=1601111740009302

[2] https://docs.ultralytics.com/models/yolo26/
Binary file added samples/linux/python/yolo26n_det/input.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
184 changes: 184 additions & 0 deletions samples/linux/python/yolo26n_det/onnxruntime_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import argparse

import cv2
import numpy as np
import onnxruntime as ort


IMAGE_SIZE = 640 # model expects [1,3,640,640]

# define class type (COCO 80)
class_map = {
0: "person",
1: "bicycle",
2: "car",
3: "motorcycle",
4: "airplane",
5: "bus",
6: "train",
7: "truck",
8: "boat",
9: "traffic light",
10: "fire hydrant",
11: "stop sign",
12: "parking meter",
13: "bench",
14: "bird",
15: "cat",
16: "dog",
17: "horse",
18: "sheep",
19: "cow",
20: "elephant",
21: "bear",
22: "zebra",
23: "giraffe",
24: "backpack",
25: "umbrella",
26: "handbag",
27: "tie",
28: "suitcase",
29: "frisbee",
30: "skis",
31: "snowboard",
32: "sports ball",
33: "kite",
34: "baseball bat",
35: "baseball glove",
36: "skateboard",
37: "surfboard",
38: "tennis racket",
39: "bottle",
40: "wine glass",
41: "cup",
42: "fork",
43: "knife",
44: "spoon",
45: "bowl",
46: "banana",
47: "apple",
48: "sandwich",
49: "orange",
50: "broccoli",
51: "carrot",
52: "hot dog",
53: "pizza",
54: "donut",
55: "cake",
56: "chair",
57: "couch",
58: "potted plant",
59: "bed",
60: "dining table",
61: "toilet",
62: "tv",
63: "laptop",
64: "mouse",
65: "remote",
66: "keyboard",
67: "cell phone",
68: "microwave",
69: "oven",
70: "toaster",
71: "sink",
72: "refrigerator",
73: "book",
74: "clock",
75: "vase",
76: "scissors",
77: "teddy bear",
78: "hair drier",
79: "toothbrush"
}


def _select_providers() -> list[str]:
available = ort.get_available_providers()
preferred = ["CUDAExecutionProvider", "CPUExecutionProvider"]
return [p for p in preferred if p in available] or available


def _load_image(image_path: str) -> tuple[np.ndarray, np.ndarray]:
img0 = cv2.imread(image_path)
if img0 is None:
raise FileNotFoundError(f"Failed to read image: {image_path}")

img = cv2.resize(img0, (IMAGE_SIZE, IMAGE_SIZE), interpolation=cv2.INTER_LINEAR)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = img.astype(np.float32) / 255.0
img = np.transpose(img, (2, 0, 1))[None] # NCHW
return img0, img


def _draw_xyxy(
frame_bgr: np.ndarray,
xyxy_640: np.ndarray,
score: float,
class_id: int,
color: tuple[int, int, int] = (0, 255, 0),
thickness: int = 2,
) -> None:
h, w = frame_bgr.shape[:2]
scale_x = w / IMAGE_SIZE
scale_y = h / IMAGE_SIZE

x1, y1, x2, y2 = xyxy_640.tolist()
x1 = int(max(0.0, min(IMAGE_SIZE, x1)) * scale_x)
y1 = int(max(0.0, min(IMAGE_SIZE, y1)) * scale_y)
x2 = int(max(0.0, min(IMAGE_SIZE, x2)) * scale_x)
y2 = int(max(0.0, min(IMAGE_SIZE, y2)) * scale_y)

cv2.rectangle(frame_bgr, (x1, y1), (x2, y2), color, thickness)
class_name = class_map.get(class_id, "Unknown")
label = f"{score:.2f} {class_name}"
cv2.putText(
frame_bgr,
label,
(x1, max(0, y1 - 8)),
cv2.FONT_HERSHEY_SIMPLEX,
0.6,
color,
2,
cv2.LINE_AA,
)


def main() -> int:
parser = argparse.ArgumentParser(description="YOLO26 ONNXRuntime inference (no NMS).")
parser.add_argument("--model", default="yolo26n.onnx", help="Path to YOLO26 ONNX model")
parser.add_argument("--image", default="input.jpg", help="Path to input image")
parser.add_argument("--output", default="output.jpg", help="Path to save visualization")
parser.add_argument("--conf", type=float, default=0.25, help="Confidence threshold")
args = parser.parse_args()

providers = _select_providers()
try:
sess = ort.InferenceSession(args.model, providers=providers)
except Exception:
sess = ort.InferenceSession(args.model, providers=["CPUExecutionProvider"])
providers = ["CPUExecutionProvider"]

input_name = sess.get_inputs()[0].name

img0, inp = _load_image(args.image)
(out,) = sess.run(None, {input_name: inp})

det = np.asarray(out, dtype=np.float32)[0] # [300,6]
scores = det[:, 4]
keep = scores >= float(args.conf)
det = det[keep]
det = det[np.argsort(-det[:, 4])]

for x1, y1, x2, y2, score, cls in det:
_draw_xyxy(img0, np.array([x1, y1, x2, y2], dtype=np.float32), float(score), int(cls))

if not cv2.imwrite(args.output, img0):
raise RuntimeError(f"Failed to write image: {args.output}")

print(f"onnxruntime={ort.__version__} providers={providers}")
print(f"detections={len(det)} saved={args.output}")
return 0


if __name__ == "__main__":
raise SystemExit(main())
13 changes: 13 additions & 0 deletions samples/linux/python/yolo26n_det/ultralytics_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from ultralytics import YOLO

# Load the YOLO26 model
model = YOLO("yolo26n.pt or your .pt model path")

# Export the model to ONNX format
model.export(format="onnx") # creates 'yolo26n.onnx'

# Load the exported ONNX model
onnx_model = YOLO("your .onnx model path")

# Run inference
results = onnx_model("your input image")
Loading