YOLOv9推理结果保存路径解析:runs/detect目录结构说明
你刚跑完YOLOv9的检测命令,终端里跳出一行“Results saved to runs/detect/yolov9_s_640_detect”,可打开文件管理器却找不到这个路径?或者找到了,但里面一堆子文件夹和文件,根本分不清哪个是原图、哪个是标注框、哪个是置信度信息?别急——这不是你操作错了,而是YOLOv9默认的输出组织逻辑确实有点“藏得深”。这篇文章不讲训练原理、不堆参数配置,就专注一件事:把 runs/detect 这个目录彻底拆开、说透、理清楚。无论你是第一次运行 detect_dual.py 的新手,还是想批量提取检测结果做后续分析的进阶用户,看完就能立刻定位你要的图片、坐标、标签和统计信息。
1. 为什么是 runs/detect?从设计逻辑说起
YOLO系列从v5开始就统一采用runs/作为顶层输出根目录,它不是随意命名,而是有明确分工的工程约定:
runs/train/:只放训练过程中的权重(weights)、日志(results.csv)、可视化图(results.png)、验证集预测图(val_batch*.jpg)runs/val/:存放模型在验证集上的详细评估报告(confusion_matrix.png、F1_curve.png 等)runs/detect/:专用于推理(inference)输出,所有你用detect_dual.py或detect.py处理过的图片、视频、文件夹,结果都归这里管
这个设计的好处是:一次实验的所有产物自动归类,不会混在一起。你不需要手动创建文件夹、重命名结果,只要记住--name参数填什么,就能精准定位到自己的那批结果。
而detect这个子目录名,也直白地告诉你:它只负责“检测任务”的输出,不掺杂训练、验证、导出ONNX等其他流程。这种清晰的职责划分,对多人协作或长期维护项目特别友好。
2. runs/detect 目录的完整结构图谱
假设你执行了这行命令:
python detect_dual.py --source './data/images/horses.jpg' --img 640 --device 0 --weights './yolov9-s.pt' --name yolov9_s_640_detect那么系统会在/root/yolov9/runs/detect/下创建一个名为yolov9_s_640_detect的文件夹。它的内部结构不是扁平的,而是按用途分层组织的。我们一层一层来看:
2.1 顶层文件夹:yolov9_s_640_detect
这是你通过--name指定的自定义名称,也是整个结果集的“身份证”。建议起名时带上关键信息,比如:
yolov9_s_640_horses(模型+尺寸+数据名)yolov9_m_1280_indoor_test(模型+尺寸+场景+用途)
这样后期翻记录时,一眼就知道这批结果是谁、在哪、为什么跑。
2.2 核心输出:images 子目录
进入yolov9_s_640_detect/后,第一个看到的就是images/文件夹。它包含两类内容:
- 原始输入的副本:如果你传入的是单张图片(如
horses.jpg),这里会原样保留一份,命名为horses.jpg - 带检测框的输出图:同一张图,叠加了边界框(Bounding Box)、类别标签和置信度分数,命名为
horses.jpg(与原图同名,但内容已更新)
小技巧:YOLOv9 默认不覆盖原图。它会先读取原图,再在内存中绘制检测结果,最后保存为新文件。所以你永远能找回未加框的干净原图——它就在
images/里,和带框图并排躺着。
如果输入是文件夹(如--source ./data/images/),images/下就会出现一整批处理后的图片,命名与源文件完全一致,方便你逐一对比。
2.3 坐标与标签:labels 子目录
这才是真正“值钱”的部分——所有检测结果的结构化数据,全在这里。
labels/文件夹下,每个.txt文件对应一张输入图片,文件名与图片名严格一致(只是后缀换成了.txt)。比如horses.jpg对应horses.txt。
打开horses.txt,你会看到类似这样的内容:
0 0.523 0.487 0.312 0.245 0 0.765 0.321 0.289 0.198 1 0.234 0.678 0.187 0.223每行代表一个检测到的目标,格式是标准的YOLO格式:
- 第1列:类别索引(0=person, 1=horse, 2=car… 具体看你的
data.yaml中的names顺序) - 第2–3列:边界框中心点的 x, y 坐标(归一化到 0~1 范围)
- 第4–5列:边界框的宽度 w 和高度 h(同样归一化)
实用提醒:这些坐标是“归一化”的,不是像素值。如果你想转成实际像素坐标(比如要裁剪目标区域),只需乘以图片宽高:
img_w, img_h = 1280, 720 # 假设原图尺寸 x_center_px = x_norm * img_w y_center_px = y_norm * img_h w_px = w_norm * img_w h_px = h_norm * img_h # 再算左上角坐标:x1 = x_center_px - w_px/2, y1 = y_center_px - h_px/2
2.4 可视化增强:visualize 子目录(YOLOv9特有)
这是YOLOv9区别于v5/v8的一个重要新增项。visualize/文件夹里存放的是热力图(heatmap)和特征图(feature map)的可视化结果,用于理解模型“为什么这么判断”。
典型文件包括:
horses_heatmap.jpg:显示模型关注图像哪些区域做出决策,越亮的地方越关键horses_feature_layer3.jpg:第3个主干网络层的特征响应图,能看出模型提取了哪些纹理/边缘信息
这些图对调试模型、分析误检漏检原因非常有用。比如一张图里马没被检出,但heatmap.jpg显示马所在区域一片暗淡,就说明模型根本没“看见”它——问题可能出在预处理或主干网络;如果马区域很亮,但labels/里没记录,那大概率是NMS阈值设太高,把结果过滤掉了。
2.5 元信息与日志:results.json 和 detect.log
results.json:一个结构化的JSON文件,汇总了本次推理的全局统计信息,例如:- 总处理图片数
- 平均每张图检测到的目标数
- 各类别检测总数("person": 42, "horse": 17...)
- 推理耗时(预处理+前向+后处理总时间)
detect.log:纯文本日志,记录命令行参数、环境信息(GPU型号、CUDA版本)、警告(如某张图尺寸不匹配被跳过)、以及每张图的详细处理状态(“Processing horses.jpg... Done in 0.12s”)。
工程建议:如果你要做自动化流水线,
results.json是最友好的数据源——Python里几行代码就能读取统计结果,无需解析日志文本。
3. 三个高频问题,一次讲清
3.1 我想只保存坐标不保存图片,怎么关掉 images 输出?
YOLOv9 的detect_dual.py默认同时输出图片和标签。如果你只需要.txt坐标文件(比如用于后续算法输入),可以加一个隐藏参数:
python detect_dual.py --source './data/images/horses.jpg' \ --img 640 --device 0 --weights './yolov9-s.pt' \ --name yolov9_s_640_detect \ --save-img False # 关键!设为False执行后,images/文件夹将完全不生成,只有labels/、visualize/、results.json和detect.log会被创建。省空间、提速度,特别适合大批量离线处理。
3.2 labels/ 里的 txt 文件,怎么快速转成 CSV 或 Excel 方便查看?
直接手写脚本太麻烦?这里给你一个开箱即用的 Python 片段,放在/root/yolov9/目录下运行即可:
# save_labels_to_csv.py import os import csv from pathlib import Path def convert_labels_to_csv(labels_dir, output_csv): with open(output_csv, 'w', newline='') as f: writer = csv.writer(f) # 表头 writer.writerow(['image_name', 'class_id', 'x_center', 'y_center', 'width', 'height']) for txt_file in Path(labels_dir).glob('*.txt'): img_name = txt_file.stem + '.jpg' # 假设原图是jpg with open(txt_file, 'r') as t: for line in t: parts = line.strip().split() if len(parts) == 5: cls, x, y, w, h = parts writer.writerow([img_name, cls, x, y, w, h]) # 使用示例:把 yolov9_s_640_detect 的 labels 转成 csv convert_labels_to_csv( labels_dir='/root/yolov9/runs/detect/yolov9_s_640_detect/labels', output_csv='/root/yolov9/runs/detect/yolov9_s_640_detect/labels_summary.csv' ) print(" CSV 已生成:labels_summary.csv")运行后,你会得到一个清晰的表格,所有检测框按行排列,Excel双击就能打开排序筛选。
3.3 我的输入是视频,结果保存在哪里?结构一样吗?
完全一样。YOLOv9 对视频的处理逻辑是:逐帧解码 → 每帧当作一张图片处理 → 每帧生成对应的 labels/.txt 和 images/.jpg。
唯一区别是:
- 输入
--source ./data/videos/test.mp4 - 输出目录下
images/里不再是test.jpg,而是按帧编号的图片:test_00001.jpg,test_00002.jpg, … labels/里对应test_00001.txt,test_00002.txt, …
这意味着你可以用完全相同的脚本(比如上面的CSV转换)来处理视频帧结果。如果想还原成视频,YOLOv9 还会额外在images/同级生成一个test.avi(或mp4)文件——那是所有带框帧拼接成的检测结果视频,直接播放就能看效果。
4. 实战建议:如何高效管理你的 runs/detect
光知道结构还不够,日常使用中几个小习惯能帮你少踩80%的坑:
4.1 建立“结果命名规范”
别再用--name test、--name run1这种名字。推荐三级命名法:
[模型缩写]_[输入类型]_[日期时间] # 示例: y9s_img640_horses_20240520_1430 y9m_vid1280_office_20240520_1515这样在/root/yolov9/runs/detect/里 ls 一下,就能按时间、按场景、按模型快速筛选,不用一个个点进去看。
4.2 定期清理,避免磁盘爆满
runs/detect/不会自动清理旧结果。一个1080P视频处理完,images/可能占几个GB。建议养成习惯:
# 查看最大的3个结果目录 du -sh /root/yolov9/runs/detect/* | sort -hr | head -3 # 删除某个旧结果(比如yolov9_s_old) rm -rf /root/yolov9/runs/detect/yolov9_s_old4.3 把 labels 当作“黄金数据”备份
labels/里的.txt是轻量、标准、无损的检测结果。相比图片,它体积小、易传输、易版本控制。建议:
- 每次重要推理后,把整个
labels/文件夹打包压缩(tar -czf labels_y9s_horses.tgz labels/) - 上传到你的私有NAS或对象存储,作为可复现的“检测快照”
5. 总结:掌握 runs/detect,就是掌握YOLOv9的输出主权
YOLOv9 的runs/detect不是一个黑盒文件夹,而是一套精心设计的“结果交付系统”。它把检测任务的全部产出——可视化结果(images/)、结构化数据(labels/)、决策依据(visualize/)、全局统计(results.json)和执行日志(detect.log)——分门别类、严丝合缝地组织起来。
你不需要记住所有细节,只要抓住三个核心:
--name是你的导航键:它决定了结果存哪,起好名=一半工作完成;labels/是你的数据金矿:所有坐标、类别、置信度都在这里,是后续分析、训练、部署的源头;images/是你的效果看板:直观验证模型是否work,哪里准、哪里偏、哪里漏。
下次再看到 “Results saved to runs/detect/xxx”,别再犹豫点开——现在你知道,每一层文件夹背后,都是为你准备好的、即取即用的工程资产。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。