当前位置: 首页 > article >正文

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

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 size
	   self.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_type
	   if not getattr(self, "stream", True) and (
	       self.source_type.stream
	       or self.source_type.screenshot
	       or len(self.dataset) > 1000  # many images
	       or any(getattr(self.dataset, "video_flag", [False]))
	   ):  # videos
	       LOGGER.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)

    # Dataloader
    if tensor:
        dataset = LoadTensor(source)
    elif in_memory:
        dataset = source
    elif 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 dataset
    setattr(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 = 0
        self.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.kler.cn/a/543557.html

相关文章:

  • (一)获取数据和读取数据
  • 团结引擎 OpenHarmony 平台全面支持 UAAL,实现引擎能力嵌入原生应用
  • 如何在 GitHub 上写博客
  • mysql读写分离与proxysql的结合
  • 函数指针(Function Pointer)与 typedef int (*FuncPtr)(int, int);typedef与using(更推荐)
  • vue纯静态实现 视频转GIF 功能(附源码)
  • 机器学习 - 机器学习模型的评价指标
  • HackerRank C++面试,中等难度题目 - Attribute Parser
  • 【C++高并发服务器WebServer】-18:事件处理模式与线程池
  • 基于Java的分布式系统架构设计与实现
  • Kafka的ISR是什么,HW是什么,怎么保证可靠性,Kafka怎么实现顺序消息?为什么Kafka的broker上的topic越多,效率越慢?
  • 嵌入式WebRTC压缩至670K,目标将so动态库压缩至500K,.a静态库还可以更小
  • 基于SpringBoot+Vue的扶贫助农管理系统
  • ubuntu下ollama/vllm两种方式在本地部署Deepseek-R1
  • 用语言模型探索语音风格空间:无需情感标签的情 感TTS
  • 常用HAL库
  • 【05】RUST常用的集合函数宏类型
  • 通过openresty和lua实现随机壁纸
  • 人工智能代理(AI Agent)的演进与未来:技术突破、应用场景与挑战
  • HbuilderX中如何配置npm和node路径
  • 大数据Orc文件生成与读取
  • 3D模型可视化引擎HOOPS Visualize在桌面端的支持有哪些特点?
  • C 语言 static 变量和函数
  • MyBatis Plus与JSON字段查询:动态构建JSON条件
  • 细究 ES6 中多种遍历对象键名方式的区别
  • 基于Spring Boot和MyBatis的后端主键分页查询接口示例