Delete examples
Browse files- examples/data/bus.jpg +0 -0
- examples/python/qnn_yolov5_multi.py +0 -350
- examples/python/snpe2_yolov5_multi.py +0 -338
examples/data/bus.jpg
DELETED
Binary file (181 kB)
|
|
examples/python/qnn_yolov5_multi.py
DELETED
@@ -1,350 +0,0 @@
|
|
1 |
-
# import sys
|
2 |
-
import os
|
3 |
-
import time
|
4 |
-
|
5 |
-
import aidlite
|
6 |
-
import cv2
|
7 |
-
import numpy as np
|
8 |
-
|
9 |
-
OBJ_CLASS_NUM = 80
|
10 |
-
NMS_THRESH = 0.45
|
11 |
-
BOX_THRESH = 0.5
|
12 |
-
MODEL_SIZE = 640
|
13 |
-
|
14 |
-
OBJ_NUMB_MAX_SIZE = 64
|
15 |
-
PROP_BOX_SIZE = (5 + OBJ_CLASS_NUM)
|
16 |
-
STRIDE8_SIZE = (MODEL_SIZE / 8)
|
17 |
-
STRIDE16_SIZE = (MODEL_SIZE / 16)
|
18 |
-
STRIDE32_SIZE = (MODEL_SIZE / 32)
|
19 |
-
|
20 |
-
anchors = [[10, 13, 16, 30, 33, 23],
|
21 |
-
[30, 61, 62, 45, 59, 119],
|
22 |
-
[116, 90, 156, 198, 373, 326]]
|
23 |
-
|
24 |
-
coco_class = [
|
25 |
-
'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
|
26 |
-
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant',
|
27 |
-
'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard',
|
28 |
-
'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle',
|
29 |
-
'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli',
|
30 |
-
'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet',
|
31 |
-
'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator',
|
32 |
-
'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush']
|
33 |
-
|
34 |
-
|
35 |
-
def eqprocess(image, size1, size2):
|
36 |
-
h, w, _ = image.shape
|
37 |
-
mask = np.zeros((size1, size2, 3), dtype=np.float32)
|
38 |
-
scale1 = h / size1
|
39 |
-
scale2 = w / size2
|
40 |
-
if scale1 > scale2:
|
41 |
-
scale = scale1
|
42 |
-
else:
|
43 |
-
scale = scale2
|
44 |
-
img = cv2.resize(image, (int(w / scale), int(h / scale)))
|
45 |
-
mask[:int(h / scale), :int(w / scale), :] = img
|
46 |
-
return mask, scale
|
47 |
-
|
48 |
-
|
49 |
-
def xywh2xyxy(x):
|
50 |
-
'''
|
51 |
-
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
52 |
-
'''
|
53 |
-
y = np.copy(x)
|
54 |
-
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
55 |
-
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
56 |
-
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
57 |
-
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
58 |
-
return y
|
59 |
-
|
60 |
-
|
61 |
-
def xyxy2xywh(box):
|
62 |
-
'''
|
63 |
-
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
64 |
-
'''
|
65 |
-
box[:, 2:] = box[:, 2:] - box[:, :2]
|
66 |
-
return box
|
67 |
-
|
68 |
-
|
69 |
-
def NMS(dets, scores, thresh):
|
70 |
-
'''
|
71 |
-
单类NMS算法
|
72 |
-
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
73 |
-
'''
|
74 |
-
x1 = dets[:, 0]
|
75 |
-
y1 = dets[:, 1]
|
76 |
-
x2 = dets[:, 2]
|
77 |
-
y2 = dets[:, 3]
|
78 |
-
areas = (y2 - y1 + 1) * (x2 - x1 + 1)
|
79 |
-
keep = []
|
80 |
-
index = scores.argsort()[::-1]
|
81 |
-
while index.size > 0:
|
82 |
-
i = index[0] # every time the first is the biggst, and add it directly
|
83 |
-
keep.append(i)
|
84 |
-
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
85 |
-
y11 = np.maximum(y1[i], y1[index[1:]])
|
86 |
-
x22 = np.minimum(x2[i], x2[index[1:]])
|
87 |
-
y22 = np.minimum(y2[i], y2[index[1:]])
|
88 |
-
w = np.maximum(0, x22 - x11 + 1) # the weights of overlap
|
89 |
-
h = np.maximum(0, y22 - y11 + 1) # the height of overlap
|
90 |
-
overlaps = w * h
|
91 |
-
ious = overlaps / (areas[i] + areas[index[1:]] - overlaps)
|
92 |
-
idx = np.where(ious <= thresh)[0]
|
93 |
-
index = index[idx + 1] # because index start from 1
|
94 |
-
|
95 |
-
return keep
|
96 |
-
|
97 |
-
|
98 |
-
def clip_coords(boxes, img_shape):
|
99 |
-
# Clip bounding xyxy bounding boxes to image shape (height, width)
|
100 |
-
boxes[:, 0].clip(0, img_shape[1], out=boxes[:, 0]) # x1
|
101 |
-
boxes[:, 1].clip(0, img_shape[0], out=boxes[:, 1]) # y1
|
102 |
-
boxes[:, 2].clip(0, img_shape[1], out=boxes[:, 2]) # x2
|
103 |
-
boxes[:, 3].clip(0, img_shape[0], out=boxes[:, 3]) # y2
|
104 |
-
|
105 |
-
|
106 |
-
def detect_postprocess(prediction, img0shape, img1shape, conf_thres=0.25, iou_thres=0.45):
|
107 |
-
'''
|
108 |
-
检测输出后处理
|
109 |
-
prediction: aidlite模型预测输出
|
110 |
-
img0shape: 原始图片shape
|
111 |
-
img1shape: 输入图片shape
|
112 |
-
conf_thres: 置信度阈值
|
113 |
-
iou_thres: IOU阈值
|
114 |
-
return: list[np.ndarray(N, 5)], 对应类别的坐标框信息, xywh、conf
|
115 |
-
'''
|
116 |
-
h, w, _ = img1shape
|
117 |
-
valid_condidates = prediction[prediction[..., 4] > conf_thres]
|
118 |
-
valid_condidates[:, 5:] *= valid_condidates[:, 4:5]
|
119 |
-
valid_condidates[:, :4] = xywh2xyxy(valid_condidates[:, :4])
|
120 |
-
|
121 |
-
max_det = 300
|
122 |
-
max_wh = 7680
|
123 |
-
max_nms = 30000
|
124 |
-
valid_condidates[:, 4] = valid_condidates[:, 5:].max(1)
|
125 |
-
valid_condidates[:, 5] = valid_condidates[:, 5:].argmax(1)
|
126 |
-
sort_id = np.argsort(valid_condidates[:, 4])[::-1]
|
127 |
-
valid_condidates = valid_condidates[sort_id[:max_nms]]
|
128 |
-
boxes, scores = valid_condidates[:, :4] + valid_condidates[:, 5:6] * max_wh, valid_condidates[:, 4]
|
129 |
-
index = NMS(boxes, scores, iou_thres)[:max_det]
|
130 |
-
out_boxes = valid_condidates[index]
|
131 |
-
clip_coords(out_boxes[:, :4], img0shape)
|
132 |
-
out_boxes[:, :4] = xyxy2xywh(out_boxes[:, :4])
|
133 |
-
print("检测到{}个区域".format(len(out_boxes)))
|
134 |
-
return out_boxes
|
135 |
-
|
136 |
-
|
137 |
-
def draw_detect_res(img, det_pred):
|
138 |
-
'''
|
139 |
-
检测结果绘制
|
140 |
-
'''
|
141 |
-
img = img.astype(np.uint8)
|
142 |
-
color_step = int(255 / len(coco_class))
|
143 |
-
for i in range(len(det_pred)):
|
144 |
-
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
145 |
-
score = det_pred[i][4]
|
146 |
-
cls_id = int(det_pred[i][5])
|
147 |
-
|
148 |
-
print(i + 1, [x1, y1, x2, y2], score, coco_class[cls_id])
|
149 |
-
|
150 |
-
cv2.putText(img, f'{coco_class[cls_id]}', (x1, y1 - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
151 |
-
cv2.rectangle(img, (x1, y1), (x2 + x1, y2 + y1), (0, int(cls_id * color_step), int(255 - cls_id * color_step)),
|
152 |
-
thickness=2)
|
153 |
-
|
154 |
-
return img
|
155 |
-
|
156 |
-
|
157 |
-
class Detect():
|
158 |
-
# YOLOv5 Detect head for detection models
|
159 |
-
def __init__(self, nc=80, anchors=(), stride=[], image_size=640): # detection layer
|
160 |
-
super().__init__()
|
161 |
-
self.nc = nc # number of classes
|
162 |
-
self.no = nc + 5 # number of outputs per anchor
|
163 |
-
self.stride = stride
|
164 |
-
self.nl = len(anchors) # number of detection layers
|
165 |
-
self.na = len(anchors[0]) // 2 # number of anchors
|
166 |
-
self.grid, self.anchor_grid = [0] * self.nl, [0] * self.nl
|
167 |
-
self.anchors = np.array(anchors, dtype=np.float32).reshape(self.nl, -1, 2)
|
168 |
-
|
169 |
-
base_scale = image_size // 8
|
170 |
-
for i in range(self.nl):
|
171 |
-
self.grid[i], self.anchor_grid[i] = self._make_grid(base_scale // (2 ** i), base_scale // (2 ** i), i)
|
172 |
-
|
173 |
-
def _make_grid(self, nx=20, ny=20, i=0):
|
174 |
-
y, x = np.arange(ny, dtype=np.float32), np.arange(nx, dtype=np.float32)
|
175 |
-
yv, xv = np.meshgrid(y, x)
|
176 |
-
yv, xv = yv.T, xv.T
|
177 |
-
# add grid offset, i.e. y = 2.0 * x - 0.5
|
178 |
-
grid = np.stack((xv, yv), 2)
|
179 |
-
grid = grid[np.newaxis, np.newaxis, ...]
|
180 |
-
grid = np.repeat(grid, self.na, axis=1) - 0.5
|
181 |
-
anchor_grid = self.anchors[i].reshape((1, self.na, 1, 1, 2))
|
182 |
-
anchor_grid = np.repeat(anchor_grid, repeats=ny, axis=2)
|
183 |
-
anchor_grid = np.repeat(anchor_grid, repeats=nx, axis=3)
|
184 |
-
return grid, anchor_grid
|
185 |
-
|
186 |
-
def sigmoid(self, arr):
|
187 |
-
return 1 / (1 + np.exp(-arr))
|
188 |
-
|
189 |
-
def __call__(self, x):
|
190 |
-
z = [] # inference output
|
191 |
-
for i in range(self.nl):
|
192 |
-
bs, _, ny, nx = x[i].shape
|
193 |
-
x[i] = x[i].reshape(bs, self.na, self.no, ny, nx).transpose(0, 1, 3, 4, 2)
|
194 |
-
y = self.sigmoid(x[i])
|
195 |
-
y[..., 0:2] = (y[..., 0:2] * 2. + self.grid[i]) * self.stride[i] # xy
|
196 |
-
y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh
|
197 |
-
z.append(y.reshape(bs, self.na * nx * ny, self.no))
|
198 |
-
|
199 |
-
return np.concatenate(z, 1)
|
200 |
-
|
201 |
-
|
202 |
-
def main():
|
203 |
-
# argvs = len(sys.argv)
|
204 |
-
# if argvs < 2:
|
205 |
-
# print("python3 ./qnn_yolov5_multi.py 0 for use DSP")
|
206 |
-
# print("python3 ./qnn_yolov5_multi.py 1 for use CPU")
|
207 |
-
# print("python3 ./qnn_yolov5_multi.py 2 for use GPU")
|
208 |
-
# return False
|
209 |
-
# acc_type = int(sys.argv[1])
|
210 |
-
|
211 |
-
print("Start main ... ...")
|
212 |
-
aidlite.set_log_level(aidlite.LogLevel.INFO)
|
213 |
-
aidlite.log_to_stderr()
|
214 |
-
print(f"Aidlite library version : {aidlite.get_library_version()}")
|
215 |
-
print(f"Aidlite python library version : {aidlite.get_py_library_version()}")
|
216 |
-
|
217 |
-
config = aidlite.Config.create_instance()
|
218 |
-
if config is None:
|
219 |
-
print("Create config failed !")
|
220 |
-
return False
|
221 |
-
|
222 |
-
# if acc_type == 1:
|
223 |
-
# config.accelerate_type = aidlite.AccelerateType.TYPE_CPU
|
224 |
-
# elif acc_type == 2:
|
225 |
-
# config.accelerate_type = aidlite.AccelerateType.TYPE_GPU
|
226 |
-
# config.is_quantify_model = 0
|
227 |
-
# elif acc_type == 0:
|
228 |
-
# config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
229 |
-
# config.is_quantify_model = 1
|
230 |
-
# else:
|
231 |
-
# print("python3 ./qnn_yolov5_multi.py 0 for use DSP")
|
232 |
-
# print("python3 ./qnn_yolov5_multi.py 1 for use CPU")
|
233 |
-
# print("python3 ./qnn_yolov5_multi.py 2 for use GPU")
|
234 |
-
# return False
|
235 |
-
|
236 |
-
config.implement_type = aidlite.ImplementType.TYPE_LOCAL
|
237 |
-
config.framework_type = aidlite.FrameworkType.TYPE_QNN
|
238 |
-
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
239 |
-
config.is_quantify_model = 1
|
240 |
-
|
241 |
-
model_path = "/home/aidlux/modelzoo/examples/data/cutoff_yolov5s_int8_qnn/cutoff_yolov5s_int8.qnn.serialized.bin"
|
242 |
-
model = aidlite.Model.create_instance(model_path)
|
243 |
-
if model is None:
|
244 |
-
print("Create model failed !")
|
245 |
-
return False
|
246 |
-
input_shapes = [[1, MODEL_SIZE, MODEL_SIZE, 3]]
|
247 |
-
output_shapes = [[1, 20, 20, 255], [1, 40, 40, 255], [1, 80, 80, 255]]
|
248 |
-
model.set_model_properties(input_shapes, aidlite.DataType.TYPE_FLOAT32,
|
249 |
-
output_shapes, aidlite.DataType.TYPE_FLOAT32)
|
250 |
-
|
251 |
-
interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
|
252 |
-
if interpreter is None:
|
253 |
-
print("build_interpretper_from_model_and_config failed !")
|
254 |
-
return None
|
255 |
-
result = interpreter.init()
|
256 |
-
if result != 0:
|
257 |
-
print(f"interpreter init failed !")
|
258 |
-
return False
|
259 |
-
result = interpreter.load_model()
|
260 |
-
if result != 0:
|
261 |
-
print("interpreter load model failed !")
|
262 |
-
return False
|
263 |
-
print("detect model load success!")
|
264 |
-
stride8 = stride16 = stride32 = None
|
265 |
-
|
266 |
-
image_path = os.path.join("../data/bus.jpg")
|
267 |
-
frame = cv2.imread(image_path)
|
268 |
-
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
269 |
-
img_input, scale = eqprocess(frame, MODEL_SIZE, MODEL_SIZE)
|
270 |
-
img_input = img_input / 255
|
271 |
-
img_input = img_input.astype(np.float32)
|
272 |
-
|
273 |
-
sum_time_0 = 0.0
|
274 |
-
sum_time_1 = 0.0
|
275 |
-
sum_time_2 = 0.0
|
276 |
-
_counter = 1
|
277 |
-
for idx in range(_counter):
|
278 |
-
st0 = time.time()
|
279 |
-
input_tensor_data = img_input.data
|
280 |
-
result = interpreter.set_input_tensor(0, input_tensor_data)
|
281 |
-
if result != 0:
|
282 |
-
print("interpreter set_input_tensor() failed")
|
283 |
-
return False
|
284 |
-
et0 = time.time()
|
285 |
-
dur0 = (et0 - st0) * 1000
|
286 |
-
sum_time_0 += dur0
|
287 |
-
print(f"current [{idx}] set_input_tensor cost time :{dur0} ms")
|
288 |
-
|
289 |
-
st1 = time.time()
|
290 |
-
result = interpreter.invoke()
|
291 |
-
if result != 0:
|
292 |
-
print("interpreter set_input_tensor() failed")
|
293 |
-
return False
|
294 |
-
et1 = time.time()
|
295 |
-
dur1 = (et1 - st1) * 1000
|
296 |
-
sum_time_1 += dur1
|
297 |
-
print(f"current [{idx}] invoke cost time :{dur1} ms")
|
298 |
-
|
299 |
-
st2 = time.time()
|
300 |
-
|
301 |
-
stride8 = interpreter.get_output_tensor(0)
|
302 |
-
if stride8 is None:
|
303 |
-
print("sample : interpreter->get_output_tensor() 0 failed !")
|
304 |
-
return False
|
305 |
-
print(f"len(stride8 {len(stride8)}")
|
306 |
-
|
307 |
-
stride16 = interpreter.get_output_tensor(1)
|
308 |
-
if stride16 is None:
|
309 |
-
print("sample : interpreter->get_output_tensor() 2 failed !")
|
310 |
-
return False
|
311 |
-
print(f"len(stride16 {len(stride16)}")
|
312 |
-
|
313 |
-
stride32 = interpreter.get_output_tensor(2)
|
314 |
-
if stride32 is None:
|
315 |
-
print("sample : interpreter->get_output_tensor() 1 failed !")
|
316 |
-
return False
|
317 |
-
print(f"len(stride32 {len(stride32)}")
|
318 |
-
et2 = time.time()
|
319 |
-
dur2 = (et2 - st2) * 1000
|
320 |
-
sum_time_2 += dur2
|
321 |
-
print(f"current [{idx}] get_output_tensor cost time :{dur2} ms")
|
322 |
-
|
323 |
-
print(
|
324 |
-
f"repeat [{_counter}] times , input[{sum_time_0 * 1000}]ms --- invoke[{sum_time_1 * 1000}]ms --- output[{sum_time_2 * 1000}]ms --- sum[{(sum_time_0 + sum_time_1 + sum_time_2) * 1000}]ms")
|
325 |
-
|
326 |
-
stride = [8, 16, 32]
|
327 |
-
yolo_head = Detect(OBJ_CLASS_NUM, anchors, stride, MODEL_SIZE)
|
328 |
-
# 后处理部分reshape需要知道模型的output_shapes
|
329 |
-
validCount0 = stride8.reshape(*output_shapes[2]).transpose(0, 3, 1, 2)
|
330 |
-
validCount1 = stride16.reshape(*output_shapes[1]).transpose(0, 3, 1, 2)
|
331 |
-
validCount2 = stride32.reshape(*output_shapes[0]).transpose(0, 3, 1, 2)
|
332 |
-
pred = yolo_head([validCount0, validCount1, validCount2])
|
333 |
-
det_pred = detect_postprocess(pred, frame.shape, [MODEL_SIZE, MODEL_SIZE, 3], conf_thres=0.5, iou_thres=0.45)
|
334 |
-
det_pred[np.isnan(det_pred)] = 0.0
|
335 |
-
det_pred[:, :4] = det_pred[:, :4] * scale
|
336 |
-
res_img = draw_detect_res(frame, det_pred)
|
337 |
-
|
338 |
-
result = interpreter.destory()
|
339 |
-
if result != 0:
|
340 |
-
print(f"interpreter set_input_tensor() failed")
|
341 |
-
return False
|
342 |
-
frame_bgr = cv2.cvtColor(res_img, cv2.COLOR_RGB2BGR)
|
343 |
-
result_img_path = f"{os.path.splitext(os.path.abspath(__file__))[0]}.jpg"
|
344 |
-
cv2.imwrite(result_img_path, frame_bgr)
|
345 |
-
print(f"The result image has been saved to : {result_img_path}")
|
346 |
-
return True
|
347 |
-
|
348 |
-
|
349 |
-
if __name__ == "__main__":
|
350 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/python/snpe2_yolov5_multi.py
DELETED
@@ -1,338 +0,0 @@
|
|
1 |
-
import os
|
2 |
-
import struct
|
3 |
-
import sys
|
4 |
-
import time
|
5 |
-
|
6 |
-
import aidlite
|
7 |
-
import cv2
|
8 |
-
import numpy as np
|
9 |
-
|
10 |
-
FLOAT_SIZE = struct.calcsize('f')
|
11 |
-
OBJ_CLASS_NUM = 80
|
12 |
-
MODEL_SIZE = 640
|
13 |
-
anchors = [[10, 13, 16, 30, 33, 23],
|
14 |
-
[30, 61, 62, 45, 59, 119],
|
15 |
-
[116, 90, 156, 198, 373, 326]]
|
16 |
-
|
17 |
-
coco_class = [
|
18 |
-
'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
|
19 |
-
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant',
|
20 |
-
'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard',
|
21 |
-
'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle',
|
22 |
-
'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli',
|
23 |
-
'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet',
|
24 |
-
'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator',
|
25 |
-
'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush']
|
26 |
-
|
27 |
-
|
28 |
-
def eqprocess(image, size1, size2):
|
29 |
-
h, w, _ = image.shape
|
30 |
-
mask = np.zeros((size1, size2, 3), dtype=np.float32)
|
31 |
-
scale1 = h / size1
|
32 |
-
scale2 = w / size2
|
33 |
-
if scale1 > scale2:
|
34 |
-
scale = scale1
|
35 |
-
else:
|
36 |
-
scale = scale2
|
37 |
-
img = cv2.resize(image, (int(w / scale), int(h / scale)))
|
38 |
-
mask[:int(h / scale), :int(w / scale), :] = img
|
39 |
-
return mask, scale
|
40 |
-
|
41 |
-
|
42 |
-
def xywh2xyxy(x):
|
43 |
-
'''
|
44 |
-
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
45 |
-
'''
|
46 |
-
y = np.copy(x)
|
47 |
-
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
48 |
-
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
49 |
-
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
50 |
-
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
51 |
-
return y
|
52 |
-
|
53 |
-
|
54 |
-
def xyxy2xywh(box):
|
55 |
-
'''
|
56 |
-
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
57 |
-
'''
|
58 |
-
box[:, 2:] = box[:, 2:] - box[:, :2]
|
59 |
-
return box
|
60 |
-
|
61 |
-
|
62 |
-
def NMS(dets, scores, thresh):
|
63 |
-
'''
|
64 |
-
单类NMS算法
|
65 |
-
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
66 |
-
'''
|
67 |
-
x1 = dets[:, 0]
|
68 |
-
y1 = dets[:, 1]
|
69 |
-
x2 = dets[:, 2]
|
70 |
-
y2 = dets[:, 3]
|
71 |
-
areas = (y2 - y1 + 1) * (x2 - x1 + 1)
|
72 |
-
keep = []
|
73 |
-
index = scores.argsort()[::-1]
|
74 |
-
while index.size > 0:
|
75 |
-
i = index[0] # every time the first is the biggst, and add it directly
|
76 |
-
keep.append(i)
|
77 |
-
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
78 |
-
y11 = np.maximum(y1[i], y1[index[1:]])
|
79 |
-
x22 = np.minimum(x2[i], x2[index[1:]])
|
80 |
-
y22 = np.minimum(y2[i], y2[index[1:]])
|
81 |
-
w = np.maximum(0, x22 - x11 + 1) # the weights of overlap
|
82 |
-
h = np.maximum(0, y22 - y11 + 1) # the height of overlap
|
83 |
-
overlaps = w * h
|
84 |
-
ious = overlaps / (areas[i] + areas[index[1:]] - overlaps)
|
85 |
-
idx = np.where(ious <= thresh)[0]
|
86 |
-
index = index[idx + 1] # because index start from 1
|
87 |
-
|
88 |
-
return keep
|
89 |
-
|
90 |
-
|
91 |
-
def clip_coords(boxes, img_shape):
|
92 |
-
# Clip bounding xyxy bounding boxes to image shape (height, width)
|
93 |
-
boxes[:, 0].clip(0, img_shape[1], out=boxes[:, 0]) # x1
|
94 |
-
boxes[:, 1].clip(0, img_shape[0], out=boxes[:, 1]) # y1
|
95 |
-
boxes[:, 2].clip(0, img_shape[1], out=boxes[:, 2]) # x2
|
96 |
-
boxes[:, 3].clip(0, img_shape[0], out=boxes[:, 3]) # y2
|
97 |
-
|
98 |
-
|
99 |
-
def detect_postprocess(prediction, img0shape, img1shape, conf_thres=0.25, iou_thres=0.45):
|
100 |
-
'''
|
101 |
-
检测输出后处理
|
102 |
-
prediction: aidlite模型预测输出
|
103 |
-
img0shape: 原始图片shape
|
104 |
-
img1shape: 输入图片shape
|
105 |
-
conf_thres: 置信度阈值
|
106 |
-
iou_thres: IOU阈值
|
107 |
-
return: list[np.ndarray(N, 5)], 对应类别的坐标框信息, xywh、conf
|
108 |
-
'''
|
109 |
-
h, w, _ = img1shape
|
110 |
-
valid_condidates = prediction[prediction[..., 4] > conf_thres]
|
111 |
-
valid_condidates[:, 5:] *= valid_condidates[:, 4:5]
|
112 |
-
valid_condidates[:, :4] = xywh2xyxy(valid_condidates[:, :4])
|
113 |
-
|
114 |
-
max_det = 300
|
115 |
-
max_wh = 7680
|
116 |
-
max_nms = 30000
|
117 |
-
valid_condidates[:, 4] = valid_condidates[:, 5:].max(1)
|
118 |
-
valid_condidates[:, 5] = valid_condidates[:, 5:].argmax(1)
|
119 |
-
sort_id = np.argsort(valid_condidates[:, 4])[::-1]
|
120 |
-
valid_condidates = valid_condidates[sort_id[:max_nms]]
|
121 |
-
boxes, scores = valid_condidates[:, :4] + valid_condidates[:, 5:6] * max_wh, valid_condidates[:, 4]
|
122 |
-
index = NMS(boxes, scores, iou_thres)[:max_det]
|
123 |
-
out_boxes = valid_condidates[index]
|
124 |
-
clip_coords(out_boxes[:, :4], img0shape)
|
125 |
-
out_boxes[:, :4] = xyxy2xywh(out_boxes[:, :4])
|
126 |
-
print("检测到{}个区域".format(len(out_boxes)))
|
127 |
-
return out_boxes
|
128 |
-
|
129 |
-
|
130 |
-
def draw_detect_res(img, det_pred):
|
131 |
-
'''
|
132 |
-
检测结果绘制
|
133 |
-
'''
|
134 |
-
img = img.astype(np.uint8)
|
135 |
-
color_step = int(255 / len(coco_class))
|
136 |
-
for i in range(len(det_pred)):
|
137 |
-
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
138 |
-
score = det_pred[i][4]
|
139 |
-
cls_id = int(det_pred[i][5])
|
140 |
-
|
141 |
-
print(i + 1, [x1, y1, x2, y2], score, coco_class[cls_id])
|
142 |
-
|
143 |
-
cv2.putText(img, f'{coco_class[cls_id]}', (x1, y1 - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
144 |
-
cv2.rectangle(img, (x1, y1), (x2 + x1, y2 + y1), (0, int(cls_id * color_step), int(255 - cls_id * color_step)),
|
145 |
-
thickness=2)
|
146 |
-
|
147 |
-
return img
|
148 |
-
|
149 |
-
|
150 |
-
class Detect():
|
151 |
-
# YOLOv5 Detect head for detection models
|
152 |
-
def __init__(self, nc=80, anchors=(), stride=[], image_size=640): # detection layer
|
153 |
-
super().__init__()
|
154 |
-
self.nc = nc # number of classes
|
155 |
-
self.no = nc + 5 # number of outputs per anchor
|
156 |
-
self.stride = stride
|
157 |
-
self.nl = len(anchors) # number of detection layers
|
158 |
-
self.na = len(anchors[0]) // 2 # number of anchors
|
159 |
-
self.grid, self.anchor_grid = [0] * self.nl, [0] * self.nl
|
160 |
-
self.anchors = np.array(anchors, dtype=np.float32).reshape(self.nl, -1, 2)
|
161 |
-
|
162 |
-
base_scale = image_size // 8
|
163 |
-
for i in range(self.nl):
|
164 |
-
self.grid[i], self.anchor_grid[i] = self._make_grid(base_scale // (2 ** i), base_scale // (2 ** i), i)
|
165 |
-
|
166 |
-
def _make_grid(self, nx=20, ny=20, i=0):
|
167 |
-
y, x = np.arange(ny, dtype=np.float32), np.arange(nx, dtype=np.float32)
|
168 |
-
yv, xv = np.meshgrid(y, x)
|
169 |
-
yv, xv = yv.T, xv.T
|
170 |
-
# add grid offset, i.e. y = 2.0 * x - 0.5
|
171 |
-
grid = np.stack((xv, yv), 2)
|
172 |
-
grid = grid[np.newaxis, np.newaxis, ...]
|
173 |
-
grid = np.repeat(grid, self.na, axis=1) - 0.5
|
174 |
-
anchor_grid = self.anchors[i].reshape((1, self.na, 1, 1, 2))
|
175 |
-
anchor_grid = np.repeat(anchor_grid, repeats=ny, axis=2)
|
176 |
-
anchor_grid = np.repeat(anchor_grid, repeats=nx, axis=3)
|
177 |
-
return grid, anchor_grid
|
178 |
-
|
179 |
-
def sigmoid(self, arr):
|
180 |
-
return 1 / (1 + np.exp(-arr))
|
181 |
-
|
182 |
-
def __call__(self, x):
|
183 |
-
z = [] # inference output
|
184 |
-
for i in range(self.nl):
|
185 |
-
bs, _, ny, nx = x[i].shape
|
186 |
-
x[i] = x[i].reshape(bs, self.na, self.no, ny, nx).transpose(0, 1, 3, 4, 2)
|
187 |
-
y = self.sigmoid(x[i])
|
188 |
-
y[..., 0:2] = (y[..., 0:2] * 2. + self.grid[i]) * self.stride[i] # xy
|
189 |
-
y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh
|
190 |
-
z.append(y.reshape(bs, self.na * nx * ny, self.no))
|
191 |
-
|
192 |
-
return np.concatenate(z, 1)
|
193 |
-
|
194 |
-
|
195 |
-
def main():
|
196 |
-
acc_type = 0
|
197 |
-
aidlite.set_log_level(aidlite.LogLevel.INFO)
|
198 |
-
aidlite.log_to_stderr()
|
199 |
-
|
200 |
-
# image process
|
201 |
-
image_path = r"../data/bus.jpg"
|
202 |
-
frame = cv2.imread(image_path)
|
203 |
-
if frame is None:
|
204 |
-
print(f"{image_path} not exists")
|
205 |
-
return False
|
206 |
-
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
207 |
-
img_input, scale = eqprocess(frame, MODEL_SIZE, MODEL_SIZE)
|
208 |
-
img_input = img_input / 255
|
209 |
-
img_input = img_input.astype(np.float32)
|
210 |
-
|
211 |
-
config = aidlite.Config.create_instance()
|
212 |
-
if config is None:
|
213 |
-
print("build_interpretper_from_model_and_config failed !")
|
214 |
-
return False
|
215 |
-
|
216 |
-
# model init
|
217 |
-
acc_type_dsp = True
|
218 |
-
model_path = r"../data/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s_int8_htp_snpe2.dlc"
|
219 |
-
outNode_names = "/model.24/m.1/Conv,/model.24/m.2/Conv,/model.24/m.0/Conv"
|
220 |
-
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
221 |
-
config.is_quantify_model = 1
|
222 |
-
|
223 |
-
|
224 |
-
config.implement_type = aidlite.ImplementType.TYPE_LOCAL
|
225 |
-
config.framework_type = aidlite.FrameworkType.TYPE_SNPE2
|
226 |
-
config.snpe_out_names = outNode_names.split(',')
|
227 |
-
print("---------------------------")
|
228 |
-
print(config.snpe_out_names)
|
229 |
-
|
230 |
-
model = aidlite.Model.create_instance(model_path)
|
231 |
-
if model is None:
|
232 |
-
print("Create model failed !")
|
233 |
-
return False
|
234 |
-
|
235 |
-
input_shapes = [[1, MODEL_SIZE, MODEL_SIZE, 3]]
|
236 |
-
output_shapes = [[1, 40, 40, 255], [1, 20, 20, 255], [1, 80, 80, 255]]
|
237 |
-
model.set_model_properties(input_shapes, aidlite.DataType.TYPE_FLOAT32, output_shapes,
|
238 |
-
aidlite.DataType.TYPE_FLOAT32)
|
239 |
-
|
240 |
-
snpe2_interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
|
241 |
-
if snpe2_interpreter is None:
|
242 |
-
print("build_interpretper_from_model_and_config failed !")
|
243 |
-
return None
|
244 |
-
result = snpe2_interpreter.init()
|
245 |
-
if result != 0:
|
246 |
-
print(f"interpreter init failed !")
|
247 |
-
return False
|
248 |
-
result = snpe2_interpreter.load_model()
|
249 |
-
if result != 0:
|
250 |
-
print("interpreter load model failed !")
|
251 |
-
return False
|
252 |
-
print("detect model load success!")
|
253 |
-
|
254 |
-
stride8 = stride16 = stride32 = None
|
255 |
-
sum_time_0 = 0.0
|
256 |
-
sum_time_1 = 0.0
|
257 |
-
sum_time_2 = 0.0
|
258 |
-
_counter = 1
|
259 |
-
for idx in range(_counter):
|
260 |
-
st0 = time.time()
|
261 |
-
|
262 |
-
if acc_type_dsp:
|
263 |
-
time.sleep(0.04) # 40milliseconds
|
264 |
-
|
265 |
-
input_tensor_data = img_input.data
|
266 |
-
result = snpe2_interpreter.set_input_tensor(0, input_tensor_data)
|
267 |
-
if result != 0:
|
268 |
-
print("interpreter set_input_tensor() failed")
|
269 |
-
return False
|
270 |
-
et0 = time.time()
|
271 |
-
dur0 = (et0 - st0) * 1000
|
272 |
-
sum_time_0 += dur0
|
273 |
-
print(f"current [{idx}] set_input_tensor cost time :{dur0} ms")
|
274 |
-
|
275 |
-
st1 = time.time()
|
276 |
-
result = snpe2_interpreter.invoke()
|
277 |
-
if result != 0:
|
278 |
-
print("interpreter set_input_tensor() failed")
|
279 |
-
return False
|
280 |
-
et1 = time.time()
|
281 |
-
dur1 = (et1 - st1) * 1000
|
282 |
-
sum_time_1 += dur1
|
283 |
-
print(f"current [{idx}] invoke cost time :{dur1} ms")
|
284 |
-
|
285 |
-
st2 = time.time()
|
286 |
-
|
287 |
-
if acc_type_dsp:
|
288 |
-
time.sleep(0.02) # 40milliseconds
|
289 |
-
|
290 |
-
stride8 = snpe2_interpreter.get_output_tensor(0)
|
291 |
-
if stride8 is None:
|
292 |
-
print("sample : interpreter->get_output_tensor() 0 failed !")
|
293 |
-
return False
|
294 |
-
print(f"len(stride8 {len(stride8)}")
|
295 |
-
|
296 |
-
stride16 = snpe2_interpreter.get_output_tensor(1)
|
297 |
-
if stride16 is None:
|
298 |
-
print("sample : interpreter->get_output_tensor() 2 failed !")
|
299 |
-
return False
|
300 |
-
print(f"len(stride16 {len(stride16)}")
|
301 |
-
|
302 |
-
stride32 = snpe2_interpreter.get_output_tensor(2)
|
303 |
-
if stride32 is None:
|
304 |
-
print("sample : interpreter->get_output_tensor() 1 failed !")
|
305 |
-
return False
|
306 |
-
print(f"len(stride32 {len(stride32)}")
|
307 |
-
et2 = time.time()
|
308 |
-
dur2 = (et2 - st2) * 1000
|
309 |
-
sum_time_2 += dur2
|
310 |
-
print(f"current [{idx}] get_output_tensor cost time :{dur2} ms")
|
311 |
-
|
312 |
-
print(
|
313 |
-
f"repeat [{_counter}] time , input[{sum_time_0}]ms --- invoke[{sum_time_1}]ms --- output[{sum_time_2}]ms --- sum[{sum_time_0 + sum_time_1 + sum_time_2}]ms")
|
314 |
-
|
315 |
-
stride = [8, 16, 32]
|
316 |
-
yolo_head = Detect(OBJ_CLASS_NUM, anchors, stride, MODEL_SIZE)
|
317 |
-
validCount0 = stride8.reshape(*output_shapes[2]).transpose(0, 3, 1, 2)
|
318 |
-
validCount1 = stride16.reshape(*output_shapes[0]).transpose(0, 3, 1, 2)
|
319 |
-
validCount2 = stride32.reshape(*output_shapes[1]).transpose(0, 3, 1, 2)
|
320 |
-
pred = yolo_head([validCount0, validCount1, validCount2])
|
321 |
-
det_pred = detect_postprocess(pred, frame.shape, [MODEL_SIZE, MODEL_SIZE, 3], conf_thres=0.5, iou_thres=0.45)
|
322 |
-
det_pred[np.isnan(det_pred)] = 0.0
|
323 |
-
det_pred[:, :4] = det_pred[:, :4] * scale
|
324 |
-
res_img = draw_detect_res(frame, det_pred)
|
325 |
-
|
326 |
-
result = snpe2_interpreter.destory()
|
327 |
-
if result != 0:
|
328 |
-
print(f"interpreter set_input_tensor() failed")
|
329 |
-
return False
|
330 |
-
frame_bgr = cv2.cvtColor(res_img, cv2.COLOR_RGB2BGR)
|
331 |
-
result_img_path = f"{os.path.splitext(os.path.abspath(__file__))[0]}.jpg"
|
332 |
-
cv2.imwrite(result_img_path, frame_bgr)
|
333 |
-
print(f"The result image has been saved to : {result_img_path}")
|
334 |
-
return True
|
335 |
-
|
336 |
-
|
337 |
-
if __name__ == "__main__":
|
338 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|