Skip to content

Commit 59a118f

Browse files
committed
Add yolo26n_det in samples/linux/python
1 parent 343e479 commit 59a118f

File tree

6 files changed

+583
-0
lines changed

6 files changed

+583
-0
lines changed

samples/linux/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ The following table lists all available sample models with descriptions and exec
159159
| wideresnet50 | WideResNet50 image classification | `python wideresnet50/wideresnet50.py` |
160160
| xlsr | XLSR super-resolution | `python xlsr/xlsr.py` |
161161
| yolov8_det | YOLOv8 object detection | `python yolov8_det/yolov8_det.py` |
162+
| yolo26n_det | YOLO26n object detection | `python yolov26n_det/yolo26n_det.py` |
162163

163164
> **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.
164165
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# yolo26n_det Sample Code
2+
3+
## Introduction
4+
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.
5+
6+
## How to get the QNN format model
7+
### 1. Export .onnx format model using ultralytics version script
8+
```bash
9+
python ultralytics_version.py
10+
```
11+
12+
### 2. Set QNN related Environment Variables:
13+
```bash
14+
export QNN_SDK_ROOT=<path_to_your_qnn_sdk_root>
15+
export LD_LIBRARY_PATH=$QNN_SDK_ROOT/lib/aarch64-oe-linux-gcc11.2:$LD_LIBRARY_PATH
16+
export PYTHONPATH=${QNN_SDK_ROOT}/lib/python
17+
export PATH=${QNN_SDK_ROOT}/bin/x86_64-linux-clang/:$PATH
18+
export CPLUS_INCLUDE_PATH=/usr/include/c++/9:/usr/include/x86_64-linux-gnu/c++/9
19+
export LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9
20+
```
21+
22+
### 3. Model Conversion
23+
```bash
24+
$QNN_SDK_ROOT/bin/x86_64-linux-clang/qnn-onnx-converter \
25+
-i ./yolo26n.onnx \
26+
--preserve_io layout \
27+
--preserve_io datatype \
28+
--output_path ./yolo26n.cpp
29+
```
30+
31+
### 4. Model Lib Generation
32+
```bash
33+
$QNN_SDK_ROOT/bin/x86_64-linux-clang/qnn-model-lib-generator \
34+
-c ./yolo26n.cpp \
35+
-b ./yolo26n.bin \
36+
-t aarch64-oe-linux-gcc11.2 \
37+
-o ./
38+
```
39+
At this stage, a .so model library is generated. This library can be used on both the QNN CPU and HTP backends.
40+
41+
### 5. Context Binary Generation
42+
```bash
43+
$QNN_SDK_ROOT/bin/x86_64-linux-clang/qnn-context-binary-generator \
44+
--model ./x86_64-linux-clang/libyolo26n.so \
45+
--soc_model 77 \
46+
--backend ${QNN_SDK_ROOT}/lib/x86_64-linux-clang/libQnnHtp.so \
47+
--binary_file cntx_yolo26n_soc77_fp16
48+
```
49+
At this stage, a context binary (.bin) is generated, which can only be used on the HTP backend.
50+
51+
For more information, please refer to the QAIRT SDK documentation.
52+
53+
## Notes
54+
- 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.
55+
56+
## References
57+
[1] https://docs.qualcomm.com/nav/home/general_tools.html?product=1601111740009302
58+
59+
[2] https://docs.ultralytics.com/models/yolo26/
476 KB
Loading
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import argparse
2+
3+
import cv2
4+
import numpy as np
5+
import onnxruntime as ort
6+
7+
8+
IMAGE_SIZE = 640 # model expects [1,3,640,640]
9+
10+
# define class type (COCO 80)
11+
class_map = {
12+
0: "person",
13+
1: "bicycle",
14+
2: "car",
15+
3: "motorcycle",
16+
4: "airplane",
17+
5: "bus",
18+
6: "train",
19+
7: "truck",
20+
8: "boat",
21+
9: "traffic light",
22+
10: "fire hydrant",
23+
11: "stop sign",
24+
12: "parking meter",
25+
13: "bench",
26+
14: "bird",
27+
15: "cat",
28+
16: "dog",
29+
17: "horse",
30+
18: "sheep",
31+
19: "cow",
32+
20: "elephant",
33+
21: "bear",
34+
22: "zebra",
35+
23: "giraffe",
36+
24: "backpack",
37+
25: "umbrella",
38+
26: "handbag",
39+
27: "tie",
40+
28: "suitcase",
41+
29: "frisbee",
42+
30: "skis",
43+
31: "snowboard",
44+
32: "sports ball",
45+
33: "kite",
46+
34: "baseball bat",
47+
35: "baseball glove",
48+
36: "skateboard",
49+
37: "surfboard",
50+
38: "tennis racket",
51+
39: "bottle",
52+
40: "wine glass",
53+
41: "cup",
54+
42: "fork",
55+
43: "knife",
56+
44: "spoon",
57+
45: "bowl",
58+
46: "banana",
59+
47: "apple",
60+
48: "sandwich",
61+
49: "orange",
62+
50: "broccoli",
63+
51: "carrot",
64+
52: "hot dog",
65+
53: "pizza",
66+
54: "donut",
67+
55: "cake",
68+
56: "chair",
69+
57: "couch",
70+
58: "potted plant",
71+
59: "bed",
72+
60: "dining table",
73+
61: "toilet",
74+
62: "tv",
75+
63: "laptop",
76+
64: "mouse",
77+
65: "remote",
78+
66: "keyboard",
79+
67: "cell phone",
80+
68: "microwave",
81+
69: "oven",
82+
70: "toaster",
83+
71: "sink",
84+
72: "refrigerator",
85+
73: "book",
86+
74: "clock",
87+
75: "vase",
88+
76: "scissors",
89+
77: "teddy bear",
90+
78: "hair drier",
91+
79: "toothbrush"
92+
}
93+
94+
95+
def _select_providers() -> list[str]:
96+
available = ort.get_available_providers()
97+
preferred = ["CUDAExecutionProvider", "CPUExecutionProvider"]
98+
return [p for p in preferred if p in available] or available
99+
100+
101+
def _load_image(image_path: str) -> tuple[np.ndarray, np.ndarray]:
102+
img0 = cv2.imread(image_path)
103+
if img0 is None:
104+
raise FileNotFoundError(f"Failed to read image: {image_path}")
105+
106+
img = cv2.resize(img0, (IMAGE_SIZE, IMAGE_SIZE), interpolation=cv2.INTER_LINEAR)
107+
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
108+
img = img.astype(np.float32) / 255.0
109+
img = np.transpose(img, (2, 0, 1))[None] # NCHW
110+
return img0, img
111+
112+
113+
def _draw_xyxy(
114+
frame_bgr: np.ndarray,
115+
xyxy_640: np.ndarray,
116+
score: float,
117+
class_id: int,
118+
color: tuple[int, int, int] = (0, 255, 0),
119+
thickness: int = 2,
120+
) -> None:
121+
h, w = frame_bgr.shape[:2]
122+
scale_x = w / IMAGE_SIZE
123+
scale_y = h / IMAGE_SIZE
124+
125+
x1, y1, x2, y2 = xyxy_640.tolist()
126+
x1 = int(max(0.0, min(IMAGE_SIZE, x1)) * scale_x)
127+
y1 = int(max(0.0, min(IMAGE_SIZE, y1)) * scale_y)
128+
x2 = int(max(0.0, min(IMAGE_SIZE, x2)) * scale_x)
129+
y2 = int(max(0.0, min(IMAGE_SIZE, y2)) * scale_y)
130+
131+
cv2.rectangle(frame_bgr, (x1, y1), (x2, y2), color, thickness)
132+
class_name = class_map.get(class_id, "Unknown")
133+
label = f"{score:.2f} {class_name}"
134+
cv2.putText(
135+
frame_bgr,
136+
label,
137+
(x1, max(0, y1 - 8)),
138+
cv2.FONT_HERSHEY_SIMPLEX,
139+
0.6,
140+
color,
141+
2,
142+
cv2.LINE_AA,
143+
)
144+
145+
146+
def main() -> int:
147+
parser = argparse.ArgumentParser(description="YOLO26 ONNXRuntime inference (no NMS).")
148+
parser.add_argument("--model", default="yolo26n.onnx", help="Path to YOLO26 ONNX model")
149+
parser.add_argument("--image", default="input.jpg", help="Path to input image")
150+
parser.add_argument("--output", default="output.jpg", help="Path to save visualization")
151+
parser.add_argument("--conf", type=float, default=0.25, help="Confidence threshold")
152+
args = parser.parse_args()
153+
154+
providers = _select_providers()
155+
try:
156+
sess = ort.InferenceSession(args.model, providers=providers)
157+
except Exception:
158+
sess = ort.InferenceSession(args.model, providers=["CPUExecutionProvider"])
159+
providers = ["CPUExecutionProvider"]
160+
161+
input_name = sess.get_inputs()[0].name
162+
163+
img0, inp = _load_image(args.image)
164+
(out,) = sess.run(None, {input_name: inp})
165+
166+
det = np.asarray(out, dtype=np.float32)[0] # [300,6]
167+
scores = det[:, 4]
168+
keep = scores >= float(args.conf)
169+
det = det[keep]
170+
det = det[np.argsort(-det[:, 4])]
171+
172+
for x1, y1, x2, y2, score, cls in det:
173+
_draw_xyxy(img0, np.array([x1, y1, x2, y2], dtype=np.float32), float(score), int(cls))
174+
175+
if not cv2.imwrite(args.output, img0):
176+
raise RuntimeError(f"Failed to write image: {args.output}")
177+
178+
print(f"onnxruntime={ort.__version__} providers={providers}")
179+
print(f"detections={len(det)} saved={args.output}")
180+
return 0
181+
182+
183+
if __name__ == "__main__":
184+
raise SystemExit(main())
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from ultralytics import YOLO
2+
3+
# Load the YOLO26 model
4+
model = YOLO("yolo26n.pt or your .pt model path")
5+
6+
# Export the model to ONNX format
7+
model.export(format="onnx") # creates 'yolo26n.onnx'
8+
9+
# Load the exported ONNX model
10+
onnx_model = YOLO("your .onnx model path")
11+
12+
# Run inference
13+
results = onnx_model("your input image")

0 commit comments

Comments
 (0)