yolov8多batch推理,nms后处理

news2024/11/20 0:37:31

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 = stream
        if 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 called
        self.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 = imgsz
        self.mode = 'image'
        # Generate fake paths
        self.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_boxes
        if 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:]])

            # 计算重叠部分的面积,若没有不重叠部分则面积为 0
            w = 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_thresh
            condition2 = iou1 < 0.8
            condition3 = iou2 < 0.8
            idx = 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.coloradmin.cn/o/1500599.html

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

相关文章

有没有能用蓝牙的游泳耳机?6招解决选购难题,瞄准好货!

在数字化时代&#xff0c;我们越来越依赖各种电子设备来提升生活质量。对于喜欢运动的朋友来说&#xff0c;耳机已经成为他们必不可少的装备之一。无论是跑步、健身还是游泳&#xff0c;耳机都能为我们提供美妙的音乐和清晰的语音通话&#xff0c;让我们的运动体验更加丰富多彩…

React报错 之 Objects are not valid as a React child

原文链接&#xff1a; 1、React报错之Objects are not valid as a React child 2、Objects are not valid as a React child error [Solved] 作者&#xff1a;Borislav Hadzhiev 以下文中涉及到的链接均来自于该作者&#xff0c;他写了很多相关的文章&#xff0c;可以多看看他的…

微信开发者工具 vim 键位绑定

问题&#xff1a;如标题 解决&#xff1a; 最上边点击设置&#xff0c;找到编辑器设置 点击更多编辑器设置&#xff0c;然后会弹出设置这个页面 搜索 vim &#xff0c;并点击 一直往下边滑动&#xff0c;找到 setting.json 然后加入这段代码&#xff1a; "vim.insertM…

python练习题2

1.一下哪项不是python语言的保留字&#xff08;&#xff09; A.False B.and C.true D.if 答案&#xff1a;C&#xff08;应该是True&#xff09; 2.x5&#xff0c;y3&#xff0c;执行x&#xff0c;yy&#xff0c;x之后&#xff0c;x和y的值分别是什么&#xff08;&#xff09; …

记一次edu证书站的挖洞经历

前言 前几天在网上冲浪的时候无意间看到了一个Edu的站点&#xff0c;是一个很常见的类似MOOC的那种在线学习系统&#xff0c;对外开放&#xff0c;同时有注册和登录功能。对于我这种常年低危的菜鸡来说&#xff0c;这是最愿意看到的&#xff0c;因为一个Web网站有了登录功能&a…

Discuz论坛网站报错Discuz!Database Error(0)notconnect的解决办法

运营服务器大本营有段时间了&#xff0c;在运营期间遇到两次Discuz&#xff01;Database Error&#xff08;0&#xff09;notconnect报错&#xff0c;和你们分享遇到Discuz报错的解决办法&#xff0c;希望可以帮助到你。 首先网站报错&#xff08;0&#xff09;notconnect&…

iOS——【自动引用计数】ARC规则及实现

1.3.3所有权修饰符 所有权修饰符一共有四种&#xff1a; __strong 修饰符__weak 修饰符__undafe_unretained 修饰符__autoreleasing 修饰符 __strong修饰符 _strong修饰符表示对对象的强引用&#xff0c;持有强引用的变量在超出其作用域的时候会被废弃&#xff0c;随着强引…

玄机科技女神大集结!妇女节来一场别开生面的“她”力量巡礼!

3.8妇女节到啦&#xff01;是不是觉得整个世界都充满了粉红色的气息&#xff1f;各位小伙伴是不是已经准备好为身边的女性送上祝福了呢&#xff1f;而今天&#xff0c;我们也要来一场特别的“联欢”&#xff0c;盘点一下玄机科技动画中那些风格各异、魅力无限的女神们&#xff…

bug - poi getMergedRegion合并后的行列number错误

第一个CellRangeAddress 的Row number 应该是0&#xff0c;但是给出的是1。 其它的CellRangeAddress 与实际大致相差4-5不等&#xff0c;没有规律。 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>…

开源模型应用落地-工具使用篇-Ollama(六)

一、前言 在AI大模型百花齐放的时代&#xff0c;很多人都对新兴技术充满了热情&#xff0c;都想尝试一下。但是&#xff0c;实际上要入门AI技术的门槛非常高。除了需要高端设备&#xff0c;还需要面临复杂的部署和安装过程&#xff0c;这让很多人望而却步。不过&#xff0c;随着…

llama factory学习笔记

模型 模型名模型大小默认模块TemplateBaichuan27B/13BW_packbaichuan2BLOOM560M/1.1B/1.7B/3B/7.1B/176Bquery_key_value-BLOOMZ560M/1.1B/1.7B/3B/7.1B/176Bquery_key_value-ChatGLM36Bquery_key_valuechatglm3DeepSeek (MoE)7B/16B/67Bq_proj,v_projdeepseekFalcon7B/40B/18…

寻找数组的中心索引

给你一个整数数组 nums &#xff0c;请计算数组的 中心下标 。 数组 中心下标 是数组的一个下标&#xff0c;其左侧所有元素相加的和等于右侧所有元素相加的和。 如果中心下标位于数组最左端&#xff0c;那么左侧数之和视为 0 &#xff0c;因为在下标的左侧不存在元素。这一点…

跨网络传输的大致过程+图解(软件虚拟层),ip地址介绍,ip地址和mac地址对比

目录 跨网络传输 引入​​​​​​​ 举例 -- 唐僧西天取经 结论 介绍 ip地址 引入 介绍 类型 公有ip 私有ip 版本 ipv4 ipv6 ip地址和mac地址的唯一性问题 数据包转发的过程 引入 思考 -- 如何跨子网 过程 图解 封装和解包 去掉差异 ip地址/协议的重要…

Nginx正向代理域名的配置

目录 前言 1.打开文件 2. 启用代理 3. 指定代理服务器 4. 保存配置文件并重新加载Nginx。 5. 添加域名解析。 6. 配置客户端。 总结 前言 Nginx是一个高性能、开源的Web服务器软件&#xff0c;不仅可以作为反向代理服务器使用&#xff0c;还可以作为正向代理服务器使用…

IDEA启动项目读取nacos乱码导致启动失败

新安装的2023社区版IDEA,启动项目报错。 forest: interceptors: - com.gdsz.b2b.frontend.api.Interceptors.ApiInterceptor org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length 1 at org.yaml.snakeyaml.reader.S…

Zabbix(四)

Zabbix Proxy zabbix作为一个分布式监控系统(分布式监控解决方案)&#xff0c;支持通过代理(proxy)收集zabbix agent的监控数据&#xff0c;然后由zabbix proxy再把数据发送给zabbix server&#xff0c;也就是zabbix proxy 可以代替zabbix server收集监控数据&#xff0c;然后…

VBA中类的解读及应用第十讲:限制文本框的输入,使其只能输入数值(上)

《VBA中类的解读及应用》教程【10165646】是我推出的第五套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。 类&#xff0c;是非常抽象的&#xff0c;更具研究的价值。随着我们学习、应用VBA的深入&#xff0…

React-父传子

1.概念 说明&#xff1a;父组件传递数据子组件标签身上绑定属性&#xff1b;子组件接受数据props的参数。props是一个对象&#xff0c;包含父组件传递的所有数据。例如数字、字符串、布尔值、数组、对象、函数、JSX。不允许直接修改父组件传递的数据。 2.例子 // 父传子 // …

YOLO建筑物损伤评估数据集

YOLO建筑物损伤评估数据集&#xff0c;重度损伤&#xff0c;轻微损伤&#xff0c;中度损伤&#xff0c;未损伤4类&#xff0c;近五千张图像&#xff0c;yolo标注完整&#xff0c;应用数据增强。 适用于CV项目&#xff0c;毕设&#xff0c;科研&#xff0c;实验等 需要此数据集…

抖店月销过万的爆单技巧,新手轻松月入1w+,附抖店学习资料!

我是电商珠珠 抖店开通之后&#xff0c;怎么才能快速出单是很多新手小伙伴困扰的问题。其实想要运营好抖店一点都不难&#xff0c;我做抖店也有三年多时间了&#xff0c;接下来我说的每一步&#xff0c;不管是有货源还是无货源的都适用。 1、铺货低价福利款 店铺开好之后&am…