yolov5的pt模型转化为rk3588的rknn,并在rk3588上调用api进行前向推理

当使用yolov5进行目标检测且进行边缘计算的场景时,要考虑性价比或者国产化的话,rk3588板子是个不错的选择。

本篇介绍yolov5的pytorch模型转化为rknn的流程,并展示在rk板子上如何调用相关api来使用转好的rknn模型进行前向推理。

pt转rknn流程

pt转onnx

首先将训练好的pt模型转为onnx中间模型,在转之前需要先修改主目录底下的models下的yolo.py的部分代码,将如图的forward推理部分进行注释。
在这里插入图片描述
替换为:

    def forward(self, x):
        z = []
        for i in range(self.nl):
            x[i] = self.m[i](x[i])
 
        return x

如果识别出现乱框的现象,则替换为:

    def forward(self, x):
        z = []
        for i in range(self.nl):
            x[i] = torch.sigmoid(self.m[i](x[i]))
 
        return x

记得在训练时再给他改回去,否则会报错,在转模型时才需要改这部分代码。
接下来运行export.py来转onnx:

python export.py --weights runs/train/exp/weights/best.pt --img 320 --batch 1 --include onnx

onnx转rknn

首先创建一个虚拟环境,我创建的python版本为3.8。可以直接使用pip install -r requirements.txt来创建环境;
如果出现报错,则使用conda env create -f environment.yml来创建。如果pip安装可以的话,可以直接-i换源比较方便。
这里rknn-toolkit2安装会失败是正常的,下面会手动进行安装。

*以上为直接复制我的环境,也可以根据下面的步骤来自己安装相应的包。

接下来下载RKNN-Toolkit2,可以通过官网下载,也可以通过我上传的资源下载。
下载完先进入刚才创建的环境安装rknn-toolkit2包,如图,进入packages底下,安装相关依赖:

pip install -r requirements_cp38-1.6.0.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

在这里插入图片描述
然后安装相关rknn-toolkit2包:

pip install rknn_toolkit2-1.6.0+81f21f4d-cp38-cp38-linux_x86_64.whl

*接下来进行onnx转rknn
在如图所示路径下打开test.py
在这里插入图片描述
修改相关参数
在这里插入图片描述
在这里插入图片描述
最后一个参数要改为rk3588,默认为rk3566。改完后直接运行test.py文件即可转为rknn。

rk板子上进行前向推理

因为rk3588是aarch64架构的,所以不能用rknn-toolkit2包,而是要用rknn-toolkit-lite2包,在rk上安装对应的whl:
在这里插入图片描述
代码如下:

from copy import copy
import time
import numpy as np
import cv2
from rknnlite.api import RKNNLite

RKNN_MODEL = 'best.rknn'
# IMG_PATH = './input/240513_00000741.jpg'
OBJ_THRESH = 0.25
NMS_THRESH = 0.45
IMG_SIZE = (640, 640)
OUTPUT_VIDEO_PATH = 'output_1.mp4'
BOX = (450, 150, 1100, 550)
CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
           'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
           'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
           'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
           'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
           'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
           'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
           'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
           'hair drier', 'toothbrush']

anchors = [[[10, 13], [16, 30], [33, 23]],
           [[30, 61], [62, 45], [59, 119]],
           [[116, 90], [156, 198], [373, 326]]]

class Letter_Box_Info():
    def __init__(self, shape, new_shape, w_ratio, h_ratio, dw, dh, pad_color) -> None:
        self.origin_shape = shape
        self.new_shape = new_shape
        self.w_ratio = w_ratio
        self.h_ratio = h_ratio
        self.dw = dw
        self.dh = dh
        self.pad_color = pad_color

def box_process(position, anchors):
    grid_h, grid_w = position.shape[2:4]
    col, row = np.meshgrid(np.arange(0, grid_w), np.arange(0, grid_h))  # (80, 80) (80, 80)
    col = col.reshape(1, 1, grid_h, grid_w)    # (1, 1, 80, 80)
    row = row.reshape(1, 1, grid_h, grid_w)
    grid = np.concatenate((col, row), axis=1)  # (1, 2, 80, 80)
    stride = np.array([IMG_SIZE[1]//grid_h, IMG_SIZE[0]//grid_w]).reshape(1,2,1,1)  # 8 8

    col = col.repeat(len(anchors), axis=0)
    row = row.repeat(len(anchors), axis=0)
    anchors = np.array(anchors)
    anchors = anchors.reshape(*anchors.shape, 1, 1)  # (3, 2, 1, 1)

    box_xy = position[:,:2,:,:]*2 - 0.5
    box_wh = pow(position[:,2:4,:,:]*2, 2) * anchors

    box_xy += grid
    box_xy *= stride
    box = np.concatenate((box_xy, box_wh), axis=1)   # (3, 4, 80, 80)

    # Convert [c_x, c_y, w, h] to [x1, y1, x2, y2]
    xyxy = np.copy(box)
    xyxy[:, 0, :, :] = box[:, 0, :, :] - box[:, 2, :, :]/ 2  # top left x
    xyxy[:, 1, :, :] = box[:, 1, :, :] - box[:, 3, :, :]/ 2  # top left y
    xyxy[:, 2, :, :] = box[:, 0, :, :] + box[:, 2, :, :]/ 2  # bottom right x
    xyxy[:, 3, :, :] = box[:, 1, :, :] + box[:, 3, :, :]/ 2  # bottom right y

    return xyxy
#
def filter_boxes(boxes, box_confidences, box_class_probs):
    """Filter boxes with object threshold.
    """
    box_confidences = box_confidences.reshape(-1)
    class_max_score = np.max(box_class_probs, axis=-1)
    classes = np.argmax(box_class_probs, axis=-1)


    _class_pos = np.where(class_max_score* box_confidences >= OBJ_THRESH)
    scores = (class_max_score* box_confidences)[_class_pos]

    boxes = boxes[_class_pos]
    classes = classes[_class_pos]

    return boxes, classes, scores

# def filter_boxes(boxes, box_confidences, box_class_probs):
#     """Filter boxes with object threshold.
#     """
#     boxes = boxes.reshape(-1, 4)
#     box_confidences = box_confidences.reshape(-1)
#     box_class_probs = box_class_probs.reshape(-1, box_class_probs.shape[-1])
#
#     _box_pos = np.where(box_confidences >= OBJ_THRESH)
#     boxes = boxes[_box_pos]
#     box_confidences = box_confidences[_box_pos]
#     box_class_probs = box_class_probs[_box_pos]
#
#     class_max_score = np.max(box_class_probs, axis=-1)
#     classes = np.argmax(box_class_probs, axis=-1)
#     _class_pos = np.where(class_max_score >= OBJ_THRESH)
#
#     boxes = boxes[_class_pos]
#     classes = classes[_class_pos]
#     scores = (class_max_score * box_confidences)[_class_pos]
#
#     return boxes, classes, scores

def nms_boxes(boxes, scores):
    """Suppress non-maximal boxes.
    # Returns
        keep: ndarray, index of effective boxes.
    """
    x = boxes[:, 0]
    y = boxes[:, 1]
    w = boxes[:, 2] - boxes[:, 0]
    h = boxes[:, 3] - boxes[:, 1]

    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 post_process(input_data, anchors):
    boxes, scores, classes_conf = [], [], []
    # 1*255*h*w -> 3*85*h*w
    input_data = [_in.reshape([len(anchors[0]),-1]+list(_in.shape[-2:])) for _in in input_data]
    for i in range(len(input_data)):                                    # (3, 85, 80, 80)
        boxes.append(box_process(input_data[i][:,:4,:,:], anchors[i]))  # (3, 4, 80, 80)
        scores.append(input_data[i][:,4:5,:,:])                         # (3, 1, 80, 80)
        classes_conf.append(input_data[i][:,5:,:,:])                    # (3, 80, 80, 80)

    def sp_flatten(_in):
        ch = _in.shape[1]
        _in = _in.transpose(0,2,3,1)
        return _in.reshape(-1, ch)

    boxes = [sp_flatten(_v) for _v in boxes]                  # (3, 19200, 4)
    classes_conf = [sp_flatten(_v) for _v in classes_conf]    # (3, 19200, 80)
    scores = [sp_flatten(_v) for _v in scores]                # (3, 19200, 1)

    boxes = np.concatenate(boxes)                  # (25200, 4)
    classes_conf = np.concatenate(classes_conf)    # (25200, 80)
    scores = np.concatenate(scores)                # (25200, 1)

    # filter according to threshold
    boxes, classes, scores = filter_boxes(boxes, scores, classes_conf)
    # (12, 4)  12  12

    # nms
    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)

        if len(keep) != 0:
            nboxes.append(b[keep])
            nclasses.append(c[keep])
            nscores.append(s[keep])

    if not nclasses and not nscores:
        return None, None, None

    boxes = np.concatenate(nboxes)
    classes = np.concatenate(nclasses)
    scores = np.concatenate(nscores)

    return boxes, classes, scores

def draw(image, boxes, scores, classes):
    for box, score, cl in zip(boxes, scores, classes):
        top, left, right, bottom = [int(_b) for _b in box]
        print("%s @ (%d %d %d %d) %.3f" % (CLASSES[cl], top, left, right, bottom, score))
        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)

def letterbox(im, new_shape=(640, 640), color=(0, 0, 0), letter_box_info_list=[]):
    shape = im.shape[:2]  # current shape [height, width]
    if isinstance(new_shape, int):
        new_shape = (new_shape, new_shape)

    r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])

    ratio = r  # width, height ratios
    new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
    dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  # wh padding
    # dw, dh = np.mod(dw, 32), np.mod(dh, 32)

    dw /= 2  # divide padding into 2 sides
    dh /= 2

    if shape[::-1] != new_unpad:  # resize
        im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR)
    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
    im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add border
    letter_box_info_list.append(Letter_Box_Info(shape, new_shape, ratio, ratio, dw, dh, color))
    return im, letter_box_info_list

def get_real_box(box, in_format='xyxy', letter_box_info_list=[]):
    bbox = copy(box)
    # unletter_box result
    if in_format=='xyxy':
        bbox[:,0] -= letter_box_info_list[-1].dw
        bbox[:,0] /= letter_box_info_list[-1].w_ratio
        bbox[:,0] = np.clip(bbox[:,0], 0, letter_box_info_list[-1].origin_shape[1])

        bbox[:,1] -= letter_box_info_list[-1].dh
        bbox[:,1] /= letter_box_info_list[-1].h_ratio
        bbox[:,1] = np.clip(bbox[:,1], 0, letter_box_info_list[-1].origin_shape[0])

        bbox[:,2] -= letter_box_info_list[-1].dw
        bbox[:,2] /= letter_box_info_list[-1].w_ratio
        bbox[:,2] = np.clip(bbox[:,2], 0, letter_box_info_list[-1].origin_shape[1])

        bbox[:,3] -= letter_box_info_list[-1].dh
        bbox[:,3] /= letter_box_info_list[-1].h_ratio
        bbox[:,3] = np.clip(bbox[:,3], 0, letter_box_info_list[-1].origin_shape[0])
    return bbox


if __name__ == '__main__':
    rknn = RKNNLite()

    print('--> Load RKNN model')
    ret = rknn.load_rknn(RKNN_MODEL)
    if ret != 0:
        print('Load RKNN model failed')
        exit(ret)
    print('done')
    ret = rknn.init_runtime()
    if ret != 0:
        print('Init runtime environment failed!')
        exit(ret)
    print('done')

    cap = cv2.VideoCapture("./input/out_240715151339.mp4")

    # 获取视频的一些属性
    fps = cap.get(cv2.CAP_PROP_FPS)
    # width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    # height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    # 创建 VideoWriter 对象
    x, y, w, h = BOX
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')  # 或者使用 'XVID'
    out = cv2.VideoWriter(OUTPUT_VIDEO_PATH, fourcc, fps, (w, h))

    fps = 0.0
    while True:
        t1 = time.time()
        # 读取一帧
        ret, frame = cap.read()
        if not ret:
            break

        # 加载帧
        img0 = frame[y:y+h, x:x+w, :]

        img_size = (640, 640)
        img, letter_box_info_list = letterbox(im= img0.copy(), new_shape=(IMG_SIZE[1], IMG_SIZE[0]))  # padded resize

        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # HWC to CHW, BGR to RGB

        if len(img.shape) == 3:
            img = img[None]  # expand for batch dim

        outputs = rknn.inference(inputs=[img])  # Inference

        boxes, classes, scores = post_process(outputs, anchors)
        boxes_filter, scores_filter, classes_filter = [0, 0, 0, 0], [], []
        max_box = [0, 0, 0, 0]
        for box, score, cl in zip(boxes, scores, classes):
            if cl == 0:
                if (box[2]-box[0])*(box[3]-box[1]) > (max_box[2]-max_box[0])*(max_box[3]-max_box[1]):
                    max_box = box
                    boxes_filter = np.expand_dims(max_box, axis=0)
                    scores_filter = np.expand_dims(score, axis=0)
                    classes_filter = np.expand_dims(cl, axis=0)
        img_p = img0.copy()

        draw(img_p, get_real_box(boxes_filter, 'xyxy', letter_box_info_list), scores_filter, classes_filter)
        cv2.imwrite("11.jpg", img_p)
        out.write(img_p)

    cap.release()
    out.release()
    rknn.release()

这里我是输入视频,输出一帧一帧的图片来查看,可以自行改变输入输出的格式。
后续再补充实现npu进行加速。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/924983.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

家校通小程序实战教程03学生管理

目录 1 创建数据源2 搭建后台功能3 设置主列字段4 批量导入数据5 设置查询条件6 实现查询和重置总结 我们现在已经搭建了班级管理&#xff0c;并且录入了班级口令。之后就是加入班级的功能了。这里分为老师加入班级和学生家长加入班级。 如果是学生家长的话&#xff0c;在加入之…

题目 3209: 蓝桥杯2024年第十五届省赛真题-好数

一个整数如果按从低位到高位的顺序&#xff0c;奇数位&#xff08;个位、百位、万位 &#xff09;上的数字是奇数&#xff0c;偶数位&#xff08;十位、千位、十万位 &#xff09;上的数字是偶数&#xff0c;我们就称之为“好数”。给定一个正整数 N&#xff0c;请计算从…

ASP.NET Core Web API 控制器

文章目录 一、基类&#xff1a;ControllerBase二、API 控制器类属性三、使用 Get() 方法提供天气预报结果 在深入探讨如何编写自己的 PizzaController 类之前&#xff0c;让我们先看一下 WeatherController 示例中的代码&#xff0c;了解它的工作原理。 在本单元中&#xff0c;…

scrapy豆瓣爬虫增强-批量随机请求头

1.1 豆瓣爬虫增强,中间件随机请求头 1.2 清除原有的中间件,进行中间件测试 1.3 导入全新的中间件 1.4 运行爬虫,这个时候的请求头是固定的 1.5 强化对agent的输出,会舍弃输出cookie,使输出更明了 1.6 转移输出请求头位置 新增输出 造成这样问题的原因是Douban/Douban/settings…

三维地形图计算软件(三)-原基于PYQT5+pyqtgraph旧代码

最先入手设计三维地形图及平基挖填方计算软件时&#xff0c;地形图的显示方案是&#xff1a;三维视图基于pyqtgraph.opengl显示和二维视图基于pyqtgraph的PlotWidget来显示地形地貌&#xff0c;作到一半时就发现&#xff0c;地形点过多时&#xff0c;将会造成系统卡顿(加载时主…

累积局部效应 (ALE) 图分析记录

Git地址&#xff1a;https://github.com/blent-ai/ALEPython/tree/dev 查看源码需要pip install alepython安装&#xff0c;这边查看源码发现就实际就一个py文件而已&#xff0c;我懒得再去安装&#xff0c;故直接下载源码&#xff0c;调用方法也可&#xff1b; # -*- coding:…

浅谈网络 | 应用层之HTTP协议

目录 HTTP 请求的准备HTTP 请求的构建HTTP 请求的发送过程HTTP 返回的构建HTTP 2.0QUIC 协议HTTP 3.0 在讲完传输层之后&#xff0c;我们接下来进入应用层的内容。应用层的协议种类繁多&#xff0c;那从哪里开始讲起呢&#xff1f;不妨从我们最常用、最熟悉的 HTTP 协议 开始。…

qt5.14.2跟vs2022配置

1.qt6要在线安装&#xff0c;安装时间比较长&#xff0c;要求网络要稳定&#xff0c;不适合快速安装 2.使用qt5.14.2离线安装包&#xff0c;安装速度快&#xff0c;可以快速安装。 3.安装完qt.5.14.2后打开QtCreate4.0.1&#xff0c;打开 工具->选项->Kits,发现如下图: 没…

华为海思2025届校招笔试面试经验分享

目前如果秋招还没有offer的同学&#xff0c;可以赶紧投递下面这些公司&#xff0c;都在补招。争取大家年前就把后端offer拿下。如果大家在准备秋招补录取过程中有任何问题&#xff0c;都可以私信小编&#xff0c;免费提供帮助。如果还有部分准备备战春招的同学&#xff0c;也可…

超详细ensp配置VRRP和MSTP协议

一、简介 1、什么是VRRP&#xff1a; &#xff08;1&#xff09;VRRP&#xff08;Virtual Router Redundancy Protocol&#xff09;的概念&#xff1a; VRRP&#xff08;Virtual Router Redundancy Protocol&#xff09;指的是一种实现路由器冗余备份的协议&#xff0c;常用于…

linux基础2

声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&#…

SAAS美容美发系统架构解析

随着技术的不断发展&#xff0c;SAAS&#xff08;Software as a Service&#xff0c;软件即服务&#xff09;模式在各个行业的应用逐渐深化&#xff0c;美容美发行业也不例外。传统的美容美发店面通常依赖纸质记录、手动操作和复杂的管理流程&#xff0c;而随着SAAS平台的出现&…

和数集团业务说明会(南京站)顺利举办

2024年11月24日&#xff0c;上海和数集团业务说明会&#xff08;南京站&#xff09;&#xff0c;在南京希尔顿酒店成功举办。 和数集团董事长兼总经理唐毅先生&#xff0c;以其敏锐的行业洞察力和丰富的实践经验&#xff0c;向与会者分享了和数集团在区块链领域的丰厚研究成果和…

微积分复习笔记 Calculus Volume 1 - 6.9 Calculus of the Hyperbolic Functions

6.9 Calculus of the Hyperbolic Functions - Calculus Volume 1 | OpenStax

MCU跨领域融合的风向标是什么?

【哔哥哔特导读】从市场竞争的加剧到技术发展的需求&#xff0c;从智能化趋势到安全性要求的提高&#xff0c;再到市场需求的变化&#xff0c;这些因素共同推动了MCU趋势的发展&#xff0c;那么&#xff0c;当前的发展方向是怎样的&#xff1f; 随着技术的飞速发展和市场需求的…

使用ENSP实现OSPF

一、项目拓扑 二、项目实现 1.路由器AR1配置 进入系统试图 sys将路由器命名为R1 sysname R1关闭信息中心 undo info-center enable 进入g0/0/0接口 int g0/0/0将g0/0/0接口IP地址配置为1.1.1.1/24 ip address 1.1.1.1 24进入g0/0/1接口 int g0/0/1将g0/0/1接口IP地址配置为2…

1、Three.js开端准备环境

准备工作 从 CDN 导入 1.安装 VSCode 2.安装 Node.js 3.查看Three.js最新版本 4.如何cdn引入&#xff1a; https://cdn.jsdelivr.net/npm/threev版本号/build/three.module.js 例如&#xff1a;https://cdn.jsdelivr.net/npm/threev0.170.0/build/three.module.js 我们需要…

【HTTP】http与https

http与https的关系 应用层协议&#xff1a; http&#xff08;HyperText Transfer Protocol&#xff09;超文本传输协议&#xff1b; https&#xff08;Hypertext Transfer Protocol Secure&#xff09;超文本传输安全协议&#xff1b; 传输层协议&#xff1a;TCP&#xff08;Tr…

百度 文心一言 vs 阿里 通义千问 哪个好?

背景介绍&#xff1a; 在当前的人工智能领域&#xff0c;随着大模型技术的快速发展&#xff0c;市场上涌现出了众多的大规模语言模型。然而&#xff0c;由于缺乏统一且权威的评估标准&#xff0c;很多关于这些模型能力的文章往往基于主观测试或自行设定的排行榜来评价模型性能…

MySQL聚合查询分组查询联合查询

#对应代码练习 -- 创建考试成绩表 DROP TABLE IF EXISTS exam; CREATE TABLE exam ( id bigint, name VARCHAR(20), chinese DECIMAL(3,1), math DECIMAL(3,1), english DECIMAL(3,1) ); -- 插入测试数据 INSERT INTO exam (id,name, chinese, math, engli…