├── .gitignore ├── README.md ├── inference_npu.py ├── lib ├── config.py └── postprocess.py ├── models ├── yolov5s-640-640.rknn └── yolov5s.rknn └── rknn_toolkit_lite2-1.4.0-cp39-cp39-linux_aarch64.whl /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YOLOv5-RK3588-Python 2 | Modify Code From rknn-toolkit2 3 | 4 | # Getting Started 5 | You can change source cam, resolution from capture in config.py 6 | 7 | # Prerequisites 8 | 1. must compile opencv support gstreamer 9 | 2. opencv 10 | 3. gstreamer 11 | 4. rknnlite2 from rknn-toolkit2 12 | 5. usb webcam 13 | 14 | # Running the program 15 | python inference_npu.py 16 | 17 | # This branch (singlethread) 18 | 1. Improve performance by transfer detect box to original stream 19 | 2. remove redundancy postprocess 20 | 3. add default support cv2.capture (cam2) 21 | 4. add file mp4 support (need gstreamer) 22 | 23 | # Example on Youtube 24 | https://www.youtube.com/watch?v=eD6L55MkDoo 25 | # YOLOv5 vs YOLOv8 26 | https://www.youtube.com/watch?v=ROTseFoK89o 27 | -------------------------------------------------------------------------------- /inference_npu.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import platform 4 | from rknnlite.api import RKNNLite 5 | from imutils.video import FPS 6 | import time 7 | from lib.postprocess import yolov5_post_process, letterbox_reverse_box 8 | import lib.config as config 9 | import argparse 10 | 11 | # construct the argument parse and parse the arguments 12 | ap = argparse.ArgumentParser() 13 | #cam = use gstreamer, cam2 = use cv2.videocapture 14 | ap.add_argument("-i", "--inputtype", required=False, default="cam2", 15 | help="Select input cam, cam2, file") 16 | ap.add_argument("-f", "--filename", required=False, default="skyfall.mp4", 17 | help="file video (.mp4)") 18 | args = vars(ap.parse_args()) 19 | 20 | IMG_SIZE = config.IMG_SIZE 21 | 22 | CLASSES = config.CLASSES 23 | 24 | # decice tree for rk356x/rk3588 25 | DEVICE_COMPATIBLE_NODE = config.DEVICE_COMPATIBLE_NODE 26 | 27 | RK356X_RKNN_MODEL = config.RK356X_RKNN_MODEL 28 | RK3588_RKNN_MODEL = config.RK3588_RKNN_MODEL 29 | 30 | def get_host(): 31 | # get platform and device type 32 | system = platform.system() 33 | machine = platform.machine() 34 | os_machine = system + '-' + machine 35 | if os_machine == 'Linux-aarch64': 36 | try: 37 | with open(DEVICE_COMPATIBLE_NODE) as f: 38 | device_compatible_str = f.read() 39 | if 'rk3588' in device_compatible_str: 40 | host = 'RK3588' 41 | else: 42 | host = 'RK356x' 43 | except IOError: 44 | print('Read device node {} failed.'.format(DEVICE_COMPATIBLE_NODE)) 45 | exit(-1) 46 | else: 47 | host = os_machine 48 | return host 49 | 50 | #def draw(image, boxes, scores, classes): 51 | def draw(image, boxes, scores, classes, dw, dh): 52 | """Draw the boxes on the image. 53 | 54 | # Argument: 55 | image: original image. 56 | boxes: ndarray, boxes of objects. 57 | classes: ndarray, classes of objects. 58 | scores: ndarray, scores of objects. 59 | all_classes: all classes name. 60 | """ 61 | for box, score, cl in zip(boxes, scores, classes): 62 | top, left, right, bottom = box 63 | # print('class: {}, score: {}'.format(CLASSES[cl], score)) 64 | # print('box coordinate left,top,right,down: [{}, {}, {}, {}]'.format(top, left, right, bottom)) 65 | 66 | ##Transform Box to original image 67 | top, left, right, bottom = letterbox_reverse_box(top, left, right, bottom, config.CAM_WIDTH, config.CAM_HEIGHT, config.IMG_SIZE, config.IMG_SIZE, dw, dh) 68 | 69 | top = int(top) 70 | left = int(left) 71 | right = int(right) 72 | bottom = int(bottom) 73 | 74 | cv2.rectangle(image, (top, left), (right, bottom), (255, 0, 0), 2) 75 | cv2.putText(image, '{0} {1:.2f}'.format(CLASSES[cl], score), 76 | (top, left - 6), 77 | cv2.FONT_HERSHEY_SIMPLEX, 78 | 0.6, (0, 0, 255), 2) 79 | 80 | def letterbox(im, new_shape=(640, 640), color=(0, 0, 0)): 81 | # Resize and pad image while meeting stride-multiple constraints 82 | shape = im.shape[:2] # current shape [height, width] 83 | if isinstance(new_shape, int): 84 | new_shape = (new_shape, new_shape) 85 | 86 | # Scale ratio (new / old) 87 | r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) 88 | 89 | # Compute padding 90 | ratio = r, r # width, height ratios 91 | new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) 92 | dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding 93 | 94 | dw /= 2 # divide padding into 2 sides 95 | dh /= 2 96 | 97 | if shape[::-1] != new_unpad: # resize 98 | im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR) 99 | top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) 100 | left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) 101 | im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border 102 | return im, ratio, (dw, dh) 103 | 104 | def open_cam_usb(dev, width, height): 105 | # We want to set width and height here, otherwise we could just do: 106 | # return cv2.VideoCapture(dev) 107 | 108 | if args["inputtype"] == 'cam': 109 | gst_str = ("uvch264src device=/dev/video{} ! " 110 | "image/jpeg, width={}, height={}, framerate=30/1 ! " 111 | "jpegdec ! " 112 | "video/x-raw, format=BGR ! " 113 | "appsink").format(dev, width, height) 114 | vs = cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER) 115 | 116 | elif args["inputtype"] == 'file': 117 | gst_str = ("filesrc location={} ! " 118 | "qtdemux name=demux demux. ! queue ! faad ! audioconvert ! audioresample ! autoaudiosink demux. ! " 119 | "avdec_h264 ! videoscale ! videoconvert ! " 120 | "appsink").format(args["filename"]) 121 | vs = cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER) 122 | 123 | elif args["inputtype"] == 'cam2': 124 | vs = cv2.VideoCapture(dev) 125 | vs.set(cv2.CAP_PROP_FRAME_WIDTH, width) 126 | vs.set(cv2.CAP_PROP_FRAME_HEIGHT, height) 127 | 128 | 129 | return vs 130 | 131 | 132 | 133 | 134 | if __name__ == '__main__': 135 | 136 | host_name = get_host() 137 | if host_name == 'RK356x': 138 | rknn_model = RK356X_RKNN_MODEL 139 | elif host_name == 'RK3588': 140 | rknn_model = RK3588_RKNN_MODEL 141 | else: 142 | print("This demo cannot run on the current platform: {}".format(host_name)) 143 | exit(-1) 144 | 145 | rknn_lite = RKNNLite() 146 | 147 | # load RKNN model 148 | print('--> Load RKNN model') 149 | ret = rknn_lite.load_rknn(rknn_model) 150 | if ret != 0: 151 | print('Load RKNN model failed') 152 | exit(ret) 153 | print('done') 154 | 155 | # ori_img = cv2.imread('./bus.jpg') 156 | # img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2RGB) 157 | 158 | # init runtime environment 159 | print('--> Init runtime environment') 160 | # run on RK356x/RK3588 with Debian OS, do not need specify target. 161 | if host_name == 'RK3588': 162 | ret = rknn_lite.init_runtime(core_mask=RKNNLite.NPU_CORE_0) 163 | else: 164 | ret = rknn_lite.init_runtime() 165 | if ret != 0: 166 | print('Init runtime environment failed') 167 | exit(ret) 168 | print('done') 169 | 170 | 171 | #Create Stream from Webcam 172 | vs = open_cam_usb(config.CAM_DEV, config.CAM_WIDTH, config.CAM_HEIGHT) 173 | 174 | 175 | time.sleep(2.0) 176 | fps = FPS().start() 177 | 178 | if not vs.isOpened(): 179 | print("Cannot capture from camera. Exiting.") 180 | quit() 181 | 182 | prev_frame_time = 0 183 | new_frame_time = 0 184 | 185 | 186 | # loop over the frames from the video stream 187 | while True: 188 | 189 | ret, frame = vs.read() 190 | 191 | if not ret: 192 | break 193 | #Debug Webcam Input 194 | # cv2.imshow("Original", frame) 195 | #Show FPS in Pic 196 | new_frame_time = time.time() 197 | show_fps = 1/(new_frame_time-prev_frame_time) 198 | prev_frame_time = new_frame_time 199 | show_fps = int(show_fps) 200 | show_fps = str("{} FPS".format(show_fps)) 201 | 202 | ori_frame = frame 203 | 204 | frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 205 | frame, ratio, (dw, dh) = letterbox(frame, new_shape=(IMG_SIZE, IMG_SIZE)) 206 | # frame = cv2.resize(frame, (IMG_SIZE, IMG_SIZE)) 207 | 208 | # Inference 209 | outputs = rknn_lite.inference(inputs=[frame]) 210 | 211 | # post process 212 | input0_data = outputs[0] 213 | input1_data = outputs[1] 214 | input2_data = outputs[2] 215 | 216 | input0_data = input0_data.reshape([3, -1]+list(input0_data.shape[-2:])) 217 | input1_data = input1_data.reshape([3, -1]+list(input1_data.shape[-2:])) 218 | input2_data = input2_data.reshape([3, -1]+list(input2_data.shape[-2:])) 219 | 220 | input_data = list() 221 | input_data.append(np.transpose(input0_data, (2, 3, 0, 1))) 222 | input_data.append(np.transpose(input1_data, (2, 3, 0, 1))) 223 | input_data.append(np.transpose(input2_data, (2, 3, 0, 1))) 224 | 225 | #Disable Enable YOLO Post process 226 | boxes, classes, scores = yolov5_post_process(input_data) 227 | 228 | # boxes = None 229 | 230 | # img_1 = frame 231 | img_1 = ori_frame 232 | if boxes is not None: 233 | 234 | # img_1 = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) 235 | # draw(img_1, boxes, scores, classes) 236 | draw(img_1, boxes, scores, classes, dw, dh) 237 | 238 | # show FPS in Frame 239 | cv2.putText(img_1, show_fps, (7, 70), cv2.FONT_HERSHEY_SIMPLEX, 1, (100, 255, 0), 1, cv2.LINE_AA) 240 | 241 | #rescale to equal original 242 | # old_h, old_w = img_1.shape[:2] 243 | # ratio_h, ratio_w = ratio 244 | # print(old_h/ratio_h, old_w/ratio_w) 245 | # img_1 = cv2.resize(img_1, (int(old_h/ratio_h), int(old_w/ratio_w)), interpolation=cv2.INTER_LINEAR) 246 | # img_1 = cv2.resize(img_1, (800, 800), interpolation=cv2.INTER_LINEAR) 247 | 248 | # show output 249 | cv2.imshow("yolov5 post process result", img_1) 250 | 251 | key = cv2.waitKey(1) & 0xFF 252 | 253 | # if the `q` key was pressed, break from the loop 254 | if key == ord("q"): 255 | break 256 | 257 | 258 | # update the FPS counter 259 | fps.update() 260 | 261 | 262 | rknn_lite.release() 263 | 264 | # stop the timer and display FPS information 265 | fps.stop() 266 | print("[INFO] elapsed time: {:.2f}".format(fps.elapsed())) 267 | print("[INFO] approx. FPS: {:.2f}".format(fps.fps())) 268 | 269 | # do a bit of cleanup 270 | cv2.destroyAllWindows() 271 | vs.release() 272 | 273 | -------------------------------------------------------------------------------- /lib/config.py: -------------------------------------------------------------------------------- 1 | # YOLOv5 Parameter 2 | #OBJ_THRESH = 0.25 3 | OBJ_THRESH = 0.5 4 | NMS_THRESH = 0.45 5 | IMG_SIZE = 640 6 | # YOLOv5 Classes 7 | CLASSES = ("person", "bicycle", "car", "motorbike ", "aeroplane ", "bus ", "train", "truck ", "boat", "traffic light", 8 | "fire hydrant", "stop sign ", "parking meter", "bench", "bird", "cat", "dog ", "horse ", "sheep", "cow", "elephant", 9 | "bear", "zebra ", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", 10 | "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife ", 11 | "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza ", "donut", "cake", "chair", "sofa", 12 | "pottedplant", "bed", "diningtable", "toilet ", "tvmonitor", "laptop ", "mouse ", "remote ", "keyboard ", "cell phone", "microwave ", 13 | "oven ", "toaster", "sink", "refrigerator ", "book", "clock", "vase", "scissors ", "teddy bear ", "hair drier", "toothbrush ") 14 | 15 | # decice tree for rk356x/rk3588 16 | DEVICE_COMPATIBLE_NODE = '/proc/device-tree/compatible' 17 | 18 | RK356X_RKNN_MODEL = 'models/yolov5s.rknn' 19 | RK3588_RKNN_MODEL = 'models/yolov5s-640-640.rknn' 20 | 21 | #Webcam dev /device/video0, /device/video1 etc. 22 | CAM_DEV = 0 23 | CAM_DEV2 = 2 24 | 25 | #Capture Resolution 26 | CAM_WIDTH = 1280 27 | CAM_HEIGHT = 720 28 | 29 | #Position Display 30 | D1_WIDTH = 0 31 | D1_HEIGHT = 200 32 | 33 | D2_WIDTH = 640 34 | D2_HEIGHT = 200 35 | -------------------------------------------------------------------------------- /lib/postprocess.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import lib.config as config 3 | 4 | OBJ_THRESH = config.OBJ_THRESH 5 | NMS_THRESH = config.NMS_THRESH 6 | IMG_SIZE = config.IMG_SIZE 7 | 8 | def letterbox_reverse_box(x1, y1, x2, y2, cam_width, cam_height, yolo_width, yolo_height, dw, dh): 9 | 10 | w_scale = cam_width / yolo_width 11 | h_scale = cam_height / yolo_height 12 | 13 | scale = max(w_scale, h_scale) 14 | 15 | x1 = round( scale * ((x1 - dw) + (yolo_width / 2 - dw)) - (cam_width / 2) ) 16 | y1 = round( scale * ((y1 - dh) + (yolo_height / 2 - dh)) - (cam_height / 2) ) 17 | x2 = round( scale * ((x2 - dw) + (yolo_width / 2 - dw)) - (cam_width / 2) ) 18 | y2 = round( scale * ((y2 - dh) + (yolo_height / 2 - dh)) - (cam_height / 2) ) 19 | 20 | 21 | return [x1, y1, x2, y2] 22 | 23 | def sigmoid(x): 24 | return 1 / (1 + np.exp(-x)) 25 | 26 | def xywh2xyxy(x): 27 | # Convert [x, y, w, h] to [x1, y1, x2, y2] 28 | y = np.copy(x) 29 | y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x 30 | y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y 31 | y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x 32 | y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y 33 | return y 34 | 35 | def yolov5_post_process(input_data): 36 | masks = [[0, 1, 2], [3, 4, 5], [6, 7, 8]] 37 | anchors = [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], 38 | [59, 119], [116, 90], [156, 198], [373, 326]] 39 | 40 | boxes, classes, scores = [], [], [] 41 | for input, mask in zip(input_data, masks): 42 | b, c, s = process(input, mask, anchors) 43 | b, c, s = filter_boxes(b, c, s) 44 | boxes.append(b) 45 | classes.append(c) 46 | scores.append(s) 47 | 48 | boxes = np.concatenate(boxes) 49 | boxes = xywh2xyxy(boxes) 50 | classes = np.concatenate(classes) 51 | scores = np.concatenate(scores) 52 | 53 | nboxes, nclasses, nscores = [], [], [] 54 | for c in set(classes): 55 | inds = np.where(classes == c) 56 | b = boxes[inds] 57 | c = classes[inds] 58 | s = scores[inds] 59 | 60 | keep = nms_boxes(b, s) 61 | 62 | nboxes.append(b[keep]) 63 | nclasses.append(c[keep]) 64 | nscores.append(s[keep]) 65 | 66 | if not nclasses and not nscores: 67 | return None, None, None 68 | 69 | boxes = np.concatenate(nboxes) 70 | classes = np.concatenate(nclasses) 71 | scores = np.concatenate(nscores) 72 | 73 | return boxes, classes, scores 74 | 75 | def process(input, mask, anchors): 76 | anchors = [anchors[i] for i in mask] 77 | grid_h, grid_w = map(int, input.shape[0:2]) 78 | 79 | box_confidence = sigmoid(input[..., 4]) 80 | box_confidence = np.expand_dims(box_confidence, axis=-1) 81 | 82 | box_class_probs = sigmoid(input[..., 5:]) 83 | 84 | box_xy = sigmoid(input[..., :2])*2 - 0.5 85 | 86 | col = np.tile(np.arange(0, grid_w), grid_w).reshape(-1, grid_w) 87 | row = np.tile(np.arange(0, grid_h).reshape(-1, 1), grid_h) 88 | col = col.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2) 89 | row = row.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2) 90 | grid = np.concatenate((col, row), axis=-1) 91 | box_xy += grid 92 | box_xy *= int(IMG_SIZE/grid_h) 93 | 94 | box_wh = pow(sigmoid(input[..., 2:4])*2, 2) 95 | box_wh = box_wh * anchors 96 | 97 | box = np.concatenate((box_xy, box_wh), axis=-1) 98 | 99 | return box, box_confidence, box_class_probs 100 | 101 | def nms_boxes(boxes, scores): 102 | """Suppress non-maximal boxes. 103 | 104 | # Arguments 105 | boxes: ndarray, boxes of objects. 106 | scores: ndarray, scores of objects. 107 | 108 | # Returns 109 | keep: ndarray, index of effective boxes. 110 | """ 111 | x = boxes[:, 0] 112 | y = boxes[:, 1] 113 | w = boxes[:, 2] - boxes[:, 0] 114 | h = boxes[:, 3] - boxes[:, 1] 115 | 116 | areas = w * h 117 | order = scores.argsort()[::-1] 118 | 119 | keep = [] 120 | while order.size > 0: 121 | i = order[0] 122 | keep.append(i) 123 | 124 | xx1 = np.maximum(x[i], x[order[1:]]) 125 | yy1 = np.maximum(y[i], y[order[1:]]) 126 | xx2 = np.minimum(x[i] + w[i], x[order[1:]] + w[order[1:]]) 127 | yy2 = np.minimum(y[i] + h[i], y[order[1:]] + h[order[1:]]) 128 | 129 | w1 = np.maximum(0.0, xx2 - xx1 + 0.00001) 130 | h1 = np.maximum(0.0, yy2 - yy1 + 0.00001) 131 | inter = w1 * h1 132 | 133 | ovr = inter / (areas[i] + areas[order[1:]] - inter) 134 | inds = np.where(ovr <= NMS_THRESH)[0] 135 | order = order[inds + 1] 136 | keep = np.array(keep) 137 | return keep 138 | 139 | def filter_boxes(boxes, box_confidences, box_class_probs): 140 | """Filter boxes with box threshold. It's a bit different with origin yolov5 post process! 141 | 142 | # Arguments 143 | boxes: ndarray, boxes of objects. 144 | box_confidences: ndarray, confidences of objects. 145 | box_class_probs: ndarray, class_probs of objects. 146 | 147 | # Returns 148 | boxes: ndarray, filtered boxes. 149 | classes: ndarray, classes for boxes. 150 | scores: ndarray, scores for boxes. 151 | """ 152 | boxes = boxes.reshape(-1, 4) 153 | box_confidences = box_confidences.reshape(-1) 154 | box_class_probs = box_class_probs.reshape(-1, box_class_probs.shape[-1]) 155 | 156 | _box_pos = np.where(box_confidences >= OBJ_THRESH) 157 | boxes = boxes[_box_pos] 158 | box_confidences = box_confidences[_box_pos] 159 | box_class_probs = box_class_probs[_box_pos] 160 | 161 | class_max_score = np.max(box_class_probs, axis=-1) 162 | classes = np.argmax(box_class_probs, axis=-1) 163 | _class_pos = np.where(class_max_score >= OBJ_THRESH) 164 | 165 | boxes = boxes[_class_pos] 166 | classes = classes[_class_pos] 167 | scores = (class_max_score* box_confidences)[_class_pos] 168 | 169 | return boxes, classes, scores 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /models/yolov5s-640-640.rknn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cluangar/YOLOv5-RK3588-Python/ed0d6acbd2592a17864a6c12d67bd3cbe73f2086/models/yolov5s-640-640.rknn -------------------------------------------------------------------------------- /models/yolov5s.rknn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cluangar/YOLOv5-RK3588-Python/ed0d6acbd2592a17864a6c12d67bd3cbe73f2086/models/yolov5s.rknn -------------------------------------------------------------------------------- /rknn_toolkit_lite2-1.4.0-cp39-cp39-linux_aarch64.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cluangar/YOLOv5-RK3588-Python/ed0d6acbd2592a17864a6c12d67bd3cbe73f2086/rknn_toolkit_lite2-1.4.0-cp39-cp39-linux_aarch64.whl --------------------------------------------------------------------------------