智能零售柜商品识别:VOC转YOLO格式与YOLOv8训练实战
简介面向智能零售结算场景的商品识别检测数据集适合从事计算机视觉目标检测的开发者、学生及算法工程师用于训练和评估自动结算系统中的商品识别模型。数据集共5422张已标注图片涵盖113类商品并已按训练集3796张、验证集1084张、测试集542张完成划分可直接用于PaddleDetection、PaddleX等主流框架。压缩包共8057个文件包含2685张jpg图像、2685个xml标注文件与2687个txt标签文件同时提供VOC与YOLO两种格式兼容YOLO系列、SSD、PP-YOLO等算法包体约881.5MB。已有597人学习下载。借助完整标注与标准划分读者可快速复现检测流程、对比不同模型表现相关项目最高mAP可达96.41为智能零售商品识别研究提供可靠的数据基础。1. 智能零售柜商品识别5000 张双格式数据集到底能跑出什么智能零售柜的商品识别说白了就是让柜子里的摄像头知道“谁拿了什么”。这件事听起来简单真正落地时最卡脖子的往往不是模型结构而是数据。你拿不到足够多、足够杂、标注足够准的商品图后面调参调出花来也没用。这个标题里的“5000张VOC格式和YOLO格式标签”核心价值就在于它同时给了两套标注VOC 的 XML 适合做数据审查和格式转换的中间态YOLO 的 TXT 可以直接喂给 YOLOv5/v8 这类检测器。对做智能柜、无人零售、货架盘点的人来说这是一份能直接开跑的起点数据。适合谁适合手上已经有柜体硬件、想先验证识别链路是否通的人也适合学生做课程设计或比赛 baseline。但别指望 5000 张就能覆盖你真实场景的全部 SKU它更像一块敲门砖不是终点。2. 先搞清楚 VOC 和 YOLO 两套标签的差异在哪2.1 标注坐标系不同转换时最容易翻车VOC 格式的标注文件是 XML每个目标用bndbox记录xmin, ymin, xmax, ymax这是绝对像素坐标原点在图片左上角。YOLO 格式则是每张图对应一个 TXT每行class_id x_center y_center width height全部是归一化到 0~1 的相对值。很多人第一次转换时直接拿 VOC 的坐标除以图片宽高就写进 TXT结果训练时框全飘了原因通常是忘了 VOC 的坐标是包含边界的而 YOLO 的宽高是框的绝对宽高再归一化不是右下角坐标。正确做法是先算w xmax - xminh ymax - ymin再分别除以图片宽高。2.2 类别映射表必须两边一致VOC 的 XML 里写的是类别名字符串YOLO 的 TXT 里写的是从 0 开始的整数索引。如果你直接拿 VOC 的类别名去训 YOLO第一轮就会报类别不匹配。常见做法是维护一个classes.txt每行一个类别名行号就是 YOLO 的 class_id。转换脚本里读 XML 的name去classes.txt里查索引查不到就报错并记录别默默跳过否则你会得到一份“看起来能跑但少类”的数据集。2.3 图片和标签的目录结构决定你后面省不省心VOC 常见结构是JPEGImages/放图Annotations/放 XML。YOLO 常见结构是images/train/、images/val/、labels/train/、labels/val/图片和标签同名不同后缀。如果你拿到的压缩包是混在一起的第一步不是急着训模型而是先按下面这个脚本把目录理清楚。我一般会先跑一遍统计看看有没有图片没有对应标签、或者标签里类别为空的情况。import os import xml.etree.ElementTree as ET from pathlib import Path # 统计 VOC 数据集中图片与 XML 的配对情况 img_dir Path(JPEGImages) xml_dir Path(Annotations) img_stems {p.stem for p in img_dir.glob(*.jpg)} xml_stems {p.stem for p in xml_dir.glob(*.xml)} only_img img_stems - xml_stems only_xml xml_stems - img_stems print(f图片无标签: {len(only_img)}) print(f标签无图片: {len(only_xml)}) # 检查每个 XML 的类别分布 from collections import Counter cls_counter Counter() for xml_path in xml_dir.glob(*.xml): tree ET.parse(xml_path) root tree.getroot() for obj in root.findall(object): name obj.find(name).text cls_counter[name] 1 print(类别分布:, cls_counter.most_common())这段脚本先做配对检查再做类别统计。参数上你只需要改img_dir和xml_dir两个路径。如果only_img数量很大说明你的数据里有一批图没标训练前要么补标要么删掉如果某个类别只有个位数后面训练时这类基本学不动考虑合并或补充。3. 把 VOC 转成 YOLO转换脚本与四个边界坑3.1 转换脚本的核心逻辑与参数说明下面这个脚本是我在多个零售柜项目里反复用过的版本输入是 VOC 的JPEGImages和Annotations输出是 YOLO 的images和labels同时按 8:2 划分 train/val。关键参数有三个classes_file指定类别映射val_ratio控制验证集比例copy_images决定是复制还是软链接图片。零售柜场景图片不大我一般直接复制省得后面路径乱了。import shutil import random import xml.etree.ElementTree as ET from pathlib import Path from PIL import Image def voc_to_yolo(img_dir, xml_dir, out_dir, classes_file, val_ratio0.2, copy_imagesTrue): img_dir Path(img_dir) xml_dir Path(xml_dir) out_dir Path(out_dir) # 读取类别映射 with open(classes_file, r, encodingutf-8) as f: classes [line.strip() for line in f if line.strip()] cls_to_id {name: i for i, name in enumerate(classes)} # 收集所有有效样本 samples [] for xml_path in xml_dir.glob(*.xml): stem xml_path.stem img_path img_dir / f{stem}.jpg if not img_path.exists(): continue tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in cls_to_id: continue bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 边界裁剪防止越界 xmin max(0, min(xmin, w - 1)) ymin max(0, min(ymin, h - 1)) xmax max(0, min(xmax, w - 1)) ymax max(0, min(ymax, h - 1)) if xmax xmin or ymax ymin: continue xc (xmin xmax) / 2.0 / w yc (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_to_id[name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) if lines: samples.append((img_path, lines)) random.shuffle(samples) split int(len(samples) * (1 - val_ratio)) train_samples samples[:split] val_samples samples[split:] for subset, subset_samples in [(train, train_samples), (val, val_samples)]: img_out out_dir / images / subset lbl_out out_dir / labels / subset img_out.mkdir(parentsTrue, exist_okTrue) lbl_out.mkdir(parentsTrue, exist_okTrue) for img_path, lines in subset_samples: if copy_images: shutil.copy(img_path, img_out / img_path.name) else: os.symlink(img_path.resolve(), img_out / img_path.name) with open(lbl_out / f{img_path.stem}.txt, w) as f: f.write(\n.join(lines)) print(ftrain: {len(train_samples)}, val: {len(val_samples)}) voc_to_yolo(JPEGImages, Annotations, yolo_dataset, classes.txt, val_ratio0.2)逻辑上先读类别表再逐 XML 解析做边界裁剪和有效性检查最后按比例划分并写出。参数val_ratio0.2对 5000 张来说验证集约 1000 张够用如果类别极不均衡建议改成按类别分层抽样否则小类可能全被分到训练集。copy_imagesTrue会占双倍磁盘但路径干净适合第一次跑通。3.2 四个边界坑越界、空标签、同名不同类、图片损坏第一个坑是越界框。VOC 标注里偶尔出现xmax大于图片宽度的情况直接归一化会得到大于 1 的值YOLO 训练时虽然不报错但框会异常。上面脚本里做了min(xmax, w-1)的裁剪这是血泪经验别省。第二个坑是空标签。有些 XML 里object数量为 0转换后 TXT 是空文件。YOLO 默认会忽略空标签图但如果你用某些版本的数据加载器空文件可能导致报错。我的做法是直接跳过这些图不写入数据集。第三个坑是同名不同类。零售柜里经常有“可乐罐”和“可乐瓶”这种相似类别如果classes.txt里写重了或者映射错了模型会学得四不像。转换前一定用前面的统计脚本看一眼类别分布确认没有拼写不一致。第四个坑是图片损坏。5000 张里难免有几张打不开的PIL 读取时会抛异常。建议在转换前加一轮Image.open校验损坏的直接剔除并记录文件名别让它在训练中途炸掉。4. 用 YOLOv8 训练这份数据集的完整命令与参数4.1 环境准备与数据配置文件假设你已经装好了 ultralytics没装的话pip install ultralytics一行搞定。数据配置文件retail.yaml要写清楚路径和类别数。注意path写你实际的数据集根目录train和val写相对路径。nc是类别数names按classes.txt的顺序写顺序错了模型输出的类别名就全乱。# retail.yaml path: /data/yolo_dataset train: images/train val: images/val nc: 10 names: 0: cola_can 1: cola_bottle 2: water_bottle 3: chips_small 4: chips_large 5: candy_box 6: tissue_pack 7: milk_box 8: juice_bottle 9: unknown_item4.2 训练命令与关键参数怎么调下面这条命令是我在单卡 3090 上跑 5000 张零售柜数据的常用配置。imgsz640是 YOLOv8 的默认输入尺寸零售柜商品通常占画面比例不大640 够用如果小目标漏检多可以提到 960但显存和耗时都会涨。batch16是 24G 显存下的稳妥值你显存小就降到 8。epochs100对 5000 张来说通常能收敛但要看mAP50曲线如果 80 轮后还在涨就加到 150。yolo detect train \ dataretail.yaml \ modelyolov8n.pt \ imgsz640 \ epochs100 \ batch16 \ lr00.01 \ lrf0.01 \ patience20 \ device0 \ projectruns/retail \ nameexp1参数说明modelyolov8n.pt是最小模型适合先跑通链路如果精度不够换yolov8s.pt或yolov8m.pt。lr0初始学习率 0.01 是默认值数据量小可以降到 0.005 防止震荡。patience20表示 20 轮没提升就早停省时间。device0指定第一块 GPUCPU 训练会慢到怀疑人生。4.3 训练过程中看什么指标跑起来后重点盯三个box_loss是否稳定下降mAP50是否在涨cls_loss有没有突然飙升。如果cls_loss飙升多半是类别映射错了或者某类样本太少。如果mAP50卡在 0.3 以下先别调模型回去看数据——大概率是标注框质量差或者类别混淆严重。零售柜场景里透明包装和反光商品最容易让模型翻车这时候不是加数据就是加数据增强没有捷径。5. 避坑与排查零售柜数据集训练中最容易踩的五个雷5.1 现象训练 loss 正常但验证 mAP 极低原因通常是训练集和验证集分布不一致。比如你的 5000 张里某些类别只在训练集出现验证集里没有mAP 自然低。解决方法是划分时按类别分层抽样确保每个类别在 train 和 val 里都有。另一个原因是验证集的标签格式和训练集不一致比如一个用了归一化坐标一个用了绝对坐标检查labels/val里的数值范围是否在 0~1。5.2 现象模型把“可乐罐”识别成“可乐瓶”原因一般是两类样本数量差距大或者标注时边界模糊。零售柜里罐和瓶的形状差异其实不小但如果你的数据里瓶的样本是罐的 10 倍模型会偏向瓶。解决办法是过采样小类或者在损失函数里给小类更高权重。YOLOv8 不直接支持类别权重但你可以通过复制小类图片来平衡。5.3 现象推理时框位置偏移严重原因多半是转换时坐标算错了。回去检查 VOC 的xmax是否被当成了宽YOLO 的width是(xmax - xmin) / w不是xmax / w。这个错误非常常见而且训练时 loss 看起来正常只有推理时才会暴露。建议转换后随机抽 10 张图用脚本把 YOLO 标签画回图上肉眼确认框对齐。5.4 现象训练到一半报显存不足原因可能是batch太大或者imgsz太高。5000 张 640 分辨率下batch16在 8G 显存上会炸。解决办法是降batch到 8 或 4同时开ampTrue混合精度。如果还不行把imgsz降到 512但小目标召回会掉需要权衡。5.5 现象验证集图片没有对应标签文件原因通常是转换脚本里跳过了空标签图但验证集划分时又把这些图算进去了。检查labels/val目录下是否有缺失的 TXT。我的习惯是转换后跑一遍for f in images/val/*.jpg; do test -f labels/val/$(basename $f .jpg).txt || echo $f; done把没有标签的图删掉保证训练和验证的输入一致。6. 进阶技巧用 ReID 思路补足商品识别的类内差异6.1 为什么检测之外还要考虑 ReID零售柜里同一类商品可能有不同包装版本比如可乐的节日限定罐和普通罐检测模型会把它们都标成“可乐罐”但如果你要做精准库存需要区分具体 SKU。这时候检测只能给你“这是可乐”ReID 才能告诉你“这是哪一款可乐”。ReID 数据集的核心是同一目标在不同视角、光照下的多张图你可以从 5000 张检测数据里按类别裁剪出小图构建一个简易的 ReID 训练集。6.2 从检测数据构建 ReID 样本的脚本下面这段代码把 YOLO 格式的标签还原成裁剪图按类别存到不同文件夹每个文件夹里就是同一类商品的不同实例。注意这里用的是训练集图片验证集不要动否则评估会泄漏。import cv2 from pathlib import Path def crop_by_yolo(img_dir, lbl_dir, out_dir, classes): img_dir Path(img_dir) lbl_dir Path(lbl_dir) out_dir Path(out_dir) for img_path in img_dir.glob(*.jpg): lbl_path lbl_dir / f{img_path.stem}.txt if not lbl_path.exists(): continue img cv2.imread(str(img_path)) h, w img.shape[:2] with open(lbl_path) as f: for i, line in enumerate(f): parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) xc, yc, bw, bh map(float, parts[1:]) x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) x1, y1 max(0, x1), max(0, y1) x2, y2 min(w, x2), min(h, y2) if x2 x1 or y2 y1: continue crop img[y1:y2, x1:x2] cls_name classes[cls_id] save_dir out_dir / cls_name save_dir.mkdir(parentsTrue, exist_okTrue) cv2.imwrite(str(save_dir / f{img_path.stem}_{i}.jpg), crop) classes [cola_can, cola_bottle, water_bottle, chips_small, chips_large, candy_box, tissue_pack, milk_box, juice_bottle, unknown_item] crop_by_yolo(yolo_dataset/images/train, yolo_dataset/labels/train, reid_crops, classes)逻辑是按 YOLO 标签的归一化坐标还原出绝对框裁剪后按类别存。参数上classes必须和retail.yaml里的names顺序完全一致否则类别名会错位。裁剪出来的小图可以直接喂给 ReID 模型也可以用来做数据增强把同一 SKU 的裁剪图贴回不同背景扩充检测数据。6.3 一个验证技巧用混淆矩阵定位最差的类训练完 YOLOv8 后runs/retail/exp1/下会生成confusion_matrix.png。别只看 mAP打开这张图找对角线最浅的那一格那就是模型最混淆的两个类。零售柜里常见的是“矿泉水”和“苏打水”互混因为瓶身透明、标签相似。定位到之后要么补这两类的区分性样本要么在标注时把边界画得更紧。我一般会把这个矩阵打印出来贴在工位上下一轮数据迭代就盯着这几个类补。这套流程跑下来5000 张数据从 VOC 到 YOLO 再到训练和 ReID 扩展基本能让你在半天内看到第一个可用的检测结果。但记住零售柜的真实挑战永远在长尾 SKU 和光照变化上数据集只是起点持续补数据和迭代标注才是常态。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

DeepSeek多模态模型测评实战:API调用与Prompt设计全指南

DeepSeek多模态模型测评实战:API调用与Prompt设计全指南

最近不少开发者开始关注 DeepSeek 在多模态方向上的进展。刚好我手头接了一批图片理解、OCR 抽取、图表分析类的需求,趁这个机会把 DeepSeek 最新多模态模型的测评方法和结果整理成了一份完整笔记。这篇文章不打算只罗列结论,而是把测评思路、 Prompt 设…

2026/10/4 2:25:02 阅读更多 →
yum 命令完全指南:linux-command 手册中的 RPM 软件包管理实战

yum 命令完全指南:linux-command 手册中的 RPM 软件包管理实战

文档教程 【免费下载链接】linux-command Linux命令大全搜索工具,内容包含Linux命令手册、详解、学习、搜集。https://git.io/linux 项目地址: https://gitcode.com/GitHub_Trending/linux/linux-command 点击查看 免费下载 本文是 linux-command 仓库中…

2026/10/4 2:25:02 阅读更多 →
Coursebook预处理与条件编译详解:从 include 到宏定义的完整指南

Coursebook预处理与条件编译详解:从 include 到宏定义的完整指南

Coursebook预处理与条件编译详解:从 #include 到宏定义的完整指南 【免费下载链接】coursebook Open Source Introductory Systems Programming Textbook for the University of Illinois 项目地址: https://gitcode.com/GitHub_Trending/co/coursebook Cour…

2026/10/4 2:25:02 阅读更多 →

最新新闻

构建跨平台终端工作流:不是OpenShell,而是可复现的命令行基础设施

构建跨平台终端工作流:不是OpenShell,而是可复现的命令行基础设施

1. OpenShell 是什么?它不是 Shell,也不是“开源 Shell”的简称OpenShell 这个名字在当前技术社区里存在显著的语义混淆——它既不是 Linux/macOS 原生 shell(如 bash、zsh、fish)的开源实现,也不是 Windows PowerShel…

2026/10/4 4:53:32 阅读更多 →
插件加载失败全解析:从failed to load plugins到依赖冲突排查指南

插件加载失败全解析:从failed to load plugins到依赖冲突排查指南

“plugins”这词儿本身没什么新鲜的,但如果你在搜索引擎里敲下“failed to load plugins web boot: 2 entries did not activate”或者“harness failed to load plugins”,会发现这行看似轻描淡写的报错,背后能牵出一整串关于插件机制、依赖…

2026/10/4 4:53:32 阅读更多 →
EEGLAB数据导入实战指南:从文件格式到电极定位一条龙

EEGLAB数据导入实战指南:从文件格式到电极定位一条龙

刚接触EEGLAB的时候,我绕了不少弯子。官方文档和视频教程看起来都挺规矩,但真到自己上手,第一步“往EEGLAB导入数据”就能劝退一拨人。下载完软件、把MATLAB路径设置好,双击打开EEGLAB,界面上那十几个菜单项&#xff0…

2026/10/4 4:53:32 阅读更多 →
云桌面落地实战:VDI+IDV混合架构与镜像标准化全指南

云桌面落地实战:VDI+IDV混合架构与镜像标准化全指南

简介:本资源是一份面向企业IT管理者与数字化转型实施人员的云桌面建设落地方案,聚焦桌面虚拟化技术在安全加固、集中运维与移动办公场景中的深度应用。方案系统梳理了传统PC架构下的数据泄露、终端失管、补丁滞后及业务连续性薄弱等痛点,提出…

2026/10/4 4:53:32 阅读更多 →
工业瓶装质检数据集:4500张VOC+YOLO双格式真实产线数据

工业瓶装质检数据集:4500张VOC+YOLO双格式真实产线数据

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 4:53:32 阅读更多 →
STM32驱动MR25H40CDF SPI MRAM,工业存储掉电无忧

STM32驱动MR25H40CDF SPI MRAM,工业存储掉电无忧

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 4:52:32 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:35 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:36 阅读更多 →