#from rknn.api import RKNN from rknnlite.api import RKNNLite import cv2 import numpy as np import cv2 import time import os from PIL import Image """ yolov5 预测脚本 for rknn """ SIZE = (640, 640) Width = 640 Height = 640 CLASSES = ("lighting") OBJ_THRESH = 0.1 NMS_THRESH = 0.1 MASKS = [[0, 1, 2], [3, 4, 5], [6, 7, 8]] ANCHORS = [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], [59, 119], [116, 90], [156, 198], [373, 326]] IMAGE_EXT = [".jpg", "*.JPG", ".jpeg", ".webp", ".bmp", ".png"] def sigmoid(x): return 1 / (1 + np.exp(-x)) def letterbox_image(image, size): iw, ih = image.size w, h = size scale = min(w / iw, h / ih) nw = int(iw * scale) nh = int(ih * scale) image = np.array(image) image = cv2.resize(image, (nw, nh), interpolation=cv2.INTER_LINEAR) image = Image.fromarray(image) new_image = Image.new('RGB', size, (128, 128, 128)) new_image.paste(image, ((w - nw) // 2, (h - nh) // 2)) return new_image def get_image_list(path): image_names = [] for maindir, subdir, file_name_list in os.walk(path): for filename in file_name_list: apath = os.path.join(maindir, filename) ext = os.path.splitext(apath)[1] if ext in IMAGE_EXT: image_names.append(apath) return image_names def filter_boxes(boxes, box_confidences, box_class_probs) -> (np.ndarray, np.ndarray, np.ndarray): box_scores = box_confidences * box_class_probs # 条件概率, 在该cell存在物体的概率的基础上是某个类别的概率 box_classes = np.argmax(box_scores, axis=-1) # 找出概率最大的类别索引 box_class_scores = np.max(box_scores, axis=-1) # 最大类别对应的概率值 pos = np.where(box_class_scores >= OBJ_THRESH) # 找出概率大于阈值的item # pos = box_class_scores >= OBJ_THRESH # 找出概率大于阈值的item boxes = boxes[pos] classes = box_classes[pos] scores = box_class_scores[pos] return boxes, classes, scores def nms_boxes(boxes, scores): x = boxes[:, 0] y = boxes[:, 1] w = boxes[:, 2] h = boxes[:, 3] areas = w * h order = scores.argsort()[::-1] keep = [] while order.size > 0: i = order[0] keep.append(i) xx1 = np.maximum(x[i], x[order[1:]]) yy1 = np.maximum(y[i], y[order[1:]]) xx2 = np.minimum(x[i] + w[i], x[order[1:]] + w[order[1:]]) yy2 = np.minimum(y[i] + h[i], y[order[1:]] + h[order[1:]]) w1 = np.maximum(0.0, xx2 - xx1 + 0.00001) h1 = np.maximum(0.0, yy2 - yy1 + 0.00001) inter = w1 * h1 ovr = inter / (areas[i] + areas[order[1:]] - inter) inds = np.where(ovr <= NMS_THRESH)[0] order = order[inds + 1] keep = np.array(keep) return keep def draw(image, boxes, scores, classes): """Draw the boxes on the image. # Argument: image: original image. boxes: ndarray, boxes of objects. classes: ndarray, classes of objects. scores: ndarray, scores of objects. all_classes: all classes name. """ labels = [] box_ls = [] for box, score, cl in zip(boxes, scores, classes): x, y, w, h = box print('class: {}, score: {}'.format(CLASSES[cl], score)) print('box coordinate left,top,right,down: [{}, {}, {}, {}]'.format(x, y, x + w, y + h)) x *= image.shape[1] y *= image.shape[0] w *= image.shape[1] h *= image.shape[0] top = max(0, np.floor(x).astype(int)) left = max(0, np.floor(y).astype(int)) right = min(image.shape[1], np.floor(x + w + 0.5).astype(int)) bottom = min(image.shape[0], np.floor(y + h + 0.5).astype(int)) print('class: {}, score: {}'.format(CLASSES[cl], score)) print('box coordinate left,top,right,down: [{}, {}, {}, {}]'.format(top, left, right, bottom)) labels.append(CLASSES[cl]) box_ls.append((top, left, right, bottom)) cv2.rectangle(image, (top, left), (right, bottom), (255, 0, 0), 2) cv2.putText(image, '{0} {1:.2f}'.format(CLASSES[cl], score), (top, left - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) return labels, box_ls def load_model0(model_path, npu_id): rknn = RKNNLite() devs = rknn.list_devices() device_id_dict = {} for index, dev_id in enumerate(devs[-1]): if dev_id[:2] != 'TS': device_id_dict[0] = dev_id if dev_id[:2] == 'TS': device_id_dict[1] = dev_id print('-->loading model : ' + model_path) rknn.load_rknn(model_path) print('--> Init runtime environment on: ' + device_id_dict[npu_id]) ret = rknn.init_runtime(device_id=device_id_dict[npu_id]) if ret != 0: print('Init runtime environment failed') exit(ret) print('done') return rknn def load_rknn_model(PATH): # Create RKNN object rknn = RKNNLite() # Load tensorflow model print('--> Loading model') ret = rknn.load_rknn(PATH) if ret != 0: print('load rknn model failed') exit(ret) print('done') #ret = rknn.init_runtime(device_id='TS018083200400178', rknn2precompile=True) ret = rknn.init_runtime() if ret != 0: print('Init runtime environment failed') exit(ret) print('done') return rknn def predict(img_src, rknn): img = cv2.resize(img_src, SIZE) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # Set inputs #image = Image.open(img_src) #img = letterbox_image(img_src, (Width, Height)) #img = np.array(img) t0 = time.time() print("img shape \t:", img.shape) pred_onx = rknn.inference(inputs=[img]) print("time: \t", time.time() - t0) boxes, classes, scores = [], [], [] for t in range(3): input0_data = sigmoid(pred_onx[t][0]) input0_data = np.transpose(input0_data, (1, 2, 0, 3)) grid_h, grid_w, channel_n, predict_n = input0_data.shape print("-------------------input0_data.shape----------------",input0_data.shape) anchors = [ANCHORS[i] for i in MASKS[t]] box_confidence = input0_data[..., 4] box_confidence = np.expand_dims(box_confidence, axis=-1) box_class_probs = input0_data[..., 5:] box_xy = input0_data[..., :2] box_wh = input0_data[..., 2:4] col = np.tile(np.arange(0, grid_w), grid_h).reshape(-1, grid_w) row = np.tile(np.arange(0, grid_h).reshape(-1, 1), grid_w) col = col.reshape((grid_h, grid_w, 1, 1)).repeat(3, axis=-2) row = row.reshape((grid_h, grid_w, 1, 1)).repeat(3, axis=-2) grid = np.concatenate((col, row), axis=-1) box_xy = box_xy * 2 - 0.5 + grid box_wh = (box_wh * 2) ** 2 * anchors box_xy /= (grid_w, grid_h) # 计算原尺寸的中心 box_wh /= SIZE # 计算原尺寸的宽高 box_xy -= (box_wh / 2.) # 计算原尺寸的xy box = np.concatenate((box_xy, box_wh), axis=-1) res = filter_boxes(box, box_confidence, box_class_probs) boxes.append(res[0]) classes.append(res[1]) scores.append(res[2]) boxes, classes, scores = np.concatenate(boxes), np.concatenate(classes), np.concatenate(scores) #print("------------------------boxes, classes, scores-----------------------",boxes, classes, scores) nboxes, nclasses, nscores = [], [], [] for c in set(classes): inds = np.where(classes == c) b = boxes[inds] c = classes[inds] s = scores[inds] keep = nms_boxes(b, s) #keep = [0,1,2] #print("--------------keep-------------",keep) nboxes.append(b[keep]) nclasses.append(c[keep]) nscores.append(s[keep]) if len(nboxes) < 1: return [], [], [] boxes = np.concatenate(nboxes) classes = np.concatenate(nclasses) scores = np.concatenate(nscores) print("------------------------boxes, classes, scores-----------------------",boxes, classes, scores) return boxes, classes, scores ''' label_list = [] box_list = [] for box, score, cl in zip(boxes, scores, classes): x, y, w, h = box x *= img_src.shape[1] y *= img_src.shape[0] w *= img_src.shape[1] h *= img_src.shape[0] top = max(0, np.floor(x).astype(int)) left = max(0, np.floor(y).astype(int)) right = min(img_src.shape[1], np.floor(x + w + 0.5).astype(int)) bottom = min(img_src.shape[0], np.floor(y + h + 0.5).astype(int)) label_list.append(CLASSES[cl]) box_list.append((top, left, right, bottom)) return label_list, np.array(box_list) ''' def draw(image, boxes, scores, classes): """Draw the boxes on the image. # Argument: image: original image. boxes: ndarray, boxes of objects. classes: ndarray, classes of objects. scores: ndarray, scores of objects. all_classes: all classes name. """ for box, score, cl in zip(boxes, scores, classes): x, y, w, h = box print('class: {}, score: {}'.format(CLASSES[cl], score)) print('box coordinate left,top,right,down: [{}, {}, {}, {}]'.format(x, y, x+w, y+h)) x *= image.shape[1] y *= image.shape[0] w *= image.shape[1] h *= image.shape[0] top = max(0, np.floor(x + 0.5).astype(int)) left = max(0, np.floor(y + 0.5).astype(int)) right = min(image.shape[1], np.floor(x + w + 0.5).astype(int)) bottom = min(image.shape[0], np.floor(y + h + 0.5).astype(int)) print('class: {}, score: {}'.format(CLASSES[cl], score)) print('box coordinate left,top,right,down: [{}, {}, {}, {}]'.format(top, left, right, bottom)) cv2.rectangle(image, (top, left), (right, bottom), (255, 0, 0), 2) cv2.putText(image, '{0} {1:.2f}'.format(CLASSES[cl], score), (top, left - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) return image def clip_coords(boxes, img_shape): # Clip bounding xyxy bounding boxes to image shape (height, width) #boxes[:, 0].clp(0, img_shape[1]) # x1 #boxes[:, 1].clp(0, img_shape[0]) # y1 #boxes[:, 2].clp(0, img_shape[1]) # x2 #boxes[:, 3].clp(0, img_shape[0]) # y2 np.clip(boxes[:, 0],0,img_shape[1]) np.clip(boxes[:, 1],0,img_shape[0]) np.clip(boxes[:, 2],0,img_shape[1]) np.clip(boxes[:, 3],0,img_shape[0]) return boxes def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): # Rescale coords (xyxy) from img1_shape to img0_shape if ratio_pad is None: # calculate from img0_shape gain = min(img1_shape[0]/img0_shape[0], img1_shape[1]/img0_shape[1]) # gain = old / new print("------------gain-----------",gain) pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding else: gain = ratio_pad[0][0] pad = ratio_pad[1] print("-----------old-coords-----------",coords) coords[:, [2]] = (coords[:, [0]] + coords[:, [2]]) * img1_shape[1] - pad[0] # x padding coords[:, [3]] = (coords[:, [1]] + coords[:, [3]]) * img1_shape[0] - pad[1] # y padding coords[:, [0]] = coords[:, [0]] * img1_shape[1] - pad[0] # x padding coords[:, [1]] = coords[:, [1]] * img1_shape[0] - pad[1] # y padding print("-----------new-coords-----------",coords) print("------------pad-----------",pad) coords[:, :4] /= gain coords = clip_coords(coords, img0_shape) return coords def display(boxes=None, classes=None, scores=None, image_src=None, input_size=(640, 640), line_thickness=None, text_bg_alpha=0.0): labels = classes boxs = boxes confs = scores h, w, c = image_src.shape if len(boxes) <= 0: return image_src boxs[:, :] = scale_coords(input_size, boxs[:, :], (h, w)).round() tl = line_thickness or round(0.002 * (w + h) / 2) + 1 for i, box in enumerate(boxs): x1, y1, x2, y2 = box ratio = (y2-y1)/(x2-x1) x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) np.random.seed(int(labels[i]) + 2020) color = (np.random.randint(0, 255), 0, np.random.randint(0, 255)) cv2.rectangle(image_src, (x1, y1), (x2, y2), color, max(int((w + h) / 600), 1), cv2.LINE_AA) label = '{0:.3f}'.format(confs[i]) t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=1)[0] c2 = x1 + t_size[0] + 3, y1 - t_size[1] - 5 if text_bg_alpha == 0.0: cv2.rectangle(image_src, (x1 - 1, y1), c2, color, cv2.FILLED, cv2.LINE_AA) else: # 透明文本背景 alphaReserve = text_bg_alpha # 0:不透明 1:透明 BChannel, GChannel, RChannel = color xMin, yMin = int(x1 - 1), int(y1 - t_size[1] - 3) xMax, yMax = int(x1 + t_size[0]), int(y1) image_src[yMin:yMax, xMin:xMax, 0] = image_src[yMin:yMax, xMin:xMax, 0] * alphaReserve + BChannel * (1 - alphaReserve) image_src[yMin:yMax, xMin:xMax, 1] = image_src[yMin:yMax, xMin:xMax, 1] * alphaReserve + GChannel * (1 - alphaReserve) image_src[yMin:yMax, xMin:xMax, 2] = image_src[yMin:yMax, xMin:xMax, 2] * alphaReserve + RChannel * (1 - alphaReserve) cv2.putText(image_src, label, (x1 + 3, y1 - 4), 0, tl / 3, [255, 255, 255], thickness=1, lineType=cv2.LINE_AA) return image_src if __name__ == '__main__': path = "./imgs/" save_folder = "./result/" #RKNN_MODEL_PATH = r"yolov5s-640-640.rknn" #RKNN_MODEL_PATH = r"best_640x640.rknn" RKNN_MODEL_PATH = r"23best_640x640.rknn" rknn = load_rknn_model(RKNN_MODEL_PATH) predict.__defaults__ = (None, rknn) files = get_image_list(path) current_time = time.localtime() for image_name in files: image_src = cv2.imread(image_name) #image_src = Image.open(image_name) boxes, classes, scores = predict(image_src) ''' image = draw(img, boxes, scores, classes) save_file_name = os.path.join(save_folder, os.path.basename(image_name)) cv2.imwrite(save_file_name,image) ''' image = np.array(image_src) save_image = display(boxes, classes, scores, image) save_image = cv2.cvtColor(save_image, cv2.COLOR_BGR2RGB) save_file_name = os.path.join(save_folder, os.path.basename(image_name)) cv2.imwrite(save_file_name,save_image) print("--------------------------res-----------------------",boxes, classes, scores)