TRT4-trt-integrate - 3 使用onnxruntime进行onnx的模型推理过程

news2024/11/17 15:47:59

前言:

  • onnx是microsoft开发的一个中间格式,而onnxruntime简称ort是microsoft为onnx开发的推理引擎。
  • 允许使用onnx作为输入进行直接推理得到结果。

py接口的推理过程:

 main函数:


if __name__ == "__main__":

    session = onnxruntime.InferenceSession("workspace/yolov5s.onnx", providers=["CPUExecutionProvider"])#建立一个InferenceSession,塞进去的是onnx的路径实际运算

    image = cv2.imread("workspace/car.jpg")
    image_input, M, IM = preprocess(image)
    pred = session.run(["output"], {"images": image_input})[0]
    boxes = post_process(pred, IM)

    for obj in boxes:
        left, top, right, bottom = map(int, obj[:4])
        confidence = obj[4]
        label = int(obj[6])
        cv2.rectangle(image, (left, top), (right, bottom), (0, 255, 0), 2)
        cv2.putText(image, f"{label}: {confidence:.2f}", (left, top+20), 0, 1, (0, 0, 255), 2, 16)

    cv2.imwrite("workspace/python-ort.jpg", image)
 session = onnxruntime.InferenceSession("workspace/yolov5s.onnx", providers=["CPUExecutionProvider"])

建立一个InferenceSession,塞进去的是onnx的路径,实际运算的后端选用的是CPU

也可以选用cuda等等

    image = cv2.imread("workspace/car.jpg")
    image_input, M, IM = preprocess(image)

之后就是预处理

    pred = session.run(["output"], {"images": image_input})[0]
    boxes = post_process(pred, IM)

session.run就是运行的inference过程

 输入第一个是output的name,决定了哪几个节点作为输出,就将这个名字传递给他

第二个是input的dict,这个意思就是如果有好多个输入,那应该是将名字与输入进行一一对应,比如"input1 ":input1  ,   "input2":input2....

那么在这里output就是一个输出的list,然后我们取第0项

就是这个样子。

预处理:


def preprocess(image, input_w=640, input_h=640):
    scale = min(input_h / image.shape[0], input_w / image.shape[1])
    ox = (-scale * image.shape[1] + input_w + scale  - 1) * 0.5
    oy = (-scale * image.shape[0] + input_h + scale  - 1) * 0.5
    M = np.array([
        [scale, 0, ox],
        [0, scale, oy]
    ], dtype=np.float32)
    IM = cv2.invertAffineTransform(M)

    image_prep = cv2.warpAffine(image, M, (input_w, input_h), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=(114, 114, 114))
    image_prep = (image_prep[..., ::-1] / 255.0).astype(np.float32)
    image_prep = image_prep.transpose(2, 0, 1)[None]
    return image_prep, M, IM

 

后处理:

def nms(boxes, threshold=0.5):

    keep = []
    remove_flags = [False] * len(boxes)
    for i in range(len(boxes)):

        if remove_flags[i]:
            continue

        ib = boxes[i]
        keep.append(ib)
        for j in range(len(boxes)):
            if remove_flags[j]:
                continue

            jb = boxes[j]

            # class mismatch or image_id mismatch
            if ib[6] != jb[6] or ib[5] != jb[5]:
                continue

            cleft,  ctop    = max(ib[:2], jb[:2])
            #例子:
            #将 ib 的前两个元素 [2, 3] 与 jb 的前两个元素 [4, 1] 进行比较,并取其中较大的值。所以结果是 [4, 3]。
            cright, cbottom = min(ib[2:4], jb[2:4])
            cross = max(0, cright - cleft) * max(0, cbottom - ctop)
            union = max(0, ib[2] - ib[0]) * max(0, ib[3] - ib[1]) + max(0, jb[2] - jb[0]) * max(0, jb[3] - jb[1]) - cross
            iou = cross / union
            if iou >= threshold:
                remove_flags[j] = True
    return keep

def post_process(pred, IM, threshold=0.25):

    # b, n, 85
    boxes = []
    for image_id, box_id in zip(*np.where(pred[..., 4] >= threshold)):
        item = pred[image_id, box_id]
        cx, cy, w, h, objness = item[:5]
        label = item[5:].argmax()
        confidence = item[5 + label] * objness
        if confidence < threshold:
            continue

        boxes.append([cx - w * 0.5, cy - h * 0.5, cx + w * 0.5, cy + h * 0.5, confidence, image_id, label])

    boxes = np.array(boxes)
    lr = boxes[:, [0, 2]]
    tb = boxes[:, [1, 3]]
    boxes[:, [0, 2]] = lr * IM[0, 0] + IM[0, 2]
    boxes[:, [1, 3]] = tb * IM[1, 1] + IM[1, 2]

    # left, top, right, bottom, confidence, image_id, label
    boxes = sorted(boxes.tolist(), key=lambda x:x[4], reverse=True)
    return nms(boxes)

 我们可以发现,真正的onnxruntime只有两行,一个onnxruntime.InferenceSession,一个run就结束了。其余的都是和之前一样的,这是非常好用便捷的,所以如果有模型需要作测试,是非常推荐用onnxruntime的

CPP接口推理过程:

Inference:

在main函数中只有一个inference


int main(){
    inference();
    return 0;
}

所以我们直接来到inference的解读中

 auto engine_data = load_file("yolov5s.onnx");
//读onnx文件
    Ort::Env env(ORT_LOGGING_LEVEL_INFO, "onnx");
//设置打印的日志级别    
    Ort::SessionOptions session_options;
//定义sessionoptions 类似于python中的    session =     onnxruntime.InferenceSession("workspace/yolov5s.onnx", providers=["CPUExecutionProvider"])

    auto mem = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
//设置MemoryInfo
    session_options.SetIntraOpNumThreads(1);
    session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
//启动一些扩展
    Ort::Session session(env, "yolov5s.onnx", session_options);
    //创建session,将选项传进去
    auto output_dims = session.GetOutputTypeInfo(0).GetTensorTypeAndShapeInfo().GetShape();
    //获取output的shape
    const char *input_names[] = {"images"}, *output_names[] = {"output"};
    int input_batch = 1;
    int input_channel = 3;
    int input_height = 640;
    int input_width = 640;
    int64_t input_shape[] = {input_batch, input_channel, input_height, input_width};
    int input_numel = input_batch * input_channel * input_height * input_width;
    float* input_data_host = new float[input_numel];
    auto input_tensor = Ort::Value::CreateTensor(mem, input_data_host, input_numel, input_shape, 4);
    //创建一个Tensor,引用input_data_host中的数据

预处理:


    ///
    // letter box
    auto image = cv::imread("car.jpg");
    float scale_x = input_width / (float)image.cols;
    float scale_y = input_height / (float)image.rows;
    float scale = std::min(scale_x, scale_y);
    float i2d[6], d2i[6];
    i2d[0] = scale;  i2d[1] = 0;  i2d[2] = (-scale * image.cols + input_width + scale  - 1) * 0.5;
    i2d[3] = 0;  i2d[4] = scale;  i2d[5] = (-scale * image.rows + input_height + scale - 1) * 0.5;

    cv::Mat m2x3_i2d(2, 3, CV_32F, i2d);
    cv::Mat m2x3_d2i(2, 3, CV_32F, d2i);
    cv::invertAffineTransform(m2x3_i2d, m2x3_d2i);

    cv::Mat input_image(input_height, input_width, CV_8UC3);
    cv::warpAffine(image, input_image, m2x3_i2d, input_image.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar::all(114));
    cv::imwrite("input-image.jpg", input_image);

    int image_area = input_image.cols * input_image.rows;
    unsigned char* pimage = input_image.data;
    float* phost_b = input_data_host + image_area * 0;
    float* phost_g = input_data_host + image_area * 1;
    float* phost_r = input_data_host + image_area * 2;
    for(int i = 0; i < image_area; ++i, pimage += 3){
        // 注意这里的顺序rgb调换了
        *phost_r++ = pimage[0] / 255.0f;
        *phost_g++ = pimage[1] / 255.0f;
        *phost_b++ = pimage[2] / 255.0f;
    }
    ///

制作输出矩阵并运行:

    // 3x3输入,对应3x3输出
    int output_numbox = output_dims[1];
    int output_numprob = output_dims[2];
    int num_classes = output_numprob - 5;
    int output_numel = input_batch * output_numbox * output_numprob;
    float* output_data_host = new float[output_numel];
    int64_t output_shape[] = {input_batch, output_numbox, output_numprob};
    auto output_tensor = Ort::Value::CreateTensor(mem, output_data_host, output_numel, output_shape, 3);

    Ort::RunOptions options;
    session.Run(options, 
        (const char* const*)input_names, &input_tensor, 1, 
        (const char* const*)output_names, &output_tensor, 1
    );
//指定输入输出的name,tensor和个数,传入tensor进行推理

后处理:

 // decode box
    vector<vector<float>> bboxes;
    float confidence_threshold = 0.25;
    float nms_threshold = 0.5;
    for(int i = 0; i < output_numbox; ++i){
        float* ptr = output_data_host + i * output_numprob;
        float objness = ptr[4];
        if(objness < confidence_threshold)
            continue;

        float* pclass = ptr + 5;
        int label     = std::max_element(pclass, pclass + num_classes) - pclass;
        float prob    = pclass[label];
        float confidence = prob * objness;
        if(confidence < confidence_threshold)
            continue;

        float cx     = ptr[0];
        float cy     = ptr[1];
        float width  = ptr[2];
        float height = ptr[3];
        float left   = cx - width * 0.5;
        float top    = cy - height * 0.5;
        float right  = cx + width * 0.5;
        float bottom = cy + height * 0.5;
        float image_base_left   = d2i[0] * left   + d2i[2];
        float image_base_right  = d2i[0] * right  + d2i[2];
        float image_base_top    = d2i[0] * top    + d2i[5];
        float image_base_bottom = d2i[0] * bottom + d2i[5];
        bboxes.push_back({image_base_left, image_base_top, image_base_right, image_base_bottom, (float)label, confidence});
    }
    printf("decoded bboxes.size = %d\n", bboxes.size());

    // nms
    std::sort(bboxes.begin(), bboxes.end(), [](vector<float>& a, vector<float>& b){return a[5] > b[5];});
    std::vector<bool> remove_flags(bboxes.size());
    std::vector<vector<float>> box_result;
    box_result.reserve(bboxes.size());

    auto iou = [](const vector<float>& a, const vector<float>& b){
        float cross_left   = std::max(a[0], b[0]);
        float cross_top    = std::max(a[1], b[1]);
        float cross_right  = std::min(a[2], b[2]);
        float cross_bottom = std::min(a[3], b[3]);

        float cross_area = std::max(0.0f, cross_right - cross_left) * std::max(0.0f, cross_bottom - cross_top);
        float union_area = std::max(0.0f, a[2] - a[0]) * std::max(0.0f, a[3] - a[1]) 
                         + std::max(0.0f, b[2] - b[0]) * std::max(0.0f, b[3] - b[1]) - cross_area;
        if(cross_area == 0 || union_area == 0) return 0.0f;
        return cross_area / union_area;
    };

    for(int i = 0; i < bboxes.size(); ++i){
        if(remove_flags[i]) continue;

        auto& ibox = bboxes[i];
        box_result.emplace_back(ibox);
        for(int j = i + 1; j < bboxes.size(); ++j){
            if(remove_flags[j]) continue;

            auto& jbox = bboxes[j];
            if(ibox[4] == jbox[4]){
                // class matched
                if(iou(ibox, jbox) >= nms_threshold)
                    remove_flags[j] = true;
            }
        }
    }
    printf("box_result.size = %d\n", box_result.size());

    for(int i = 0; i < box_result.size(); ++i){
        auto& ibox = box_result[i];
        float left = ibox[0];
        float top = ibox[1];
        float right = ibox[2];
        float bottom = ibox[3];
        int class_label = ibox[4];
        float confidence = ibox[5];
        cv::Scalar color;
        tie(color[0], color[1], color[2]) = random_color(class_label);
        cv::rectangle(image, cv::Point(left, top), cv::Point(right, bottom), color, 3);

        auto name      = cocolabels[class_label];
        auto caption   = cv::format("%s %.2f", name, confidence);
        int text_width = cv::getTextSize(caption, 0, 1, 2, nullptr).width + 10;
        cv::rectangle(image, cv::Point(left-3, top-33), cv::Point(left + text_width, top), color, -1);
        cv::putText(image, caption, cv::Point(left, top-5), 0, 1, cv::Scalar::all(0), 2, 16);
    }
    cv::imwrite("image-draw.jpg", image);

    delete[] input_data_host;
    delete[] output_data_host;
}

小结:

可以看到,这个与我们之前yolov5后处理没什么太大的区别,关键只在于对于output_tensor和output作关联,input_tensor和input作关联。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Faiss简单使用

Faiss是Facebook AI Research开发的快速相似性搜索&#xff08;similarity search&#xff09;计算库&#xff0c;为稠密向量提供高效相似度搜索和聚类&#xff0c;支持十亿级别向量的搜索。 Faiss 的核心原理是基于向量索引和近似最近邻搜索。它通过构建索引结构来加速相似性…

android9-android13 AMS演进初窥

目录 一&#xff1a;概览 WindowManagerService 基本介绍 ActivityManagerService 基本介绍 二&#xff1a;AMS及其关联的WMS中主要组件的类图和对像图 一&#xff1a;android 9中AMS/WMS的类图和对像图 二&#xff1a;android 10中AMS/WMS的类图和对像图 三&#xff1a…

怎么给图片去底色?这几个方法一定要知道

如果你是一位设计师或者是需要制作图片的人&#xff0c;那么你一定知道去除图片底色的重要性。无论是制作海报、广告、产品图片还是网站页面&#xff0c;去除图片底色可以让你的设计更加精细、美观、专业。在本文中&#xff0c;我们将介绍三种常见的图片去底色方法&#xff0c;…

p7付费课程笔记5:串行gc以及并行gc

前言 前段时间我们学习jvm的基础结构和gc相关的基础知识&#xff0c;今天我们详细讲讲几大gc。 串行gc 串行 GC 对年轻代使用 mark-copy (标记-复制) 算法&#xff0c;对老年代使用 mark-sweep-compact (标记-清除-整理) 算法。 两者都是单线程的垃圾收集器&#xff0c;不能…

百度AI成为移动生态强者的真相

移动互联网的发展&#xff0c;让移动生态成为了互联网企业竞争的重要战场。在这场竞争中&#xff0c;百度AI凭借着其优质的技术实力和完善的生态系统&#xff0c;成为了移动生态中的强者。 那么&#xff0c;百度AI究竟靠什么成为了强者呢&#xff1f;首先&#xff0c;百度AI的技…

网络安全/黑客零基础入门(经验分享)

相关网站推荐 博主研究方向为安全领域&#xff0c;以后可能更多的在圈子内发表文章&#xff0c;提高文章质量。 1、FreeBuf 国内关注度最高的全球互联网安全媒体平台&#xff0c;爱好者们交流与分享安全技术的社区&#xff0c;网络安全行业门户。 2、看雪 看雪论坛是个软件…

GB/T 25000.51解读——软件产品的兼容性怎么测?

GB/T 25000.51-2016《软件产品质量要求和测试细则》是申请软件检测CNAS认可一定会用到的一部国家标准。在前面的文章中&#xff0c;我们为大家整体介绍了GB/T 25000.51-2016《软件产品质量要求和测试细则》国家标准的结构和所涵盖的内容以及对软件产品的八大质量特性中的功能性…

Failed to load local font resource:微信小程序加载第三方字体

加载本地字体.ttf 将ttf转换为base64格式&#xff1a;https://transfonter.org/ 步骤如下 将下载后的stylesheet.css 里的font-family属性名字改一下&#xff0c;然后引进页面里就行了&#xff0c;全局样式就放app.scss&#xff0c;单页面就引入单页面 注&#xff1a; .title…

Jmeter+MySQL链接+JDBC Connection配置元件+使用

参考大大的博客学习&#xff1a;怎么用JMeter操作MySQL数据库&#xff1f;看完秒懂&#xff01;_jmeter mysql_程序员馨馨的博客-CSDN博客 注&#xff1a;里面所有没打码的都是假数据&#xff0c;麻烦大家自行修改正确的信息。 一、背景 需要取数据库中的值&#xff0c;作为…

html2Canvas+jsPDF 下载PDF 遇到跨域的对象存储的图片无法显示

一、问题原因 对象存储的域名和你网址的域名不一样&#xff0c;此时用Canvas相关插件 将DOM元素转化为PDF&#xff0c;就会出现跨域错误。 二、解决办法 两步 1. 图片元素上设置属性 crossorigin"anonymous" 支持原生img和eleme组件 2. 存储桶设置资源跨域访问…

盘点!项目管理软件排行榜前十名

如今企业规模不断扩大&#xff0c;业务逐渐复杂化&#xff0c;项目管理已经成为现代企业管理中不可或缺的一环。作为协调管理者、团队成员和客户之间交流的工具&#xff0c;项目管理软件不仅可以提高工作效率&#xff0c;还可以提高项目成功的几率&#xff0c;对于企业具有重要…

[小尘送书-第二期]《从零开始读懂量子力学》由浅入深,解释科学原理;从手机到超导,量子无处不在;从微观到宏观,遐想人生的意义!

大家好&#xff0c;我是小尘&#xff0c;欢迎关注&#xff0c;一起交流学习&#xff01;欢迎大家在CSDN后台私信我&#xff01;一起讨论学习&#xff0c;讨论如何找到满意的工作&#xff01; 本文目录 一、前言二、作者简介三、内容简介四、抽奖方式五、名家推介写在最后 一、前…

Linux使用教程

一、Linux命令基础 1、ls、ll命令——展示数据 ①ls命令——平铺展示数据 其中ls命令以平铺的方式展现数据 ②ll命令——列表展示数据 ll命令以列表的方式展现数据 -a选项&#xff0c;表示&#xff1a;all的意思&#xff0c;即列出全部文件&#xff08;包含隐藏的文件/文件夹…

【Vue】div标签实现输入框,利用contenteditable=“true“属性的标签实现

推荐个链接&#x1f517;&#xff0c;可以更好的查阅自己遇到的问题&#xff08;点击此处即可跳转&#xff09; 使用 div 实现 input、textarea 输入框 <template><div class"content"><div class"main editTextList" ><divclass&q…

[c++实验] 快读快写,O123优化,原版用时对比

前言 学过c的多知道&#xff0c;准确的来说是做过c题目的都知道&#xff1a;c题目不仅要求代码正确&#xff0c;还要求用时&#xff0c;大多用时要求都在200ms--1000ms之间&#xff0c;要是遇到大数据时&#xff0c;超时的可能就会大大提升。 结论 用时的把控也很重要&#…

网站实现下载apk安装包

目录 1、背景说明2、效果图3、具体实现3.1 界面代码3.2 js代码 4、说明4.1 存在异常4.2 解决方案 5、参考资料 1、背景说明 有时需要将写好的apk安装包在局域网内部进行发布&#xff0c;具体实现非常简单&#xff0c;如下所示 2、效果图 进入到网站后&#xff0c;点击下载按…

正确认识:2374782-02-0,FAPI-4,成纤维细胞活化蛋白抑制剂

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ PART1----试剂基础信息​​ 【中文名称】成纤维细胞活化蛋白抑制剂 【英文名称】 FAPI-4 【结 构 式】 【CAS】2374782-02-0 【分子式】C40H54F2N10O10 【分子量】872.93 【沸点】1144.165.0 C(Predicted) 【密度】1.460.…

【力扣周赛】第 355 场周赛(构造二分答案异或前缀 状态压缩⭐)

文章目录 Q1&#xff1a;6921. 按分隔符拆分字符串&#xff08;双指针&#xff09;Q2&#xff1a;6915. 合并后数组中的最大元素&#xff08;倒序遍历贪心&#xff09;代码优化 Q3&#xff1a;6955. 长度递增组的最大数目&#x1f6b9;&#x1f6b9;&#x1f6b9;&#x1f6b9;…

企业级PaaS低代码快开平台源码,基于 Salesforce Platform 的开源替代方案

PaaS低代码快开平台是一种快速开发应用系统的工具&#xff0c;用户通过少量代码甚至不写代码就可以快速构建出各种应用系统。 随着信息化技术的发展&#xff0c;企业对信息化开发的需求正在逐渐改变&#xff0c;传统的定制开发已经无法满足企业需求。低代码开发平台&#xff0…

ElementUI tabs标签页样式改造美化

今天针对ElementUI的Tabs标签页进行了样式修改&#xff0c;更改为如下图所属的样子。 在线运行地址&#xff1a;JSRUN项目-ElementUI tabs标签页样式改造 大家如果有需要可以拿来修改使用&#xff0c;下面我也简单的贴上代码&#xff0c;代码没有注释&#xff0c;很抱歉&#x…