yolov8多batch推理,nms后处理

0. 背景

在高速公路监控视频场景下,图像分辨率大都是1920 * 1080或者2560 * 1440,远处的物体(车辆和行人等)都比较小。考虑需要对图像进行拆分,然后把拆分后的数据统一送入模型中,推理的结果然后再做nms,恢复到原始图片数据中。
这个过程中牵涉到两个方面的内容,一个是多batch推理,一个是nms。

1. 多batch

例如使用1920*1080分辨率的图片数据,把该分辨率的数据分为4份。
如果只是平均分车4份,当一个物体(比如车辆)正好处于图片中心时,则可能被拆分到4个区域,这样当后续这4个区域分别得到检测框后,无法对同一个拆分的物体进行完美覆盖。所以在拆分图片是,可用适当的大一些。

1.1 平均拆分

在这里插入图片描述

1.2 建议拆分

在这里插入图片描述
例如:1920*1080分辨率的图片,进行拆分

	h1 = int(1080 * 7 / 16) h2 = int(1080 * 9 / 16) w1 = int(1920 * 7 / 16)w2 = int(1920 * 9 / 16)img0 = frame[0:h_2, 0:w_2].copy()img1 = frame[0:h_2, w_1:w].copy()img2 = frame[h_1:h, 0:w_2].copy()img3 = frame[h_1:h, w_1:w].copy()

2. yolov8中多batch推理的方式

因为刚使用yolov8不久,推理过程中的数据加载逻辑重新梳理了一下,做个记录

1)推理调用入口
results = model(source=frame, save=False, conf=conf, iou=nms, save_txt=False,show=False)
2)model定义
model = YOLO(MODEL)
3)YOLO类 (ultralytics/models/yolo/model.py)
from ultralytics import YOLO
class YOLO(Model):
4) Model基类
class Model(nn.Module):
(4.1)super().__init__()self._load(model, task)
(4.2)def __call__(self, source=None, stream=False, **kwargs):"""Calls the 'predict' function with given arguments to perform object detection."""return self.predict(source, stream, **kwargs)
(4.3)def predict(self, source=None, stream=False, predictor=None, **kwargs):if not self.predictor:self.predictor = (predictor or self._smart_load('predictor'))(overrides=args, _callbacks=self.callbacks)self.predictor.setup_model(model=self.model, verbose=is_cli)
(4.4)def _smart_load(self, key):"""Load model/trainer/validator/predictor."""try:return self.task_map[self.task][key] #detect\predictor# 根据(3)中YOLO类中的task_mape'detect': {'model': DetectionModel,'trainer': yolo.detect.DetectionTrainer,'validator': yolo.detect.DetectionValidator,'predictor': yolo.detect.DetectionPredictor, },	#	调用接口为yolo.detect.DetectionPredictor   
5)class DetectionPredictor(BasePredictor)
6)BasePredictor#因为DetectionPredictor中只有后处理的方式,数据预处理的内容在BasePredictor基类中
(6.1)def __call__(self, source=None, model=None, stream=False, *args, **kwargs):"""Performs inference on an image or stream."""self.stream = streamif stream:return self.stream_inference(source, model, *args, **kwargs)else:return list(self.stream_inference(source, model, *args, **kwargs))  # merge list of Result into one    
(6.2)def stream_inference(self, source=None, model=None, *args, **kwargs):# Setup source every time predict is calledself.setup_source(source if source is not None else self.args.source) 
(6.3)def setup_source(self, source):self.dataset = load_inference_source(source=source,imgsz=self.imgsz,vid_stride=self.args.vid_stride,buffer=self.args.stream_buffer)
7) 数据处理方式
from ultralytics.data import load_inference_source 
def load_inference_source(source=None, imgsz=640, vid_stride=1, buffer=False):    dataset = LoadPilAndNumpy(source, imgsz=imgsz)8)最终的数据处理
class LoadPilAndNumpy:def __init__(self, im0, imgsz=640):"""Initialize PIL and Numpy Dataloader."""if not isinstance(im0, list):im0 = [im0]self.paths = [getattr(im, 'filename', f'image{i}.jpg') for i, im in enumerate(im0)]self.im0 = [self._single_check(im) for im in im0]#print(self.im0)self.imgsz = imgszself.mode = 'image'# Generate fake pathsself.bs = len(self.im0)

从上面的数据执行逻辑可用看出,推理入口的数据格式可以是一个列表形式。
这个列表中包含拆分后多个区域的数据

# 例如上面拆分为了4个部分,img0, img1, img2, img3
imgs = []
imgs.append(img0)
imgs.append(img1)
imgs.append(img2)
imgs.append(img3)
resultss = model(source=imgs, save=False, conf=conf, iou=nms, save_txt=False, show=False)

最后的结果为4个batch图片数据对应的检测结果

ress0 = resultss[0].tojson()
datas0 = json.loads(ress0)ress1 = resultss[1].tojson()
datas1 = json.loads(ress1)ress2 = resultss[2].tojson()
datas2 = json.loads(ress2)ress3 = resultss[3].tojson()
datas3 = json.loads(ress3)

3. nms处理

因为4部分区域拆分时,是有重合的部分,故在4部分区域推理出结果后,还需要进行一次NMS。

# results:为4个拆分区域检测结果的合集,iou_thresh: iou计算的阈值
def nms(results, iou_thresh):grouped_results = {}# 把results的内容,根据cls的分类情况组合。因为最终做nms时需要区分是不是同一个类别for cls_boxes in results:x1, y1, x2, y2, score, cls = cls_boxesif cls not in grouped_results:grouped_results[cls] = []grouped_results[cls].append([x1, y1, x2, y2, score])#print(grouped_results)keep_boxes = []# 遍历所有的键值对for cls, boxes_l in grouped_results.items():boxes = np.array(boxes_l)# 每个 box 的坐标和置信度x1 = boxes[:, 0]y1 = boxes[:, 1]x2 = boxes[:, 2]y2 = boxes[:, 3]scores = boxes[:, 4]# 每个 box 的面积areas = (y2 - y1 + 1) * (x2 - x1 + 1)# keep_boxes 用于存放执行 NMS 后剩余的 boxes# 取出置信度从大到小排列的索引,其中 scores.argsort() 返回的是数组值从小到大的索引index = scores.argsort()[::-1]while len(index) > 0:# 取出置信度最大的 box,将其放入 keep 中,并判断其他 box 是否可以与之合并i = index[0]boxes_l[i].append(cls)keep_boxes.append(boxes_l[i])# np.maximum(arr:list, x:int)表示计算arr中每一个元素与常数 x 之间的最大值x1_overlap = np.maximum(x1[i], x1[index[1:]])y1_overlap = np.maximum(y1[i], y1[index[1:]])x2_overlap = np.minimum(x2[i], x2[index[1:]])y2_overlap = np.minimum(y2[i], y2[index[1:]])# 计算重叠部分的面积,若没有不重叠部分则面积为 0w = np.maximum(0, x2_overlap - x1_overlap + 1)h = np.maximum(0, y2_overlap - y1_overlap + 1)overlap_area = w * h# 计算 iou(交并比)ious = overlap_area / (areas[i] + areas[index[1:]] - overlap_area)# 因为在拆分时,某个物体可能只有很小一部分,这个小的区域的检测框与正常物体的检测框的# 交集占比小于iou_thresh,则这边小的区域就不会被去除。所以添加下面两个iou数值,用于# 判断某个重叠部分的区域是不是跟检测框的大小类似,从而去除该检测框的值。iou1 = overlap_area / areas[i]iou2 = overlap_area / areas[index[1:]]# 合并重叠度最大的 box,即只保留 iou < iou_thresh 的 box# 因为 np.where(ious <= iou_thresh) 的数据结构是 tuple 里面包含了一个 list,所以要用 [0] 取出 list# 添加条件2,3是为了解决,同一个物体被分隔后,目标框只是物体的小一部分,nms时遗漏condition1 = ious <= iou_threshcondition2 = iou1 < 0.8condition3 = iou2 < 0.8idx = np.where(condition1 & condition2 & condition3)[0]# 这里将需要idx + 1,由于index 是 ious 的索引,而 ious 是去除掉 index 的第一个元素对应的 box 得到的,# 所以 ious 的索引 +1 对应的 box 才是 index 相同索引对应的 index# 因为 len(ious)<=len(index),所以 len(index[idx + 1])<=len(index),所以 while 循环中 index 的元素数量越来越少index = index[idx + 1]return keep_boxes

4. 示例

nms前
在这里插入图片描述
nms处理后
在这里插入图片描述
nms前
在这里插入图片描述
nms处理后
在这里插入图片描述

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

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

相关文章

【微前端乾坤】 vue2主应用、vue2+webpack子应用,vue3+webpack子应用、vue3+vite子应用的配置

因公司需求 需要将原本vue2iframe 形式的项目改成微前端乾坤的方式。 之前iframe都是直接嵌套到vue2项目的二级目录或者三级目录下的(反正就是要随处可嵌) 用乾坤的原因&#xff1a; 1、iframe嵌套的方式存在安全隐患&#xff1b; 2、项目是联合开发的&#xff0c; 乾坤的方便…

Hack The Box-Crafty

目录 信息收集 rustscan whatweb WEB 漏洞利用 漏洞说明 漏洞验证 提权 get user.txt get Administrator 总结 信息收集 rustscan ┌──(root㉿ru)-[~/kali/hackthebox] └─# rustscan -a 10.10.11.249 --range0-65535 --ulimit5000 -- -A -sC [~] Automatically…

NLP:自定义模型训练

书接上文&#xff0c;为了完成指定的任务&#xff0c;我们需要额外训练一个特定场景的模型 这里主要参考了这篇博客&#xff1a;大佬的博客 我这里就主要讲一下我根据这位大佬的博客一步一步写下时&#xff0c;遇到的问题&#xff1a; 文中的cfg在哪里下载&#xff1f; 要不…

Fastjson漏洞利用合集

0x01 Fastjson 概述 1.应用场景 接口返回数据 Ajax异步访问数据RPC远程调用前后端分离后端返回的数据开放API(一些公司开放接口的时候&#xff0c;我们点击请求&#xff0c;返回的数据是JSON格式的)企业间合作接口(数据对接的时候定义的一种规范&#xff0c;确定入参&#x…

BUUCTF-MISC-[HDCTF2019]信号分析1

题目链接&#xff1a;BUUCTF在线评测 (buuoj.cn) 下载附件是一个WAV的文件&#xff0c;题目又叫做信号分析&#xff0c;用Adobe Audition 打开分析了 发现有很多长短不一样的信号&#xff0c;只需要分析一段 猜测长的是一短的为0 最后得到0101010101010101000000110 百度得知…

vscode如何远程到linux python venv虚拟环境开发?(python虚拟环境、vscode远程开发、vscode远程连接)

文章目录 1. 安装VSCode2. 安装扩展插件3. 配置SSH连接4. 输入用户名和密码5. 打开远程文件夹6. 创建/选择Python虚拟环境7. 安装Python插件 Visual Studio Code (VSCode) 提供了一种称为 Remote Development 的功能&#xff0c;允许用户在远程系统、容器或甚至 Windows 子系统…

【致逝去的青春】《龙珠》作者鸟山明逝世,享年68岁

鸟山明工作室&#xff08;BIRD STUDIO&#xff09;于3月8日发布讣告&#xff1a;鸟山明已于2024年3月1日因急性硬膜下血肿逝世&#xff0c;享年68岁。 《龙珠》从 1984 年开始于《周刊少年Jump》连载&#xff0c;过后曾改编曾多部动画、剧场版、游戏&#xff0c;相关周边商品也…

opengl 学习(二)-----你好,三角形

你好&#xff0c;三角形 分类demo效果解析 分类 opengl c demo #include "glad/glad.h" #include "glfw3.h" #include <iostream> #include <cmath> #include <vector>using namespace std;/** * 在学习此节之前&#xff0c;建议将这…

Alveo 概念拓扑结构

在 Alveo 加速卡中,涉及到的概念拓扑结构主要包括 Alveo 卡上的各个关键组件以及与主机系统之间的通信结构。以下是对这些概念拓扑结构的简要介绍: 1.DDR 即双数据率内存(Double Data Rate memory),是一种常见的计算机内存类型,用于存储和提供处理器所需的数据和指令。…

macos m1 arm芯片 使用jpype报错 FileNotFoundError: [Errno 2] JVM DLL not found

startJVM(jpype.getDefaultJVMPath()) 报错 Traceback (most recent call last):File "/Users/thomas990p/PycharmProjects/tuya/volcano-biz-scripts/WenKongFa/FinalCode/java2python/CallJavaAPI.py", line 12, in <module>startJVM(jpype.getDefaultJVMPa…

基于springboot实现大学生兼职网站系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现大学生兼职系统演示 摘要 现代化的市场中&#xff0c;人们日常的工作、生活都在不断的提速&#xff0c;而人们在工作与生活中与互联网的结合也越来越紧密&#xff0c;通过与互联网紧密的结合可以更好地实现日常工作的线上化、信息化、便捷化。现如今的各行各…

ebpf入门---监听所有新进程

什么是ebpf eBPF 全称 extended Berkeley Packet Filter&#xff0c;中文意思是 扩展的伯克利包过滤器。一般来说&#xff0c;要向内核添加新功能&#xff0c;需要修改内核源代码或者编写 内核模块 来实现。而 eBPF 允许程序在不修改内核源代码&#xff0c;或添加额外的内核模…

鸿蒙App基础

像素单位 .1、基础单位 为开发者提供4种像素单位&#xff0c;框架采用vp为基准数据单位。 PS&#xff1a;个人建议使用lpx&#xff0c;配置好配置文件&#xff0c;这里就可以按照UI设计稿实际的来&#xff0c;可以更好的实现设计效果 名称描述px屏幕物理像素单位vp屏幕密度相…

一拖二快充线独特优势

在现代社会&#xff0c;手机已成为我们生活中不可或缺的一部分。随着科技的不断进步&#xff0c;手机的功能越来越强大&#xff0c;从通讯工具逐渐转变为工作、学习和娱乐的得力助手。然而&#xff0c;手机的电量问题一直是困扰着我们的难题。为了解决这个问题&#xff0c;市场…

3•8向女同胞致敬|营销枢纽SaaS厂商乐通达(ltd.com)正式更名枢纽云

为了向女同胞致敬&#xff0c;我们特地选择3月8日女神节变更公司名称&#xff0c;因为《如果SaaS有性别&#xff0c;那 TA一定是女性 》。 2024年3月8日&#xff0c;“杭州乐通达网络有限公司”名称正式变更为“杭州枢纽云计算有限公司”&#xff08;简称&#xff1a;营销枢纽&…

测试常用的Linux命令

前言 直接操作硬件 将把操作硬件的代码封装成系统调用&#xff0c;供程序员使用 虚拟机软件 可以模拟的具有完整硬件系统的功能 可以在虚拟机上安装不同的操作系统 Linux内核只有一个&#xff0c;发行版有很多种 内核来运行程序和管理像磁盘和打印机等硬件设备的核心程序 终端…

积鼎科技两款国产流体仿真软件入选《上海市工业软件推广目录》!

为落实《上海市促进工业软件高质量发展行动计划(2021-2023年)》&#xff0c;聚焦重点行业和领域痛点问题&#xff0c;提升关键软件技术创新和供给能力&#xff0c;推动工业软件产品应用和产业生态建设更好支撑全市制造业数字化转型&#xff0c;《2023年上海市工业软件推荐目录》…

YOLOv8改进 | 独家创新篇 | 利用DCNv3集合DLKA形成全新的注意力机制(全网独家创新)

一、本文介绍 本文给大家带来的机制是由我独家创新结合Deformable Large Kernel Attention (D-LKA) 注意力机制和DCNv3可变形卷积的全新注意力机制模块(算是二次创新),D-LKA的基本原理是结合了大卷积核和可变形卷积的注意力机制,通过采用大卷积核来模拟类似自我关注的感受…

Linux安全--为Nginx加上PHP解析功能

yum install php-fpm -y安装php进程管理器 找到Nginx安装的路径 编辑Nginx配置文件

数学建模【主成分分析】

一、主成分分析简介 主成分分析&#xff08;Principal Component Analysis&#xff0c;PCA&#xff09;是一种降维算法&#xff0c;它能将多个指标转换为少数几个主成分&#xff0c;这些主成分是原始变量的线性组合&#xff0c;且彼此之间互不相关&#xff0c;其能反映出原始数…