当前位置:   article > 正文

RK3588部署YOLOv8_rk3588 yolov8

rk3588 yolov8

本人基于YOLOv8改进水了一篇论文,为了增加工作量在RK3588上部署了改进的算法。根据网上的方法一直没有部署成功,最后在参考官方和网络上的方法成功实现算法的部署,因此写下这篇博客进行记录,以防后面忘了怎么部署,也可供网友参考.

环境

电脑端:os:Ubuntu 20.04  rknn-toolkit2:1.5.2  python:3.8

开发板:orange pi 5   os:Ubuntu 22.04.3 LTS jammy  python:3.10.12

1.导出torchscript模型

瑞芯微官方提供了直接转pytorch模型转torchscript的代码,不需要转成ONNX格式。我参考网上pytorch->onnx->rknn的方法,模型转出为rknn后,代码一直跑不起来,主要是我的模型导出为onnx后只有一个输出output0,官方给的onnx模型有9个输出头。我用pytorch->torchscript->rknn的方法,程序完美运行。

首先,克隆Rockchip官方的YOLOv8代码,仓库地址为https://github.com/airockchip/ultralytics_yolov8.git 也可以使用我的代码文件,我本地测试是没有问题的 链接:https://pan.baidu.com/s/1NJT3JggsDu11j-AjfWoRbg?pwd=e4ox 

然后修改./ultralytics/nn/modules/head.py里的代码

将pytorch模型转torchscript,转完可以再pt模型文件夹下看到best_rknnopt.torchscript

  1. from ultralytics import YOLO
  2. model = YOLO('./runs/detect/train/yolov8_coco/weights/best.pt') # 将这里换成你模型所在的路径
  3. path = model.export(format="rknn", opset=12)

torchscript有6个输出

2.torchscript转rknn

克隆代码https://github.com/airockchip/rknn_model_zoo.git,这里要注意这个仓库现在更新到了1.5.2版本,但我使用的是1.5.0版本,克隆的时候需要注意,也可以使用我提供的链接直接下载压缩包https://pan.baidu.com/s/1LlZt9l3ks2Rg-cioTh8jbQ?pwd=ggi1 提取码:ggi1

打开 rknn_model_zoo/models/CV/object_detection/yolo/RKNN_model_convert 文件夹,新建一个yolov8_rk3588.yml文件,文件内容如下,根据你的模型路径修改model_file_path。

  1. #support yolo[v5,v6,v7,v8], ppyoloe_plus
  2. model_framework: pytorch
  3. model_file_path: yolov8_coco.torchscript
  4. RK_device_platform: RK3588
  5. # RK_device_id: simulator
  6. dataset: ../../../../../datasets/COCO/coco_subset_10.txt
  7. quantize: True
  8. pre_compile: online
  9. graph:
  10. in_0:
  11. shape: 1,3,640,640
  12. mean_values: 0
  13. std_values: 255
  14. img_type: RGB
  15. configs:
  16. quantized_dtype: asymmetric_quantized-8
  17. quantized_algorithm: normal
  18. optimization_level: 2
  19. # force_builtin_perm: True

修改convert_yolo.sh

python ../../../../../common/rknn_converter/rknn_convert.py --yml_path ./yolov8_rk3588.yml

然后终端输入 ./convert_yolo.sh 运行脚本程序,在model_cvt/RK3588/路径下可以看到转换成功的rknn模型

3.测试rknn模型

我这里是使用ADB连接开发板进行连板测试的,如果只在电脑进行模拟测试,要修改代码,我在代码里注释了。也可以下载我的工程进行测试 https://github.com/yjl326/yolo_rknn.git

  1. import os
  2. import cv2
  3. from rknn.api import RKNN
  4. import numpy as np
  5. RKNN_MODEL = "./model/yolov8_coco_RK3588_i8.rknn"
  6. IMG_FOLDER = "./datasets/COCO/"
  7. RESULT_PATH = './result/coco'
  8. CLASSES = ['person','bicycle','car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
  9. 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
  10. 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
  11. 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
  12. 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
  13. 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
  14. 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
  15. 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
  16. 'hair drier', 'toothbrush' ]
  17. OBJ_THRESH = 0.45
  18. NMS_THRESH = 0.45
  19. MODEL_SIZE = (640, 640)
  20. color_palette = np.random.uniform(0, 255, size=(len(CLASSES), 3))
  21. def sigmoid(x):
  22. return 1 / (1 + np.exp(-x))
  23. def letter_box(im, new_shape, pad_color=(0,0,0), info_need=False):
  24. # Resize and pad image while meeting stride-multiple constraints
  25. shape = im.shape[:2] # current shape [height, width]
  26. if isinstance(new_shape, int):
  27. new_shape = (new_shape, new_shape)
  28. # Scale ratio
  29. r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
  30. # Compute padding
  31. ratio = r # width, height ratios
  32. new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
  33. dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding
  34. dw /= 2 # divide padding into 2 sides
  35. dh /= 2
  36. if shape[::-1] != new_unpad: # resize
  37. im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR)
  38. top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
  39. left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
  40. im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=pad_color) # add border
  41. if info_need is True:
  42. return im, ratio, (dw, dh)
  43. else:
  44. return im
  45. def filter_boxes(boxes, box_confidences, box_class_probs):
  46. """Filter boxes with object threshold.
  47. """
  48. box_confidences = box_confidences.reshape(-1)
  49. candidate, class_num = box_class_probs.shape
  50. class_max_score = np.max(box_class_probs, axis=-1)
  51. classes = np.argmax(box_class_probs, axis=-1)
  52. _class_pos = np.where(class_max_score* box_confidences >= OBJ_THRESH)
  53. scores = (class_max_score * box_confidences)[_class_pos]
  54. boxes = boxes[_class_pos]
  55. classes = classes[_class_pos]
  56. return boxes, classes, scores
  57. def nms_boxes(boxes, scores):
  58. """Suppress non-maximal boxes.
  59. # Returns
  60. keep: ndarray, index of effective boxes.
  61. """
  62. x = boxes[:, 0]
  63. y = boxes[:, 1]
  64. w = boxes[:, 2] - boxes[:, 0]
  65. h = boxes[:, 3] - boxes[:, 1]
  66. areas = w * h
  67. order = scores.argsort()[::-1]
  68. keep = []
  69. while order.size > 0:
  70. i = order[0]
  71. keep.append(i)
  72. xx1 = np.maximum(x[i], x[order[1:]])
  73. yy1 = np.maximum(y[i], y[order[1:]])
  74. xx2 = np.minimum(x[i] + w[i], x[order[1:]] + w[order[1:]])
  75. yy2 = np.minimum(y[i] + h[i], y[order[1:]] + h[order[1:]])
  76. w1 = np.maximum(0.0, xx2 - xx1 + 0.00001)
  77. h1 = np.maximum(0.0, yy2 - yy1 + 0.00001)
  78. inter = w1 * h1
  79. ovr = inter / (areas[i] + areas[order[1:]] - inter)
  80. inds = np.where(ovr <= NMS_THRESH)[0]
  81. order = order[inds + 1]
  82. keep = np.array(keep)
  83. return keep
  84. def softmax(x, axis=None):
  85. x = x - x.max(axis=axis, keepdims=True)
  86. y = np.exp(x)
  87. return y / y.sum(axis=axis, keepdims=True)
  88. def dfl(position):
  89. # Distribution Focal Loss (DFL)
  90. n,c,h,w = position.shape
  91. p_num = 4
  92. mc = c//p_num
  93. y = position.reshape(n,p_num,mc,h,w)
  94. y = softmax(y, 2)
  95. acc_metrix = np.array(range(mc),dtype=float).reshape(1,1,mc,1,1)
  96. y = (y*acc_metrix).sum(2)
  97. return y
  98. def box_process(position):
  99. grid_h, grid_w = position.shape[2:4]
  100. col, row = np.meshgrid(np.arange(0, grid_w), np.arange(0, grid_h))
  101. col = col.reshape(1, 1, grid_h, grid_w)
  102. row = row.reshape(1, 1, grid_h, grid_w)
  103. grid = np.concatenate((col, row), axis=1)
  104. stride = np.array([MODEL_SIZE[1]//grid_h, MODEL_SIZE[0]//grid_w]).reshape(1,2,1,1)
  105. position = dfl(position)
  106. box_xy = grid +0.5 -position[:,0:2,:,:]
  107. box_xy2 = grid +0.5 +position[:,2:4,:,:]
  108. xyxy = np.concatenate((box_xy*stride, box_xy2*stride), axis=1)
  109. return xyxy
  110. def post_process(input_data):
  111. boxes, scores, classes_conf = [], [], []
  112. defualt_branch=3
  113. pair_per_branch = len(input_data)//defualt_branch
  114. # Python 忽略 score_sum 输出
  115. for i in range(defualt_branch):
  116. boxes.append(box_process(input_data[pair_per_branch*i]))
  117. classes_conf.append(input_data[pair_per_branch*i+1])
  118. scores.append(np.ones_like(input_data[pair_per_branch*i+1][:,:1,:,:], dtype=np.float32))
  119. def sp_flatten(_in):
  120. ch = _in.shape[1]
  121. _in = _in.transpose(0,2,3,1)
  122. return _in.reshape(-1, ch)
  123. boxes = [sp_flatten(_v) for _v in boxes]
  124. classes_conf = [sp_flatten(_v) for _v in classes_conf]
  125. scores = [sp_flatten(_v) for _v in scores]
  126. boxes = np.concatenate(boxes)
  127. classes_conf = np.concatenate(classes_conf)
  128. scores = np.concatenate(scores)
  129. # filter according to threshold
  130. boxes, classes, scores = filter_boxes(boxes, scores, classes_conf)
  131. # nms
  132. nboxes, nclasses, nscores = [], [], []
  133. for c in set(classes):
  134. inds = np.where(classes == c)
  135. b = boxes[inds]
  136. c = classes[inds]
  137. s = scores[inds]
  138. keep = nms_boxes(b, s)
  139. if len(keep) != 0:
  140. nboxes.append(b[keep])
  141. nclasses.append(c[keep])
  142. nscores.append(s[keep])
  143. if not nclasses and not nscores:
  144. return None, None, None
  145. boxes = np.concatenate(nboxes)
  146. classes = np.concatenate(nclasses)
  147. scores = np.concatenate(nscores)
  148. return boxes, classes, scores
  149. def draw_detections(img, left, top, right, bottom, score, class_id):
  150. """
  151. Draws bounding boxes and labels on the input image based on the detected objects.
  152. Args:
  153. img: The input image to draw detections on.
  154. box: Detected bounding box.
  155. score: Corresponding detection score.
  156. class_id: Class ID for the detected object.
  157. Returns:
  158. None
  159. """
  160. # Retrieve the color for the class ID
  161. color = color_palette[class_id]
  162. # Draw the bounding box on the image
  163. cv2.rectangle(img, (int(left), int(top)), (int(right), int(bottom)), color, 2)
  164. # Create the label text with class name and score
  165. label = f"{CLASSES[class_id]}: {score:.2f}"
  166. # Calculate the dimensions of the label text
  167. (label_width, label_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
  168. # Calculate the position of the label text
  169. label_x = left
  170. label_y = top - 10 if top - 10 > label_height else top + 10
  171. # Draw a filled rectangle as the background for the label text
  172. cv2.rectangle(img, (label_x, label_y - label_height), (label_x + label_width, label_y + label_height), color,
  173. cv2.FILLED)
  174. # Draw the label text on the image
  175. cv2.putText(img, label, (label_x, label_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
  176. def draw(image, boxes, scores, classes):
  177. img_h, img_w = image.shape[:2]
  178. # Calculate scaling factors for bounding box coordinates
  179. x_factor = img_w / MODEL_SIZE[0]
  180. y_factor = img_h / MODEL_SIZE[1]
  181. for box, score, cl in zip(boxes, scores, classes):
  182. x1, y1, x2, y2 = [int(_b) for _b in box]
  183. left = int(x1* x_factor)
  184. top = int(y1 * y_factor) - 10
  185. right = int(x2 * x_factor)
  186. bottom = int(y2 * y_factor) + 10
  187. print('class: {}, score: {}'.format(CLASSES[cl], score))
  188. print('box coordinate left,top,right,down: [{}, {}, {}, {}]'.format(left, top, right, bottom))
  189. # Retrieve the color for the class ID
  190. draw_detections(image, left, top, right, bottom, score, cl)
  191. # cv2.rectangle(image, (left, top), (right, bottom), color, 2)
  192. # cv2.putText(image, '{0} {1:.2f}'.format(CLASSES[cl], score),
  193. # (left, top - 6),
  194. # cv2.FONT_HERSHEY_SIMPLEX,
  195. # 0.6, (0, 0, 255), 2)
  196. if __name__ == '__main__':
  197. # 创建RKNN对象
  198. rknn = RKNN()
  199. #加载RKNN模型
  200. print('--> Load RKNN model')
  201. ret = rknn.load_rknn(RKNN_MODEL)
  202. if ret != 0:
  203. print('Load RKNN model failed')
  204. exit(ret)
  205. print('done')
  206. # 初始化 runtime 环境
  207. print('--> Init runtime environment')
  208. # run on RK356x/RK3588 with Debian OS, do not need specify target.
  209. ret = rknn.init_runtime(target='rk3588', device_id='48c122b87375ccbc')
  210. # 如果使用电脑进行模拟测试
  211. # ret = rknn.init_runtime()
  212. if ret != 0:
  213. print('Init runtime environment failed!')
  214. exit(ret)
  215. print('done')
  216. # 数据处理
  217. img_list = os.listdir(IMG_FOLDER)
  218. for i in range(len(img_list)):
  219. img_name = img_list[i]
  220. img_path = os.path.join(IMG_FOLDER, img_name)
  221. if not os.path.exists(img_path):
  222. print("{} is not found", img_name)
  223. continue
  224. img_src = cv2.imread(img_path)
  225. if img_src is None:
  226. print("文件不存在\n")
  227. # Due to rga init with (0,0,0), we using pad_color (0,0,0) instead of (114, 114, 114)
  228. pad_color = (0,0,0)
  229. img = letter_box(im= img_src.copy(), new_shape=(MODEL_SIZE[1], MODEL_SIZE[0]), pad_color=(0,0,0))
  230. #img = cv2.resize(img_src, (640, 512), interpolation=cv2.INTER_LINEAR) # direct resize
  231. input = np.expand_dims(img, axis=0)
  232. outputs = rknn.inference([input])
  233. boxes, classes, scores = post_process(outputs)
  234. img_p = img_src.copy()
  235. if boxes is not None:
  236. draw(img_p, boxes, scores, classes)
  237. # 保存结果
  238. if not os.path.exists(RESULT_PATH):
  239. os.mkdir(RESULT_PATH)
  240. result_path = os.path.join(RESULT_PATH, img_name)
  241. cv2.imwrite(result_path, img_p)
  242. print('Detection result save to {}'.format(result_path))
  243. pass
  244. rknn.release()

RK3588端运行代码,其实就是把RKNN换成RKNNLite,其他都一样

  1. import os
  2. import cv2
  3. from rknnlite.api import RKNNLite
  4. import numpy as np
  5. RKNN_MODEL = "./model/yolov8_coco_RK3588_i8.rknn"
  6. IMG_FOLDER = "./datasets/COCO/"
  7. RESULT_PATH = './result/coco'
  8. CLASSES = ['person','bicycle','car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
  9. 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
  10. 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
  11. 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
  12. 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
  13. 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
  14. 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
  15. 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
  16. 'hair drier', 'toothbrush' ]
  17. OBJ_THRESH = 0.45
  18. NMS_THRESH = 0.45
  19. MODEL_SIZE = (640, 640)
  20. color_palette = np.random.uniform(0, 255, size=(len(CLASSES), 3))
  21. def sigmoid(x):
  22. return 1 / (1 + np.exp(-x))
  23. def letter_box(im, new_shape, pad_color=(0,0,0), info_need=False):
  24. # Resize and pad image while meeting stride-multiple constraints
  25. shape = im.shape[:2] # current shape [height, width]
  26. if isinstance(new_shape, int):
  27. new_shape = (new_shape, new_shape)
  28. # Scale ratio
  29. r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
  30. # Compute padding
  31. ratio = r # width, height ratios
  32. new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
  33. dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding
  34. dw /= 2 # divide padding into 2 sides
  35. dh /= 2
  36. if shape[::-1] != new_unpad: # resize
  37. im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR)
  38. top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
  39. left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
  40. im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=pad_color) # add border
  41. if info_need is True:
  42. return im, ratio, (dw, dh)
  43. else:
  44. return im
  45. def filter_boxes(boxes, box_confidences, box_class_probs):
  46. """Filter boxes with object threshold.
  47. """
  48. box_confidences = box_confidences.reshape(-1)
  49. candidate, class_num = box_class_probs.shape
  50. class_max_score = np.max(box_class_probs, axis=-1)
  51. classes = np.argmax(box_class_probs, axis=-1)
  52. _class_pos = np.where(class_max_score* box_confidences >= OBJ_THRESH)
  53. scores = (class_max_score * box_confidences)[_class_pos]
  54. boxes = boxes[_class_pos]
  55. classes = classes[_class_pos]
  56. return boxes, classes, scores
  57. def nms_boxes(boxes, scores):
  58. """Suppress non-maximal boxes.
  59. # Returns
  60. keep: ndarray, index of effective boxes.
  61. """
  62. x = boxes[:, 0]
  63. y = boxes[:, 1]
  64. w = boxes[:, 2] - boxes[:, 0]
  65. h = boxes[:, 3] - boxes[:, 1]
  66. areas = w * h
  67. order = scores.argsort()[::-1]
  68. keep = []
  69. while order.size > 0:
  70. i = order[0]
  71. keep.append(i)
  72. xx1 = np.maximum(x[i], x[order[1:]])
  73. yy1 = np.maximum(y[i], y[order[1:]])
  74. xx2 = np.minimum(x[i] + w[i], x[order[1:]] + w[order[1:]])
  75. yy2 = np.minimum(y[i] + h[i], y[order[1:]] + h[order[1:]])
  76. w1 = np.maximum(0.0, xx2 - xx1 + 0.00001)
  77. h1 = np.maximum(0.0, yy2 - yy1 + 0.00001)
  78. inter = w1 * h1
  79. ovr = inter / (areas[i] + areas[order[1:]] - inter)
  80. inds = np.where(ovr <= NMS_THRESH)[0]
  81. order = order[inds + 1]
  82. keep = np.array(keep)
  83. return keep
  84. def softmax(x, axis=None):
  85. x = x - x.max(axis=axis, keepdims=True)
  86. y = np.exp(x)
  87. return y / y.sum(axis=axis, keepdims=True)
  88. def dfl(position):
  89. # Distribution Focal Loss (DFL)
  90. n,c,h,w = position.shape
  91. p_num = 4
  92. mc = c//p_num
  93. y = position.reshape(n,p_num,mc,h,w)
  94. y = softmax(y, 2)
  95. acc_metrix = np.array(range(mc),dtype=float).reshape(1,1,mc,1,1)
  96. y = (y*acc_metrix).sum(2)
  97. return y
  98. def box_process(position):
  99. grid_h, grid_w = position.shape[2:4]
  100. col, row = np.meshgrid(np.arange(0, grid_w), np.arange(0, grid_h))
  101. col = col.reshape(1, 1, grid_h, grid_w)
  102. row = row.reshape(1, 1, grid_h, grid_w)
  103. grid = np.concatenate((col, row), axis=1)
  104. stride = np.array([MODEL_SIZE[1]//grid_h, MODEL_SIZE[0]//grid_w]).reshape(1,2,1,1)
  105. position = dfl(position)
  106. box_xy = grid +0.5 -position[:,0:2,:,:]
  107. box_xy2 = grid +0.5 +position[:,2:4,:,:]
  108. xyxy = np.concatenate((box_xy*stride, box_xy2*stride), axis=1)
  109. return xyxy
  110. def post_process(input_data):
  111. boxes, scores, classes_conf = [], [], []
  112. defualt_branch=3
  113. pair_per_branch = len(input_data)//defualt_branch
  114. # Python 忽略 score_sum 输出
  115. for i in range(defualt_branch):
  116. boxes.append(box_process(input_data[pair_per_branch*i]))
  117. classes_conf.append(input_data[pair_per_branch*i+1])
  118. scores.append(np.ones_like(input_data[pair_per_branch*i+1][:,:1,:,:], dtype=np.float32))
  119. def sp_flatten(_in):
  120. ch = _in.shape[1]
  121. _in = _in.transpose(0,2,3,1)
  122. return _in.reshape(-1, ch)
  123. boxes = [sp_flatten(_v) for _v in boxes]
  124. classes_conf = [sp_flatten(_v) for _v in classes_conf]
  125. scores = [sp_flatten(_v) for _v in scores]
  126. boxes = np.concatenate(boxes)
  127. classes_conf = np.concatenate(classes_conf)
  128. scores = np.concatenate(scores)
  129. # filter according to threshold
  130. boxes, classes, scores = filter_boxes(boxes, scores, classes_conf)
  131. # nms
  132. nboxes, nclasses, nscores = [], [], []
  133. for c in set(classes):
  134. inds = np.where(classes == c)
  135. b = boxes[inds]
  136. c = classes[inds]
  137. s = scores[inds]
  138. keep = nms_boxes(b, s)
  139. if len(keep) != 0:
  140. nboxes.append(b[keep])
  141. nclasses.append(c[keep])
  142. nscores.append(s[keep])
  143. if not nclasses and not nscores:
  144. return None, None, None
  145. boxes = np.concatenate(nboxes)
  146. classes = np.concatenate(nclasses)
  147. scores = np.concatenate(nscores)
  148. return boxes, classes, scores
  149. def draw_detections(img, left, top, right, bottom, score, class_id):
  150. """
  151. Draws bounding boxes and labels on the input image based on the detected objects.
  152. Args:
  153. img: The input image to draw detections on.
  154. box: Detected bounding box.
  155. score: Corresponding detection score.
  156. class_id: Class ID for the detected object.
  157. Returns:
  158. None
  159. """
  160. # Retrieve the color for the class ID
  161. color = color_palette[class_id]
  162. # Draw the bounding box on the image
  163. cv2.rectangle(img, (int(left), int(top)), (int(right), int(bottom)), color, 2)
  164. # Create the label text with class name and score
  165. label = f"{CLASSES[class_id]}: {score:.2f}"
  166. # Calculate the dimensions of the label text
  167. (label_width, label_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
  168. # Calculate the position of the label text
  169. label_x = left
  170. label_y = top - 10 if top - 10 > label_height else top + 10
  171. # Draw a filled rectangle as the background for the label text
  172. cv2.rectangle(img, (label_x, label_y - label_height), (label_x + label_width, label_y + label_height), color,
  173. cv2.FILLED)
  174. # Draw the label text on the image
  175. cv2.putText(img, label, (label_x, label_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
  176. def draw(image, boxes, scores, classes):
  177. img_h, img_w = image.shape[:2]
  178. # Calculate scaling factors for bounding box coordinates
  179. x_factor = img_w / MODEL_SIZE[0]
  180. y_factor = img_h / MODEL_SIZE[1]
  181. for box, score, cl in zip(boxes, scores, classes):
  182. x1, y1, x2, y2 = [int(_b) for _b in box]
  183. left = int(x1* x_factor)
  184. top = int(y1 * y_factor)
  185. right = int(x2 * x_factor)
  186. bottom = int(y2 * y_factor)
  187. print('class: {}, score: {}'.format(CLASSES[cl], score))
  188. print('box coordinate left,top,right,down: [{}, {}, {}, {}]'.format(left, top, right, bottom))
  189. # Retrieve the color for the class ID
  190. draw_detections(image, left, top, right, bottom, score, cl)
  191. # cv2.rectangle(image, (left, top), (right, bottom), color, 2)
  192. # cv2.putText(image, '{0} {1:.2f}'.format(CLASSES[cl], score),
  193. # (left, top - 6),
  194. # cv2.FONT_HERSHEY_SIMPLEX,
  195. # 0.6, (0, 0, 255), 2)
  196. if __name__ == '__main__':
  197. # 创建RKNN对象
  198. rknn_lite = RKNNLite()
  199. #加载RKNN模型
  200. print('--> Load RKNN model')
  201. ret = rknn_lite.load_rknn(RKNN_MODEL)
  202. if ret != 0:
  203. print('Load RKNN model failed')
  204. exit(ret)
  205. print('done')
  206. # 初始化 runtime 环境
  207. print('--> Init runtime environment')
  208. # run on RK356x/RK3588 with Debian OS, do not need specify target.
  209. ret = rknn_lite.init_runtime()
  210. if ret != 0:
  211. print('Init runtime environment failed!')
  212. exit(ret)
  213. print('done')
  214. # 数据处理
  215. img_list = os.listdir(IMG_FOLDER)
  216. for i in range(len(img_list)):
  217. img_name = img_list[i]
  218. img_path = os.path.join(IMG_FOLDER, img_name)
  219. if not os.path.exists(img_path):
  220. print("{} is not found", img_name)
  221. continue
  222. img_src = cv2.imread(img_path)
  223. if img_src is None:
  224. print("文件不存在\n")
  225. # Due to rga init with (0,0,0), we using pad_color (0,0,0) instead of (114, 114, 114)
  226. pad_color = (0,0,0)
  227. img = letter_box(im= img_src.copy(), new_shape=(MODEL_SIZE[1], MODEL_SIZE[0]), pad_color=(0,0,0))
  228. #img = cv2.resize(img_src, (640, 512), interpolation=cv2.INTER_LINEAR) # direct resize
  229. input = np.expand_dims(img, axis=0)
  230. outputs = rknn_lite.inference([input])
  231. boxes, classes, scores = post_process(outputs)
  232. img_p = img_src.copy()
  233. if boxes is not None:
  234. draw(img_p, boxes, scores, classes)
  235. # 保存结果
  236. if not os.path.exists(RESULT_PATH):
  237. os.mkdir(RESULT_PATH)
  238. result_path = os.path.join(RESULT_PATH, img_name)
  239. cv2.imwrite(result_path, img_p)
  240. print('Detection result save to {}'.format(result_path))
  241. pass
  242. # cv2.imshow("full post process result", img_p)
  243. rknn_lite.release()

4.检测效果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/322989
推荐阅读
相关标签
  

闽ICP备14008679号