(篇六)基于PyDracula搭建一个深度学习的软件之新版本ultralytics-8.3.28调试

embedded/2025/2/13 22:38:59/

ultralytics-8.3.28版本debug记录

1传入文件

代码太多不粘贴在这里了,完整代码写在了篇三

    def open_src_file(self):config_file = 'config/fold.json'config = json.load(open(config_file, 'r', encoding='utf-8'))open_fold = config['open_fold']if not os.path.exists(open_fold):open_fold = os.getcwd()name, _ = QFileDialog.getOpenFileName(self, 'Video/image', open_fold, "Pic File(*.mp4 *.mkv *.avi *.flv *.jpg *.png)")if name:self.yolo_predict.source = name  #将图片或者视频传入到source中print(name)self.show_status('Load File:{}'.format(os.path.basename(name)))config['open_fold'] = os.path.dirname(name)config_json = json.dumps(config, ensure_ascii=False, indent=2) # 重新保存json的信息with open(config_file, 'w', encoding='utf-8') as f:f.write(config_json)self.stop()

最终我们发现,打开的图片其实保存到了YoloPredictor下面的source,但是BasePredictor(yolo检测器)这个文件下是没有source这个属性的。因此这一步并没有完成图片与yolo检测器之间的链接

# 设置输入源
self.setup_source(self.source if self.source is not None else self.args.source)# 打开的图片从这被self.args.source被加载进去
  • 在setup_source函数中,发现传入的source被包含到了self.dataset当中,我们要在这里找出self.dataset对于图片检测和视频检测都有什么区别。
1图片检测
“”“yolo检测器”“”
def setup_source(self, source):"""Sets up source and inference mode."""self.imgsz = check_imgsz(self.args.imgsz, stride=self.model.stride, min_dim=2)  # check image sizeself.transforms = (getattr(self.model.model,"transforms",classify_transforms(self.imgsz[0], crop_fraction=self.args.crop_fraction),)if self.args.task == "classify"else None)self.dataset = load_inference_source(source=source,batch=self.args.batch,vid_stride=self.args.vid_stride,buffer=self.args.stream_buffer,)self.source_type = self.dataset.source_typeif not getattr(self, "stream", True) and (self.source_type.streamor self.source_type.screenshotor len(self.dataset) > 1000  # many imagesor any(getattr(self.dataset, "video_flag", [False]))):  # videosLOGGER.warning(STREAM_WARNING)self.vid_writer = {}
‘’‘新版本yolo’‘’
def load_inference_source(source=None, batch=1, vid_stride=1, buffer=False):"""Loads an inference source for object detection and applies necessary transformations.Args:source (str, Path, Tensor, PIL.Image, np.ndarray): The input source for inference.batch (int, optional): Batch size for dataloaders. Default is 1.vid_stride (int, optional): The frame interval for video sources. Default is 1.buffer (bool, optional): Determined whether stream frames will be buffered. Default is False.Returns:dataset (Dataset): A dataset object for the specified input source."""source, stream, screenshot, from_img, in_memory, tensor = check_source(source) # 打断点source_type = source.source_type if in_memory else SourceTypes(stream, screenshot, from_img, tensor)# Dataloaderif tensor:dataset = LoadTensor(source)elif in_memory:dataset = sourceelif stream:dataset = LoadStreams(source, vid_stride=vid_stride, buffer=buffer)elif screenshot:dataset = LoadScreenshots(source)elif from_img:dataset = LoadPilAndNumpy(source)else:dataset = LoadImagesAndVideos(source, batch=batch, vid_stride=vid_stride)# Attach source types to the datasetsetattr(dataset, "source_type", source_type)return dataset

输入图片之后load_inference_source函数打断点,发现图片走的是这行代码。

    else:dataset = LoadImagesAndVideos(source, batch=batch, vid_stride=vid_stride)

再仔细分析check_source(source)返回的全是false,在这个函数内部判定is_file:True。我们的source确实是file文件,因此这一步并没有问题。
在这里插入图片描述

在这里插入图片描述
我们再仔细分析一下这行代码

    else:dataset = LoadImagesAndVideos(source, batch=batch, vid_stride=vid_stride)

我们返回的dataset是一个迭代器,使用方式如下面代码所示:

Examples:>>> loader = LoadImagesAndVideos("path/to/data", batch=32, vid_stride=1)>>> for paths, imgs, info in loader:...     # Process batch of images or video frames...     pass

在接下来的代码中有:

batch = next(self.dataset)  # 使用 next(self.dataset) 可以显式地获取下一批数据,而不是依赖 for 循环或隐式的迭代器行为。这种方式适用于需要更细粒度控制数据加载的场景,例如在某个特定条件下才加载下一批数据。self.batch = batch  # 保存当前批次
path, im, im0s = batch  # 从批次中提取路径、图像、原始图像、视频捕获和其他信息

这种情况明显和新版的dataset是不一致的。具体表现在im0s以前是原图,但如今表示注释信息info。

2视频检测

我们发现输入为视频,在check_source(source)函数中依旧会被判定为is_file:True。因此最后依旧会走LoadImagesAndVideos这个类,所生成的dataset依旧是没有属性的。setattr(dataset, "source_type", source_type)这里的属性是没有的。
在这里插入图片描述
LoadImagesAndVideos会将MP4装到一个列表里面
在这里插入图片描述
后续LoadImagesAndVideos会用视频解释器给装起来,变成self.frames

    def _new_video(self, path):"""Creates a new video capture object for the given path and initializes video-related attributes."""self.frame = 0self.cap = cv2.VideoCapture(path)self.fps = int(self.cap.get(cv2.CAP_PROP_FPS))if not self.cap.isOpened():raise FileNotFoundError(f"Failed to open video {path}")self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.vid_stride)

在提取的时候数据的时候,最后一个batch所提取的是path表示地址,im当前帧numpy数组,info其他信息。

batch = next(self.dataset)  # 使用 next(self.dataset) 可以显式地获取下一批数据,而不是依赖 for 循环或隐式的迭代器行为。这种方式适用于需要更细粒度控制数据加载的场景,例如在某个特定条件下才加载下一批数据。
self.batch = batch  # 保存当前批次,注意如果是视频,那么则为当前帧数据
path, im, info = batch  # path表示图片或者视频的地址,im当前帧numpy数组,info其他信息。

然后我发现了一个V11的缺陷,就是一些尺寸的图片无法完成检测,我就报错了
但是换了一个图片之后有可以了,估计是模型在cat的时候有地方是不满足的。

Sizes of tensors must match except in dimension 1. Expected size 136 but got size 135 for tensor number 1 in the list.

2数据集使用

在run函数将dataset将数据集转化为一个迭代器。这个self.dataset也是新版本yolo与旧版本最大的区别。

def run() 
...batch = iter(self.dataset)  # 将数据集转化为迭代器

3Debug

class YoloPredictor(BasePredictor, QObject):
。。。
self.yolo_predict = YoloPredictor()  # Createa a Yolo instance
。。。
self.yolo_predict.source = name  #将图片或者视频传入到source中
  • 问题代码1——这里报错——报错expected np.ndarray (got list)
    ultralytics-8.3.28版本batch是3个维度首先无法被解压为5个。
path, im, im0,svid_cap, s  = batch (错误源头)
。。。
  • 因此我将其这么调整
self.batch = batch  # 保存当前批次
print(batch)  # 打印 batch 的内容
print(len(batch))  # 打印 batch 的长度
path, im, im0s = batch  # 从批次中提取路径、图像、原始图像、视频捕获和其他信息
path, im, im0s = batch  # 从批次中提取路径、图像、原始图像、视频捕获和其他信息
vid_cap, s = None, None  # 其他变量设为默认值
  • 然而遇见了这个报错——expected np.ndarray (got list) 这里的im要求输入是图片而不是列表。
 # 预处理图像
with self.dt[0]:im = self.preprocess(im)  # 预处理图像if len(im.shape) == 3:  # 如果图像维度为3,则扩展批次维度im = im[None]  # 扩展为批次维度
  • 于是我调整为
with self.dt[0]:im = self.preprocess(im[count-1])  # 预处理图像if len(im.shape) == 3:  # 如果图像维度为3,则扩展批次维度im = im[None]  # 扩展为批次维度im = im.permute(0, 3, 1, 2)  # 交换维度
  • 有报错为’str’ object has no attribute ‘shape’
pred[:, :4] = ops.scale_boxes(img.shape[2:], pred[:, :4], shape).round()
  • batch = iter(self.dataset) 这个到底有啥作用
  • 报错KeyError(-1),这里的字典没有-1索引?
if isinstance(self.vid_writer[-1], cv2.VideoWriter):
self.vid_writer[-1].release()  # 释放视频写入器

太晚了明天继续debug。


http://www.ppmy.cn/embedded/161977.html

相关文章

KEPServerEX 的接口类型与连接方式的详细说明

目录 一、KEPServerEX 核心架构 二、KEPServerEX 支持的接口类型 三、KEPServerEX 支持的连接类型 1. 通用工业协议 2. 品牌专属协议 3. 行业专用协议 4. 数据库与文件接口 四、配置示例 1. 接口配置(以OPC UA为例) 2. 连接配置(以…

Rust学习总结之所有权(一)

不管是计算机的哪种语言,都有内存的管理方式。主流有两种,一是以C为代表的由开发者来决定申请和释放内存,二是以Python为代表的通过语言本身的垃圾回收机制来自动管理内存。Rust开辟了第三种方式,通过所有权系统管理内存。 Rust所…

基于进化式大语言模型的下一代漏洞挖掘范式:智能对抗与自适应攻防体系

摘要 本文提出了一种基于进化式大语言模型(Evolutionary LLM)的智能漏洞挖掘框架,突破了传统静态分析的局限,构建了具备对抗性思维的动态攻防体系。通过引入深度强化学习与多模态感知机制,实现了漏洞挖掘过程的自适应进化,在RCE、SQLi、XXE等关键漏洞类型的检测中达到97…

Visual Studio 中的键盘快捷方式

可打印快捷方式备忘单 Visual Studio 的常用键盘快捷方式 本部分中的所有快捷方式都将全局应用(除非另有指定)。 “全局”上下文表示该快捷方式适用于 Visual Studio 中的任何工具窗口。 生成:常用快捷方式 命令键盘快捷键命令 ID生成解决…

从 0 开始本地部署 DeepSeek:详细步骤 + 避坑指南 + 构建可视化(安装在D盘)

个人主页:chian-ocean 前言: 随着人工智能技术的迅速发展,大语言模型在各个行业中得到了广泛应用。DeepSeek 作为一个新兴的 AI 公司,凭借其高效的 AI 模型和开源的优势,吸引了越来越多的开发者和企业关注。为了更好地…

计算机网络,大白话

好嘞,咱就从头到尾,给你好好说道说道计算机网络里这些“门门道道”的概念: 1. 网络(Network) 啥是网络? 你可以把网络想象成一个“大Party”,大家(设备)聚在一起&#…

关于工厂模式和单例模式

工厂模式 工厂模式就是将对象的创建过程封装在一个工厂类中,将创建对象的任务交给工厂完成。外部只能通过工厂类来指定创建或查找一个什么类型的对象,但不能直接创建对象。这样的好处在于实现了创建逻辑和业务逻辑的解耦。让代码变得更好看。 工厂模式又…

54MAX传奇引擎源码完整二次开发母版编译教程

54MAX 传奇引擎 是传奇游戏爱好者开发或二次开发的一种游戏引擎,主要用于复刻或二次开发传奇私服。它在性能、功能扩展和可控性方面有其独特的特点。以下是对 54MAX 传奇引擎源码的原理与特点 的详细分析: 链接: https://pan.baidu.com/s/10Xgo631jONEM…