简介:面向工业视觉与流体力学研究的YOLO格式多目标检测数据集,专门针对工业场景中液滴、气泡及气液两相混合体的识别与定位。内含训练集1219张、验证集752张图像,标注覆盖单液滴、单气泡、液泡混合体、高密度液滴群四类目标,场景包含管道运输、流体实验、工业反应器等,兼顾稀疏与密集、单相与多相流体状态。资源共2000个文件,其中txt标注文件1971个、jpg图像27个、yaml配置文件1个、docx说明文档1个,压缩包整体约26.32MB,原生YOLO格式便于直接用于模型训练与验证。目前已有336人学习下载。标注结果经过流体力学专家校验,涵盖不同光照条件与拍摄角度,并包含气泡破裂、液滴聚合等动态过程的连续帧数据,适合密集小目标检测、多尺度识别算法优化以及两相流数值模拟验证,也可支撑工业数字孪生系统视觉模块的研发。
1. 工业液滴气泡检测:比通用目标检测更挑数据的场景
做工业视觉的人都有体会:通用目标检测数据集里那种"一个大物体占半张图"的标注,到了流体场景基本不适用。工业液滴气泡多目标检测数据集(YOLO格式,训练集1219张+验证集752张)恰恰是拿来治这种"常识失灵"的——它里面的目标大量是毫米级液滴、半透明气泡、以及密集到互相粘连的气液混合体,单张1536×1536的图里可能同时出现几十上百个目标,且光照、反射、景深都远不如公开数据集那张"干净"。适合的读者有两类:一类是做气液两相流监测、管道流体异常检测的工程师,需要快速拿到一套带专业标注的行业数据集去训练yolo系列模型;另一类是研究小目标检测、密集场景多目标检测算法的同学,想找一个比CCPD、CrowdHuman更有"工业物理感"的验证集。这份数据集的标注体系经过了流体力学专家校验,四分类严格区分单液滴、单气泡、液泡混合体和高密度液滴群,直接按YOLO格式喂进训练脚本就能跑,省掉大量清洗时间。
2. 数据与标注体系:四分类结构、文件粒度与类别不均衡
2.1 四分类为什么这么划分,边界在哪
先看类别设计。数据集的四类目标分别用0droplet(单液滴)、1bubble(单气泡)、2dropletbubble(液泡混合体)、droplet(高密度液滴群)命名,这个命名方式透露了一个关键信息:它不是一个"按物体种类"的分类法,而是"按流体形态和交互状态"的分类法。
从检测模型的角度看,这四类的区分难度是递增的。单液滴和单气泡相对好办,只要轮廓清晰、与背景对比度够,普通检测头就能学出来。真正的难点在2dropletbubble——液滴和气泡在运动中会互相挤压、合并、破裂,边界呈不规则弧线,且半透明特性导致内部纹理透出背景,模型很容易把混合体误判成"一个液滴旁边带个气泡"的两个独立目标。而droplet类更是直接指向高密度聚集场景,大量小液滴互相遮挡,标注框之间IoU可能超过0.5,这对NMS后处理是很大的压力。
这里我想提醒一个实践中的边界问题:四分类虽然严格,但实际工业场景里的目标并不总是能干净地落入某一类。比如一个正在破裂的气泡,前半帧还是1bubble,后半帧可能就变成了2dropletbubble。所以用这份数据集训练时,我一般建议把2dropletbubble当成"过渡态"来理解,预测阶段如果出现类别来回跳,优先怀疑是形态切换而不是模型不稳定。
2.2 文件命名规律与标注字段解析
文件名看起来乱,其实是有规律的。先看几个例子:
Slice248_JPG_jpg.rf.3d10af9fcc7e277e9acd8838d4291ee1.jpg Slice231_JPG_jpg.rf.e3ad448a9d3730ff9ec591193309b2f0.jpg OW3_B1-120_F8_B1-120_N45_1020342_jpg.rf.0f0343666de305000eadefc99da2a189.jpg Slice478_JPG_jpg.rf.61bb8851cd5d0888949a2bf87fe035ac.jpgSlice前缀表明这些是从连续拍摄的视频流里按帧切片得到的,Slice248这种编号大概是第248帧。OW3开头的文件则像是实验批次编号,B1-120、F8、N45这些字段推测是指定的流体参数(比如通道号、流速档位、喷嘴编号)。后面的.rf.加一长串哈希是标注工具(Roboflow)自动生成的唯一ID,下载后重命名时这个ID不要动,它对应标注文件里的原始图像引用。
标注文件是YOLO格式,每行一个目标:
0 0.4532 0.6189 0.0213 0.0198 2 0.7210 0.3345 0.0456 0.0482 droplet 0.1567 0.8871 0.1134 0.1098每一行五个字段:类别名(或类别ID)、归一化中心点x、归一化中心点y、归一化宽度w、归一化高度h。所有坐标都除以了图像宽高,所以值域在0到1之间。注意类别字段这里出现的是字符串(droplet)而不是纯数字,这在Roboflow导出时比较常见,直接用YOLO脚本训练前需要做一次标签映射,把字符串转成整数ID,否则解析器会报错。
2.3 类别不均衡的量化分析
拿到数据集第一步我建议先做类别统计,而不是急着开训。用下面这段脚本跑一遍:
import os from collections import Counter label_dir = "path/to/labels" counter = Counter() empty_files = 0 for fname in os.listdir(label_dir): if not fname.endswith(".txt"): continue path = os.path.join(label_dir, fname) with open(path, "r", encoding="utf-8") as f: lines = [line.strip() for line in f if line.strip()] if len(lines) == 0: empty_files += 1 continue for line in lines: cls = line.split()[0] counter[cls] += 1 print("类别分布:", counter) print("空标注文件数:", empty_files)这段代码做了三件事:遍历所有标注文件、按第一个字段统计类别频次、单独统计空文件数量。空文件是很容易被忽略的坑——训练时如果某张图没有标注,YOLO的训练脚本一般会跳过它,但如果验证集里混入了大量空文件,mAP会被严重稀释,看起来"什么都检测不到"。
从数据集的构成推测,droplet(高密度液滴群)类别的样本量会显著高于其他三类,因为一张图里只要出现密集液滴,标注框数量可能就是几十上百个。这种不均衡直接导致两个问题:一是模型对稀疏场景下的单液滴召回率偏低,二是mAP这个指标会被大类别"带跑",让你误以为整体效果不错,其实小类别烂得一塌糊涂。后面第5章会讲怎么正确处理这个不均衡。
3. 把数据集送进YOLO:目录组织、训练配置与首个Epoch
3.1 目录结构与data.yaml的坑
这份数据集是Roboflow导出的标准结构,默认是train/、valid/两个目录,各自包含images/和labels/子目录。下载解压后先确认目录长这样:
industrial_droplet_dataset/ ├── train/ │ ├── images/ │ │ ├── Slice248_JPG_jpg.rf.3d10af9fcc7e277e9acd8838d4291ee1.jpg │ │ └── ... │ └── labels/ │ ├── Slice248_JPG_jpg.rf.3d10af9fcc7e277e9acd8838d4291ee1.txt │ └── ... ├── valid/ │ ├── images/ │ └── labels/ ├── data.yaml └── README.txtdata.yaml是YOLO训练入口,但Roboflow导出的yaml通常写着names: ['0droplet', '1bubble', '2dropletbubble', 'droplet']这样的完整字符串,直接拿去yolov8/yolov12训练会报类别数不匹配。需要手动改成下面这样:
# data.yaml 修改要点 path: /absolute/path/to/industrial_droplet_dataset train: train/images val: valid/images nc: 4 names: 0: droplet_single # 原 0droplet,缩短类别名 1: bubble_single # 原 1bubble 2: droplet_bubble_mix # 原 2dropletbubble 3: droplet_dense # 原 高密度液滴群改yaml的核心是两件事:path必须写成绝对路径,YOLO训练脚本不会帮你推断相对路径;类别名里不要带数字前缀,否则混淆矩阵和可视化时标签会显示成奇怪的东西。还有一个常见问题是类别顺序,Roboflow导出时类别ID是固定的,你改names的顺序必须和原标注文件里的ID一致,不能因为觉得"droplet应该排第一个"就擅自调整,否则模型训练时标签全错位。
3.2 首个Epoch前的数据完整性审计
老手通常会跳过这一步直接开训,但流体类数据集不一样——大量图像来自连续帧,很容易出现标注文件缺失、图像损坏、或者某张图的标注框坐标越界(比如x+w大于1.0)。我建议在训练前花两分钟跑一次完整性审计:
from PIL import Image import os img_dir = "path/to/train/images" label_dir = "path/to/train/labels" issues = [] for fname in os.listdir(img_dir): stem = os.path.splitext(fname)[0] label_path = os.path.join(label_dir, stem + ".txt") if not os.path.exists(label_path): issues.append(f"缺失标注: {fname}") continue img_path = os.path.join(img_dir, fname) try: with Image.open(img_path) as im: w, h = im.size except Exception as e: issues.append(f"图像损坏: {fname} -> {e}") continue with open(label_path, "r") as f: for line in f: parts = line.split() if len(parts) != 5: issues.append(f"字段数不对: {label_path} -> {line}") continue _, cx, cy, bw, bh = parts[0], float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) if not (0 <= cx <= 1 and 0 <= cy <= 1 and 0 <= bw <= 1 and 0 <= bh <= 1): issues.append(f"坐标越界: {label_path} -> {line}") if cx + bw / 2 > 1.02 or cx - bw / 2 < -0.02: issues.append(f"框超出左/右边界: {label_path}") print(f"检查了 {len(os.listdir(img_dir))} 张图像,发现 {len(issues)} 个问题") for issue in issues[:20]: print(issue)这段审计脚本的核心逻辑是交叉验证图像和标注的孪生关系:每张图必须有对应的txt文件、图像必须能正常解码、标注框必须落在[0,1]区间内。为什么边界值放宽到1.02而不是严格的1.0?因为流体目标在图像边缘时,标注工具偶尔会画出中心点略超界的框,这类框在YOLO训练时不会报错,但会显著拉低边界目标的检测质量。放宽阈值之后,你可以决定是裁剪修正还是直接删除这些样本。
3.3 用YOLOv8/YOLOv12开训:命令与关键参数
数据集没问题之后,训练命令其实很简单。以yolov8为例:
yolo detect train \ data=/path/to/industrial_droplet_dataset/data.yaml \ model=yolov8m.pt \ epochs=100 \ imgsz=1536 \ batch=8 \ device=0 \ patience=20 \ project=./runs/droplet_experiment \ name=baseline_1536参数说明:imgsz=1536是根据数据集原始分辨率来的,不做resize直接保持原生尺寸训练,对小目标友好;batch=8是在常见单卡24G显存下的经验值,如果你的卡只有12G,要么降到4,要么开cache=True显存换时间;patience=20是早停,基于验证集loss连续20个epoch不下降就停止。
如果你的环境装的是yolov12,训练入口和参数基本一致,但需要注意yolov12的backbone结构变化后,对密集小目标的感受野策略不同,imgsz建议先用1280跑一轮baseline,再对比1536的效果。不要一上来就上1536,训练时间会拉长到两倍以上,而且小数据集上分辨率收益未必明显。
首次训练不必追求精度,重点看三件事:loss曲线是否正常下降、验证集mAP@0.5是否超过0.5、以及训练日志里是否有大量"WARNING: empty labels"之类的提示。第一个epoch结束时如果mAP@0.5不到0.1,不用慌,流体目标在1536分辨率下特征也不明显,通常要在10个epoch之后才有肉眼可见的提升。
4. 高密度液滴群的调参路线:小目标、遮挡与NMS
4.1 为什么默认配置在密集液滴上效果差
跑完第一轮baseline,你大概率会看到一个典型的失败模式:稀疏场景下单液滴和气泡检测得不错,但一到高密度液滴群,模型输出的框要么漏掉大半,要么把三五个液滴框成一个巨大bbox。这里的原因有两层。
第一层是锚框/标签分配策略的问题。YOLOv8默认的anchor-free分配器倾向于把GT框分配给与其中心最近的特征层级,而密集液滴群中目标尺寸小且互相重叠,特征金字塔的浅层虽然有高分辨率,但感受野不够大,上下文信息不足,模型很难区分"这到底是两个液滴还是一个液滴的反射光"。第二层是NMS的问题,默认IoU阈值0.7在一般场景够用,但高密度液滴群中两个真实目标的框可能IoU高达0.6,NMS一压就丢掉一个,这就是"漏检"的直接来源。
还有一个容易被忽略的因素:数据增强。YOLO默认开启mosaic增强,把四张图拼成一张,这在大物体场景下有效,但液滴群目标太小,mosaic拼接后目标尺寸被进一步缩小,很多液滴直接缩到4×4像素以下,相当于人为制造了不可检测目标,白白浪费标注。
4.2 针对密集小目标的四组参数调整
我的实践路线是对以下几组参数做组合修改,而不是单点调整:
# hyp.yaml 核心调整片段 mosaic: 0.0 # 关闭mosaic,密集小目标不需要拼图 mixup: 0.0 # 同理关闭mixup fliplr: 0.5 # 水平翻转保留,液滴形态左右对称 scale: 0.3 # 缩放增强从默认0.9降下来,避免目标被缩小到不可见 nms_iou_threshold: 0.4 # NMS阈值从0.7降到0.4 max_det: 300 # 默认300够用,但如果你发现预测框被截断就调大到500每项为什么这么改:mosaic=0.0是密集小目标场景最激进也最有效的一刀,代价是训练收敛速度变慢,因为数据多样性下降,但我实测在液滴场景下收益远大于损失。scale从0.9降到0.3是关键,YOLO的scale增强是随机缩放到0.9~1.1倍之间,但对1536分辨率下本来就只有20像素大小的液滴,0.9倍缩放就把关键纹理细节抹掉了。nms_iou_threshold=0.4是牺牲一点重叠框的召回来换取"每个液滴一个框"的精确性,这个值需要配合验证集mAP一起观察,不是越低越好。
如果你用的是yolov8,修改hyp参数可以在训练命令里直接覆盖:
yolo detect train \ data=/path/to/data.yaml \ model=yolov8m.pt \ imgsz=1536 \ epochs=100 \ batch=8 \ mosaic=0.0 mixup=0.0 \ scale=0.3 \ nms_iou_threshold=0.4yolov8的ultralytics框架支持命令行直接传超参数覆盖,但nms_iou_threshold严格说不是训练超参而是推理后处理参数,训练时传了不会报错但也不起作用,需要在推理脚本里单独设置。这是初学者很容易踩的一个理解误区。
4.3 滑窗切图:对付超密集场景的终极手段
如果上述参数调整后高密度液滴群仍然漏检严重,就该上滑窗切图了。思路很简单:把1536×1536的原图切成若干960×960或640×640的patch,每个patch独立推理,再把结果合并回原图坐标。这样做的好处是每个目标的像素面积在patch中被放大,特征更清晰。
import cv2 import numpy as np def tiling_inference(image, model, tile_size=960, overlap=96): h, w = image.shape[:2] detections = [] step = tile_size - overlap for y in range(0, h - tile_size + 1, step): for x in range(0, w - tile_size + 1, step): tile = image[y:y+tile_size, x:x+tile_size] results = model.predict(tile, imgsz=960, conf=0.25, iou=0.4) for box in results[0].boxes: x1, y1, x2, y2 = box.xyxy[0].cpu().numpy() cls = int(box.cls[0]) conf = float(box.conf[0]) # 坐标映射回原图 detections.append((x + x1, y + y1, x + x2, y + y2, cls, conf)) return detections切图参数的选择逻辑:tile_size=960意味着每张patch大约是原图的62.5%,对单个液滴来说是接近一倍的像素放大;overlap=96是防止目标正好落在patch边界被截断,留出约10%的重叠区域。合并时会有重复检测问题,同一目标可能在两个相邻patch里各出现一次,所以我一般会在合并后做个简单的NMS,用IoU大于0.5的规则去重。代价是推理时间翻了三倍左右,实时性要求高的场景需要权衡。
滑窗切图还有个隐性收益:它天然解决了图像尺寸不统一的问题。虽然这份数据集文件名推断为1536×1536,但工业采集设备偶尔会输出不同分辨率的帧,切图后所有patch统一到960×960,就不需要担心batch内尺寸分歧导致训练崩溃。
5. 常见问题排查:训练崩了、指标虚高与标注错位的处理
5.1 现象:loss在下降但mAP始终在0.1附近震荡
原因:最典型的case是类别不均衡叠加小目标学习困难。droplet高密度类别占据了训练样本的绝大多数,模型把所有注意力都用去拟合这个类别,而1bubble和0droplet在训练中被淹没了。mAP是四类平均值,单液滴类别的AP可能只有0.05,直接把整体mAP拖死。
解决:先跑一次yolo detect val拿每个类别的AP,确认是哪几类拖后腿。然后做两件事,一是对稀疏类别做过采样,简单做法是把只包含0droplet或1bubble的图片复制一份放进训练集;二是用class_weight或者将loss函数中对小类别项的权重提高,yolov8的官方写法是修改cls和box的loss系数,但不支持per-class权重,实操上更有效的是过一个简单的数据增强——对稀疏类别的样本做随机亮度扰动和轻微旋转,增强它的表面多样性。
5.2 现象:验证集mAP很高(超过0.9)但实际部署到产线完全不能用
原因:这是流体数据集最隐蔽的坑——时间泄漏。前面提到文件名里的Slice248、Slice231表示连续帧,如果把同一段视频流的前半段放进训练集、后半段放进验证集,模型其实学到了帧间连续性而不是真正的液滴特征。验证时它"认得"这帧画面,自然mAP虚高;到了产线换了机位和背景,立刻原形毕露。
解决:按视频序列切分训练/验证集,而不是按随机帧切分。拿到数据集后先按文件名的Slice编号或OW3批次分组,确保同一个批次的所有帧要么全部在训练集,要么全部在验证集。这个数据集官方已经做了752张验证集的划分,但保险起见你还是应该抽查一下验证集里是否混入了和训练集同批次的帧,方法是对所有文件名按序列号排序,检查验证集序号是否散落在训练集序号之间。
5.3 现象:推理结果里出现大量"跨类重叠框"
原因:四分类里2dropletbubble和droplet的形态边界本来就模糊,加上NMS阈值被调低到0.4之后,同一个目标很容易同时被两个不同类别的高分框命中。这不算标注错误,而是类别定义本身有重叠空间——一个高密度液滴群的中心区域,某个局部可能同时符合"液泡混合体"的特征。
解决:不要试图通过继续调低NMS阈值解决,那只会增加漏检。正确做法是做一个类别优先级规则:推理结果出来后,如果2dropletbubble的框和droplet的框IoU大于0.5,保留置信度高的一方,同时约束类别映射表,让后处理时强制同类合并。更进一步的方案是训练一个分类头专门区分液泡混合体和液滴群,但这需要额外标注,一般不做。
5.4 现象:batch=8训练时报CUDA OOM
原因:1536×1536输入加上batch=8,在24G显存的卡上刚好卡在临界点偏上的位置。如果用的是yolov8m而不是yolov8s,模型参数量翻倍,显存直接不够。
解决:三步走。第一,把batch降到4,先确认能跑通;第二,开启cache=True把图像预加载到内存,虽然不能减少显存占用,但能缩短每个epoch的时间,让你更快试错;第三,如果batch=4仍然OOM,把imgsz降到1280,对比训练精度损失大不大。还有一个容易忽略的选项是amp=True(混合精度),能省30%左右显存,默认开着但偶尔会被环境配置关掉。
5.5 现象:训练日志不断打印"WARNING: corrupt image"或"unable to load label"
原因:个别图像文件在采集或传输过程中损坏,或者某个txt标注文件编码不是UTF-8而是GBK。Roboflow导出的数据集虽然经过平台清洗,但大规模下载时zip解压中断也会导致小概率文件损坏。
解决:用第3.2节的审计脚本跑一遍,把坏图删掉或重新下载。不要试图"绕过"这个警告——YOLO遇到坏图会跳过该样本,但如果坏图集中在某个类别或某个批次的帧里,等于你无声无息地丢掉了部分验证数据,最后模型性能和日志对不上号。审计脚本跑完后,把所有坏图单独放一个目录,用quarantine目录名,方便追溯。
6. 验证与进阶:从混淆矩阵到mmrotate、DETR的对比实验
数据集自带的验证集有752张,足够用来做模型选型对比。除了mAP@0.5,我更习惯把混淆矩阵和PR曲线一起看。用ultralytics跑完验证后,runs/detect/val/confusion_matrix.png会直接给出四类别之间的错分关系——注意看2dropletbubble这一行的分布,如果它大量被误分为droplet,说明液泡混合体的语义边界在你的模型特征空间里没有被充分区分,而这个问题mAP是看不出来的。
再往前一步,我建议用mmrotate或DETR做一轮横向对比。理由很直接:液滴和气泡在流体中不全是正矩形框能装下的,倾斜的液链、椭圆形的气泡用旋转框描述更准确。mmrotate支持旋转检测头,DOTA数据集上验证过性能,你只需要把这份数据集的YOLO格式转成DOTA格式(x1 y1 x2 y2 x3 y3 x4 y4 class),然后跑一个oriented_rcnn或rotated_fcos的baseline,对比yolov8的方形框方案,能直观看出旋转框对液滴群这类细长目标的收益到底有多大。
最后一招是连续帧推理验证。数据集包含气泡破裂、液滴聚合等动态过程的连续帧,训练结束后挑一段连续帧跑视频推理,重点观察两件事:一是同一目标的预测框在帧间是否稳定抖动,液滴运动速度快,框如果每帧都在跳,说明模型的特征提取不够稳定,需要回到第4章调增强参数;二是类别标签是否在连续帧间来回横跳,液泡混合体在运动过程中形态变化剧烈,如果标签频繁在2dropletbubble和droplet之间切换,后处理时要加一个时序平滑过滤器,用前3帧的类别投票决定当前帧的输出。
从那以后,我每次拿到新的工业流体数据集,都会强制走一遍这套流程:先审计文件完整性和标注坐标、再统计类别分布、然后固定batch和imgsz跑一轮baseline、密集小目标场景直接关闭mosaic、最后用混淆矩阵和连续帧视频做双重验证。这套流程帮我躲过了好几次"验证集指标漂亮、产线寸步难行"的尴尬,希望帮到你。
这份工业液滴气泡多目标检测数据集(YOLO格式,训练集1219张、验证集752张)已经在文末整理好,下载后按第3章的目录结构解压、改好data.yaml就能直接开训。实际跑一轮下来,你对密集小目标检测和两相流场景的理解会比对任何通用数据集调参更深刻。
本文还有配套的精品资源,点击获取