news 2026/9/29 11:20:12

红蚂蚁YOLO数据集:VOC/COCO/YOLO三格式一键生成与训练实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
红蚂蚁YOLO数据集:VOC/COCO/YOLO三格式一键生成与训练实战

简介:本资源是面向计算机视觉初学者与YOLO目标检测实践者的红蚂蚁专用数据集及配套训练工具包,解决真实场景下小目标检测数据匮乏、标注格式转换繁琐、环境配置与训练流程不清晰等痛点。压缩包共2000个文件,含1000张高质量实景红蚂蚁图像,以及对应VOC(XML)、COCO(JSON)和YOLO(TXT)三种主流格式的完整标签,另有6个HTML教程文档、3个Python划分脚本(支持自定义train/val/test比例并自动组织目录结构)、1个YOLO训练配置YAML文件,总大小40.85MB。目前已有384人学习下载,涵盖从环境搭建(Windows/Linux双平台)、数据集划分、模型训练到结果可视化全流程,特别提供split_train_val生成ImageSets的脚本及多版本训练案例说明,显著降低复现门槛,适合课程实验、毕业设计与科研微调任务。

1. 红蚂蚁目标检测落地难?这个YOLO数据集把VOC/COCO/YOLO三格式标签、划分脚本、训练教程全塞进一个压缩包里,新手跑通只需20分钟

你是不是也遇到过:想用YOLO做红蚂蚁识别,但网上搜到的“红蚂蚁数据集”只有几十张图、没标注、或者只给个百度网盘链接配一句“自行转换”?更糟的是,下载后发现标签是txt但格式不对,voc转yolo时class_id错位,coco json里bbox坐标被缩放两次,train/val/test划分比例写死在代码里改起来像解谜……这个资源不是又一个半成品——它直接给你1000张实拍红蚂蚁图像(含野外、实验室、巢穴特写三种场景),每张图都同步生成Pascal VOC XML、MS COCO JSON、YOLO TXT三套标准标签,附带可配置的划分脚本(支持按比例/按文件名前缀/按拍摄日期分组),还有一份从环境搭建→数据校验→模型微调→结果可视化全流程的训练教程。适合农业植保AI初学者、林业病虫害监测项目组、高校课程设计小组——尤其当你需要在3天内交出一个能跑通的红蚂蚁识别demo时,它省掉的不是时间,是反复重装torchvision、debug labelImg导出bug、手写split逻辑的血泪经验。


2. 数据结构与三格式标签生成原理:为什么1000张图能同时满足VOC/COCO/YOLO训练需求?

2.1 原始图像与标注一致性验证:从拍摄源头控制质量边界

该数据集的1000张图像全部来自华南某农科院2023年红火蚁(Solenopsis invicta)野外监测项目,分辨率统一为1920×1080,采用RAW+JPEG双存档。关键在于标注一致性控制:所有图像由同一组经标定的Canon EOS R6相机拍摄,镜头焦距固定为100mm,拍摄距离严格控制在0.5–2m区间,确保蚂蚁个体在画面中占比稳定(最小边长≥45像素)。这直接规避了YOLO训练中最常见的尺度坍塌问题——当小目标(如远距离红蚂蚁)占比过高时,YOLOv5/v8的anchor匹配会失效。原始图像目录结构如下:

dataset_raw/ ├── images/ │ ├── IMG_0001.jpg │ ├── IMG_0002.jpg │ └── ... (1000 files) └── annotations/ └── manual_labeling.xlsx # 标注员填写的原始表格,含image_id, x_min, y_min, x_max, y_max, class_name

提示:manual_labeling.xlsx是整个数据链路的黄金标准。所有VOC/COCO/YOLO标签均由该Excel生成,而非人工二次标注。这意味着当你发现某张图的YOLO txt和VOC xml不一致时,问题一定出在转换脚本,而非原始数据。

2.2 VOC格式生成:XML结构必须包含<size>和<object>的完整嵌套

Pascal VOC要求每个XML文件必须包含<size>(图像宽高)、<object>(每个目标实例)、<bndbox>(归一化坐标禁止!必须为像素坐标)。本数据集生成的VOC XML严格遵循此规范,且额外加入<difficult>字段(红蚂蚁因形态相似常被误标,此处设为0表示非困难样本)。生成逻辑如下:

# voc_generator.py 关键片段 def create_voc_xml(image_path, bboxes, class_names, output_dir): root = ET.Element("annotation") # 必须先写<folder><filename><path>等基础字段 folder = ET.SubElement(root, "folder") folder.text = "images" filename = ET.SubElement(root, "filename") filename.text = os.path.basename(image_path) # <size>字段:从图像实际读取,禁止硬编码 img = cv2.imread(image_path) size = ET.SubElement(root, "size") width = ET.SubElement(size, "width") width.text = str(img.shape[1]) height = ET.SubElement(size, "height") height.text = str(img.shape[0]) depth = ET.SubElement(size, "depth") depth.text = str(img.shape[2]) # 每个<object>必须包含<name><pose><truncated><difficult><bndbox> for i, (x1, y1, x2, y2) in enumerate(bboxes): obj = ET.SubElement(root, "object") name = ET.SubElement(obj, "name") name.text = class_names[i] # 固定为"red_ant" pose = ET.SubElement(obj, "pose") pose.text = "Unspecified" truncated = ET.SubElement(obj, "truncated") truncated.text = "0" difficult = ET.SubElement(obj, "difficult") difficult.text = "0" bndbox = ET.SubElement(obj, "bndbox") xmin = ET.SubElement(bndbox, "xmin") xmin.text = str(int(x1)) # 注意:必须取整!float会触发labelImg解析失败 ymin = ET.SubElement(bndbox, "ymin") ymin.text = str(int(y1)) xmax = ET.SubElement(bndbox, "xmax") xmax.text = str(int(x2)) ymax = ET.SubElement(bndbox, "ymax") ymax.text = str(int(y2)) tree = ET.ElementTree(root) tree.write(os.path.join(output_dir, f"{os.path.splitext(os.path.basename(image_path))[0]}.xml"), encoding='utf-8', xml_declaration=True)

参数说明:

  • bboxes:列表,每个元素为(x1,y1,x2,y2)像素坐标元组,来自Excel原始标注;
  • class_names:列表,对应每个bbox的类别名,本数据集仅red_ant一类;
  • output_dir:生成XML的存放路径,需与VOC标准目录结构匹配(即Annotations/子目录);
  • 关键细节:xmin/ymin/xmax/ymax必须为int类型,若传入float会导致部分VOC解析器(如pascal_voc.py)报ValueError: could not convert string to float。

2.3 COCO格式生成:JSON中categories与annotations的ID映射陷阱

MS COCO要求JSON文件包含images、categories、annotations三大顶层字段,其中categories定义类别ID(id)与名称(name)映射,annotations中每个category_id必须与categories中的id严格一致。本数据集采用单类别设计,但categories仍按COCO标准定义id=1(而非0),避免与某些框架(如MMDetection)的默认索引冲突:

# coco_generator.py 关键片段 coco_dict = { "images": [], "categories": [ { "id": 1, # 强制设为1!YOLO训练时class_id从0开始,但COCO标准从1开始 "name": "red_ant", "supercategory": "insect" } ], "annotations": [] } for idx, image_path in enumerate(image_list): # 添加images条目 img_info = { "id": idx + 1, # COCO images.id从1开始 "file_name": os.path.basename(image_path), "width": img_width, "height": img_height, "date_captured": "", # 可留空 "license": 1 } coco_dict["images"].append(img_info) # 添加annotations条目(每个bbox一个) for bbox_idx, (x1, y1, x2, y2) in enumerate(bboxes_list[idx]): # COCO bbox格式为[x,y,width,height],注意x,y是左上角,非中心点 x = float(x1) y = float(y1) w = float(x2 - x1) h = float(y2 - y1) annotation = { "id": len(coco_dict["annotations"]) + 1, "image_id": idx + 1, "category_id": 1, # 必须与categories中id=1对应 "bbox": [x, y, w, h], "area": float(w * h), "iscrowd": 0 } coco_dict["annotations"].append(annotation) # 写入JSON(注意indent=4便于调试) with open(os.path.join(output_dir, "annotations.json"), "w") as f: json.dump(coco_dict, f, indent=4)

参数说明:

  • images.id与annotations.image_id必须双向匹配,否则pycocotools加载时会报KeyError: 'image_id';
  • bbox坐标必须为float(COCO官方要求),但值必须精确到小数点后1位(round(x,1)),避免浮点精度导致area计算偏差;
  • category_id设为1而非0,这是本数据集适配MMDetection、Detectron2等主流框架的关键——这些框架默认categories[0].id=1。

2.4 YOLO格式生成:txt文件命名规则与归一化坐标的致命精度

YOLO TXT格式要求:文件名与图像同名(仅扩展名不同),每行class_id x_center y_center width height,所有坐标归一化到[0,1]区间。本数据集采用双精度归一化(保留6位小数),解决YOLOv8训练时因坐标截断导致的bbox偏移问题:

# yolo_generator.py 关键片段 def convert_to_yolo_format(image_path, bboxes, class_names, output_dir, class_map={"red_ant": 0}): img = cv2.imread(image_path) h, w = img.shape[:2] yolo_lines = [] for i, (x1, y1, x2, y2) in enumerate(bboxes): # 归一化:x_center = (x1+x2)/2/w, y_center = (y1+y2)/2/h x_center = round((x1 + x2) / 2.0 / w, 6) # 强制6位小数!YOLOv8对精度敏感 y_center = round((y1 + y2) / 2.0 / h, 6) width = round((x2 - x1) / w, 6) height = round((y2 - y1) / h, 6) class_id = class_map.get(class_names[i], 0) yolo_line = f"{class_id} {x_center} {y_center} {width} {height}" yolo_lines.append(yolo_line) # 写入txt文件(与图像同名) txt_path = os.path.join(output_dir, f"{os.path.splitext(os.path.basename(image_path))[0]}.txt") with open(txt_path, "w") as f: f.write("\n".join(yolo_lines)) # 调用示例 convert_to_yolo_format( image_path="dataset_raw/images/IMG_0001.jpg", bboxes=[(120, 85, 180, 145)], # 像素坐标 class_names=["red_ant"], output_dir="labels/yolo/", class_map={"red_ant": 0} )

参数说明:

  • class_map:字典映射,本数据集仅{"red_ant": 0},但预留扩展接口;
  • round(..., 6):必须6位小数,YOLOv8的Dataset类在__getitem__中会将字符串转为float32,若原始txt只有3位小数,多次训练后坐标累积误差可达2–3像素;
  • txt_path:路径必须与YOLO训练配置中的train: labels/yolo/路径一致,否则FileNotFoundError。

3. 划分脚本深度解析:如何用3个参数控制train/val/test比例、随机种子、跨设备一致性?

3.1 核心参数设计:--ratio、--seed、--group_by的组合策略

划分脚本split_dataset.py提供三个核心参数,覆盖90%的业务场景:

参数类型默认值作用典型值示例
--ratiofloat list[0.7, 0.2, 0.1]train/val/test比例,总和必须为1.0[0.6, 0.25, 0.15]
--seedint42随机种子,保证相同输入下划分结果完全一致12345(团队协作时统一设此值)
--group_bystr"none"分组依据,避免同一拍摄批次/设备/日期的图像被拆散"date"(按拍摄日期分组)、"camera_id"(按相机编号)
# 示例1:标准7:2:1划分,固定随机种子 python split_dataset.py \ --image_dir dataset_raw/images/ \ --label_dir dataset_raw/annotations/ \ --output_dir dataset_split/ \ --ratio 0.7 0.2 0.1 \ --seed 42 # 示例2:按拍摄日期分组划分(防止时间泄漏) python split_dataset.py \ --image_dir dataset_raw/images/ \ --label_dir dataset_raw/annotations/ \ --output_dir dataset_split_date/ \ --ratio 0.6 0.25 0.15 \ --seed 12345 \ --group_by date

逻辑说明:

  • 当--group_by设为"date"时,脚本会解析图像EXIF中的DateTimeOriginal字段,将同一天拍摄的图像视为一组,再对组进行shuffle和划分——这样val/test集中不会出现与train集时间重叠的样本,符合时序预测的严谨性;
  • --seed不仅影响shuffle顺序,还影响train_test_split的随机状态,必须显式指定,否则不同机器运行结果不同,导致实验不可复现。

3.2 目录结构生成规则:YOLO训练所需的train/val/test三级嵌套

脚本生成的目录结构严格遵循Ultralytics YOLOv8官方要求:

dataset_split/ ├── images/ │ ├── train/ │ │ ├── IMG_0001.jpg │ │ └── ... │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ │ ├── IMG_0001.txt │ │ └── ... │ ├── val/ │ └── test/ └── dataset.yaml # 自动生成的配置文件

dataset.yaml内容示例:

train: ../images/train val: ../images/val test: ../images/test nc: 1 names: ['red_ant'] # 自动计算的统计信息(供调试用) stats: train_images: 700 val_images: 200 test_images: 100 total_annotations: 2347

关键细节:

  • train/val/test路径为相对路径,指向images/子目录,而非绝对路径——这是Ultralytics要求的,写成绝对路径会导致FileNotFoundError;
  • nc: 1和names: ['red_ant']由脚本自动推断,无需手动修改;
  • stats字段为只读信息,不参与训练,但可快速验证划分是否符合预期。

3.3 跨格式标签同步机制:如何保证VOC/COCO/YOLO三套标签在划分后仍一一对应?

划分脚本的核心能力是原子级同步操作:它不分别处理images/labels,而是以图像文件名为key,将同一张图的VOC XML、COCO JSON、YOLO TXT、原始JPEG作为一个原子单元移动。伪代码逻辑如下:

# split_dataset.py 核心逻辑 all_image_files = sorted(glob.glob(os.path.join(image_dir, "*.jpg"))) # 构建映射字典:{image_name: {voc: path, coco: path, yolo: path}} file_map = {} for img_path in all_image_files: base_name = os.path.splitext(os.path.basename(img_path))[0] file_map[base_name] = { "image": img_path, "voc": os.path.join(label_dir, "voc", f"{base_name}.xml"), "coco": os.path.join(label_dir, "coco", "annotations.json"), # 注意:COCO是单文件 "yolo": os.path.join(label_dir, "yolo", f"{base_name}.txt") } # 按group_by分组(如date) groups = group_files_by_exif(file_map, group_by="date") # 对每组shuffle,再按ratio切分 train_group, val_group, test_group = split_groups(groups, ratio=[0.7,0.2,0.1], seed=42) # 批量复制:确保同一base_name的所有格式文件进入同一集合 for group_name, group_files in [("train", train_group), ("val", val_group), ("test", test_group)]: for base_name in group_files: # 复制image shutil.copy(file_map[base_name]["image"], os.path.join(output_dir, "images", group_name, f"{base_name}.jpg")) # 复制voc shutil.copy(file_map[base_name]["voc"], os.path.join(output_dir, "labels", "voc", group_name, f"{base_name}.xml")) # 复制yolo(COCO单独处理) shutil.copy(file_map[base_name]["yolo"], os.path.join(output_dir, "labels", "yolo", group_name, f"{base_name}.txt"))

参数说明:

  • group_files:列表,存储base_name(如IMG_0001),而非完整路径,避免路径拼接错误;
  • shutil.copy:使用copy而非move,保留原始数据集不变,符合科研数据管理规范;
  • COCO JSON特殊处理:因是单文件,脚本会在labels/coco/下为每个split生成独立JSON(train.json,val.json,test.json),通过过滤annotations中的image_id实现。

3.4 避坑:划分脚本常见问题排查(现象→原因→解决)

现象1:dataset.yaml中train: ../images/train路径报错No such file or directory

原因:脚本生成的dataset.yaml路径是相对于ultralytics安装目录的,但用户在/home/user/yolo_project/下运行训练命令,而dataset.yaml被放在/home/user/dataset_split/。Ultralytics默认从当前工作目录读取yaml,../images/train会解析为/home/user/images/train而非/home/user/dataset_split/images/train。
解决:运行训练前,cd到dataset_split/目录,或修改dataset.yaml为绝对路径:train: /home/user/dataset_split/images/train。

现象2:划分后YOLO TXT文件为空(0字节)

原因:原始标注Excel中某行x_min或y_min为负数(拍摄时相机抖动导致标注框越界),yolo_generator.py计算x_center时出现NaN,round(NaN,6)返回nan,写入txt后为0 nan nan nan nan,YOLOv8解析时报ValueError: invalid literal for float()。
解决:在yolo_generator.py中增加边界检查:

# 在convert_to_yolo_format函数内添加 if x1 < 0: x1 = 0 if y1 < 0: y1 = 0 if x2 > w: x2 = w if y2 > h: y2 = h
现象3:COCO JSON中annotations数量与images数量不匹配,pycocotools报KeyError: 'image_id'

原因:group_by=date时,某天拍摄的图像在Excel中标注缺失(如IMG_0501.jpg有图无标注),脚本仍将该图像加入images列表,但未生成对应annotations。
解决:脚本增加预检查:遍历file_map,若某base_name的voc或yolo路径不存在,则跳过该图像,并打印警告:

if not os.path.exists(file_map[base_name]["voc"]) or not os.path.exists(file_map[base_name]["yolo"]): print(f"Warning: {base_name} missing VOC or YOLO label, skipped.") continue
现象4:--seed 42在不同Python版本下划分结果不同

原因:Python 3.9+的random.shuffle()算法变更,导致相同seed在不同版本产生不同序列。
解决:脚本强制使用numpy.random.Generator替代内置random:

import numpy as np rng = np.random.default_rng(seed=42) rng.shuffle(group_list) # 替代 random.shuffle(group_list)
现象5:--group_by camera_id时,EXIF中无CameraModel字段,脚本崩溃

原因:部分手机拍摄图像EXIF精简,缺失CameraModel。
解决:增加fallback逻辑,当EXIF字段不存在时,用文件名前缀分组(如IMG_、DSC_):

try: camera_id = exif_data.get("CameraModel", "unknown") except: camera_id = os.path.basename(img_path)[:3] # 取前3字符

4. 训练教程实战:从conda环境搭建到mAP@0.5可视化,避开YOLOv8的5个玄学坑

4.1 环境搭建:为什么必须用conda而非pip安装torch?

YOLOv8对CUDA版本极其敏感。本教程要求torch==2.0.1+cu118(CUDA 11.8),而pip安装的torch默认链接cu117或cu121,导致RuntimeError: CUDA error: no kernel image is available for execution on the device。conda能精确控制CUDA toolkit版本:

# 创建专用环境(避免污染主环境) conda create -n yolo_redant python=3.9 conda activate yolo_redant # 安装指定CUDA版本的torch(官方推荐方式) pip3 install torch==2.0.1+cu118 torchvision==0.15.2+cu118 --extra-index-url https://download.pytorch.org/whl/cu118 # 安装Ultralytics(必须>=8.0.200,修复了VOC标签解析bug) pip install ultralytics==8.0.200 # 验证CUDA可用性 python -c "import torch; print(torch.cuda.is_available(), torch.version.cuda)" # 输出应为 True 11.8

参数说明:

  • python=3.9:YOLOv8官方测试版本,3.10+存在cv2兼容性问题;
  • torch==2.0.1+cu118:+cu118后缀表示编译时链接CUDA 11.8,必须与系统nvidia-smi显示的驱动版本匹配(驱动>=520.61.05);
  • ultralytics==8.0.200:修复了v8/utils/ops.py中non_max_suppression对VOC bbox坐标解析的溢出bug。

4.2 数据校验:用3行代码发现90%的标签错误

训练前必须运行ultralytics.data.utils.check_det_dataset(),它会扫描所有标签并报告问题:

from ultralytics.data.utils import check_det_dataset check_det_dataset("dataset_split/dataset.yaml")

典型输出与解读:

  • WARNING: 3 labels contain 0 instances:3张图的TXT为空,需检查原始标注是否遗漏;
  • ERROR: 12 labels exceed image bounds:12个bbox的x_center>1.0或y_center>1.0,说明归一化计算错误;
  • WARNING: 5 images missing labels:5张图有JPG但无TXT,需补标注或从划分中剔除。

提示:此函数会生成dataset_split/labels/train.cache缓存文件,首次运行较慢(约2分钟),后续训练自动加载,提速3倍。

4.3 模型微调:为什么--epochs 100不如--epochs 50+早停?

红蚂蚁数据集仅1000张图,过拟合风险极高。本教程采用EarlyStopping策略,监控val/box_loss,连续10轮无下降则终止:

# 启动训练(关键参数已加粗) yolo detect train \ data=dataset_split/dataset.yaml \ model=yolov8s.pt \ # 使用s模型(12MB),平衡速度与精度 epochs=50 \ batch=16 \ # 根据GPU显存调整:RTX3090可设32,GTX1080Ti限12 imgsz=640 \ # 输入尺寸,640是YOLOv8默认,**禁止设1280**(显存爆炸) name=redant_v8s_640 \ patience=10 \ # **早停耐心值,必须设!** optimizer=AdamW \ # 比SGD收敛更快,适合小数据集 lr0=0.001 \ # 初始学习率,大模型用0.01,s模型用0.001 cos_lr \ # 余弦退火,比step衰减更稳定 cache=True # 启用内存缓存,加速数据加载

参数说明:

  • patience=10:早停阈值,避免在val loss平台期继续训练;
  • cache=True:将图像预处理结果缓存到RAM,减少IO等待,训练速度提升40%;
  • cos_lr:余弦学习率调度,比linear或step更平滑,防止loss震荡。

4.4 结果可视化:如何从results.csv提取mAP@0.5并画趋势图?

训练完成后,runs/detect/redant_v8s_640/results.csv包含每轮指标。用pandas分析:

import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("runs/detect/redant_v8s_640/results.csv") # 提取关键列:epoch, metrics/mAP50(B), train/box_loss, val/box_loss plt.figure(figsize=(12, 4)) plt.subplot(1, 3, 1) plt.plot(df['epoch'], df['metrics/mAP50(B)']) plt.title('mAP@0.5') plt.xlabel('Epoch') plt.ylabel('mAP') plt.subplot(1, 3, 2) plt.plot(df['epoch'], df['train/box_loss'], label='train') plt.plot(df['epoch'], df['val/box_loss'], label='val') plt.title('Box Loss') plt.xlabel('Epoch') plt.ylabel('Loss') plt.legend() plt.subplot(1, 3, 3) plt.plot(df['epoch'], df['lr/pg0']) plt.title('Learning Rate') plt.xlabel('Epoch') plt.ylabel('LR') plt.tight_layout() plt.savefig("runs/detect/redant_v8s_640/training_curve.png", dpi=300) plt.show()

关键指标解读:

  • metrics/mAP50(B):IoU阈值0.5下的mAP,红蚂蚁检测达标线为≥0.75(本数据集实测达0.78);
  • val/box_loss:验证集定位损失,若持续高于train/box_loss,说明过拟合;
  • lr/pg0:主参数组学习率,应呈平滑余弦下降。

4.5 避坑:YOLOv8训练5大玄学问题(现象→原因→解决)

现象1:CUDA out of memory即使batch=1也报错

原因:imgsz=640时,YOLOv8的AutoShape模块会预加载多尺度推理,占用额外显存。
解决:训练时禁用AutoShape,在train.py开头添加:

import torch torch.backends.cudnn.benchmark = False # 关闭cudnn benchmark
现象2:val/box_loss从第1轮就为inf

原因:dataset.yaml中train/val/test路径末尾多了斜杠(如train: ../images/train/),Ultralytics解析为../images/train//*.jpg,glob匹配失败,val集为空。
解决:检查dataset.yaml,确保路径无尾部斜杠。

现象3:训练10轮后mAP@0.5始终为0.0

原因:YOLO TXT中class_id写成1而非0,但dataset.yaml中nc=1,模型只学习class_id=0,class_id=1被忽略。
解决:用grep -r "1 " dataset_split/labels/yolo/检查,修正为0。

现象4:results.csv中metrics/mAP50(B)列全为0.0

原因:val集中图像无标签(TXT为空),COCO评估时pycocotools返回0。
解决:运行check_det_dataset(),删除无标签图像。

现象5:predict时检测框全是虚线,不显示置信度

原因:conf=0.25默认值过低,红蚂蚁小目标需提高阈值。
解决:预测时加参数--conf 0.4:

yolo detect predict model=runs/detect/redant_v8s_640/weights/best.pt source=test_img.jpg conf=0.4

5. 进阶技巧:用VOC标签反向校验YOLO训练效果——3步定位漏检与误检根源

5.1 为什么VOC XML比YOLO TXT更适合根因分析?

YOLO TXT只存归一化坐标,丢失原始像素信息;VOC XML保留<xmin><ymin><xmax><ymax>像素坐标,可直接叠加到原图验证。更重要的是,VOC的<difficult>字段(本数据集设为0)能标记易混淆样本(如红蚂蚁与黑蚂蚁幼虫),而YOLO无此机制。因此,当模型在val集上mAP偏低时,我们用VOC XML反向追溯:

  1. 提取YOLO预测结果:用model.predict()获取Boxes对象;
  2. 映射回VOC坐标系:将YOLO归一化坐标转为像素坐标;
  3. 与VOC真值比对:计算IoU,分类漏检(True Negative)、误检(False Positive)、错检(False Negative)。

5.2 步骤1:导出YOLO预测的像素级bbox(非归一化)

from ultralytics import YOLO import cv2 model = YOLO("runs/detect/redant_v8s_640/weights/best.pt") results = model("dataset_split/images/val/IMG_0001.jpg", verbose=False) # 获取第一张图的预测结果 result = results[0] # boxes.xyxy 是 [x1,y1,x2,y2] 像素坐标(已自动转回) pred_boxes = result.boxes.xyxy.cpu().numpy() # shape: (N, 4) pred_conf = result.boxes.conf.cpu().numpy() # shape: (N,) pred_cls = result.boxes.cls.cpu().numpy() # shape: (N,) # 读取原图获取尺寸 img = cv2.imread("dataset_split/images/val/IMG_0001.jpg") h, w = img.shape[:2] print(f"Image size: {w}x{h}") print(f"Predicted boxes: {pred_boxes}")

逻辑说明:

  • result.boxes.xyxy直接返回像素坐标,无需手动乘以imgsz——这是YOLOv8 v8.0.200+的改进,旧版需*640再缩放;
  • cpu().numpy()确保坐标为float64,避免GPU张量运算精度丢失。

5.3 步骤2:解析对应VOC XML获取真值bbox

import xml.etree.ElementTree as ET def parse_voc_xml(xml_path): tree = ET.parse(xml_path) root = tree.getroot() bboxes = [] for obj in root.findall('object'): name = obj.find('name').text if name != "red_ant": # 跳过其他类别 continue bbox = obj.find('bndbox') x1 = int(bbox.find('xmin').text) y1 = int(bbox.find('ymin').text) x2 = int(bbox.find('xmax').text) y2 = int(bbox.find('ymax').text) bboxes.append([x1, y1, x2, y2]) return bboxes # 获取真值 voc_path = "dataset_split/labels/voc/val/IMG_0001.xml" gt_boxes = parse_voc_xml(voc_path) print(f"Ground truth <p> <a href="https://download.csdn.net/download/m0_64879847/88240956" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 11:13:46

大模型推理优化实战:TensorRT-LLM与vLLM协同部署指南

1. 项目概述&#xff1a;Model-Optimizer 不是工具名&#xff0c;而是一类工程实践的统称“Model-Optimizer”这个标题乍看像某个开源库或商业软件的名字&#xff0c;但结合你提供的热搜词——TensorRT-LLM、vLLM、NVIDIA、PT文件转换TensorRT、Docker部署、RTX 4060 Laptop GP…

作者头像 李华
网站建设 2026/9/29 11:12:36

人脑肿瘤检测数据集:5000张CT图三格式标注与YOLO11训练实战

简介&#xff1a;这份资源面向医学影像分析与目标检测方向的开发者、研究生及算法工程师&#xff0c;提供真实CT场景下的人脑肿瘤检测数据集&#xff0c;可用于肿瘤检测项目训练&#xff0c;也可作为通用人脑检测数据的补充。数据集共5000张高质量图片&#xff0c;采用labelimg…

作者头像 李华
网站建设 2026/9/29 11:04:30

基于DeepSeek的政务政策文件智能解读系统建设方案

简介&#xff1a;一份37页的PDF文档&#xff0c;以DeepSeek技术为主线&#xff0c;系统讲解政策文件智能解读系统的建设全流程。面向政务信息化、智慧政务项目团队及AI应用实践者&#xff0c;文档从政务数字化背景与政策解读需求切入&#xff0c;依次展开DeepSeek技术原理、系统…

作者头像 李华
网站建设 2026/9/29 10:57:21

论文格式检查怎么不漏项?排查的四步清单

盲审意见里真正把稿子退回来的&#xff0c;常常不是论证薄弱&#xff0c;而是一处表题编号断档、一条文末条目缺了页码。格式排查的意义&#xff0c;就是把这类细节从「凭记忆」变成「照单勾选」——每一类格式都能在清单上被勾到&#xff0c;漏项的概率才会切实降下来。知学术…

作者头像 李华
网站建设 2026/9/29 10:56:33

TensorFlow 2.x实战指南:从环境配置到生产部署的完整链路

1. 为什么2024年还有人劝你学TensorFlow&#xff1a;直击版本选择的现实先交代一下背景。我接触TensorFlow的时间不算短&#xff0c;从1.x时代被Session和Graph搞得焦头烂额&#xff0c;到2.x之后Keras几乎成为默认入口&#xff0c;再到现在和PyTorch在社区里各占半壁江山。很多…

作者头像 李华