岩石矿物检测实战:COCO双标注与实例分割训练全流程
2026/9/11 20:59:01 网站建设 项目流程

简介:面向地质勘探与矿物资源开发领域,提供一套岩石、矿石表面矿物质检测与分割数据集,可支撑目标检测、语义分割等算法的训练与评估。整个压缩包共2000个文件,以1998张JPG图片为主,配以2个JSON标注文件,包体约215.94MB,标注采用COCO格式,同时包含分类、分割和目标检测信息。每张图片均经过马赛克增强处理,丰富了样本多样性,可帮助提升模型在复杂矿山环境下的鲁棒性与泛化能力。数据集对于矿产快速分类、矿物分布精细分析以及选矿加工中的目标定位都有直接应用价值,支持基于卷积神经网络等深度学习模型的训练与验证,可直接对接主流检测和分割框架。目前已有918人学习下载,适合地质、遥感、计算机视觉等方向的研究人员和工程师用于模型训练、算法对比与实验验证。

1. 岩石矿物检测为什么绕不开 COCO 双标注

拿到一份岩石、矿石表面矿物质检测与分割数据集,第一反应不是翻图片,而是先打开标注 json。因为在这个场景里,检测框和分割掩码经常相互“打架”——矿物颗粒边界极不规则,一个 bbox 往往把周围大片背景圈进来,纯目标检测模型训练出来就是高召回、低精度。这份超过 2600 张图像的矿物表面数据集,同时给出语义分割与目标检测标注,本质上就是在逼你在训练策略上做取舍。对于做地质勘探图像识别、选矿粒度分析或者矿物自动分类的工程师来说,这份数据的价值不只是“能跑通 YOLO”,而是能帮助你搞清楚如何在同一种 COCO 标注格式下,把实例分割和边界框输出统一进一个训练管线。本文从标注结构、数据增强、模型配置到验证脚本,完整拆一遍这套流程,直接可复现。

2. COCO 标注格式里 detection 与 segmentation 的数据组织

2.1 一个 json 文件如何同时承载三类标注信息

COCO 标注格式的核心是三个数组:imagesannotationscategories。这套岩石矿物数据集里的分类、检测、分割信息,全部压缩在这三个数组的对应关系里,不需要额外文件。

import json with open('annotations/instances_train.json', 'r', encoding='utf-8') as f: coco = json.load(f) print(coco.keys()) # dict_keys(['info', 'licenses', 'images', 'annotations', 'categories']) print('图像数:', len(coco['images'])) print('标注实例数:', len(coco['annotations'])) print('类别数:', len(coco['categories']))

逻辑上先看顶层键。images数组里每条记录是单张图的idfile_namewidthheightannotations数组里的每一条是一个独立目标实例,对应到某张图。categories数组则是矿物类别表。也就是说,“分类”信息不是单独一个标签文件,而是通过annotation.category_id指向categories表里的类别名;“分割”通过annotation.segmentation字段编码;“检测”通过annotation.bbox字段表达。三者共用同一份实例标注。

这样设计的好处是训练 Mask R-CNN 这类双头模型时,检测分支和分割分支共享同一个 RoI,不需要额外同步两个标注文件。但也带来一个隐患:语义分割的标签和检测框标签天然不一致时,模型在边界框回归和掩码预测之间会产生梯度冲突。矿物表面矿物质扫描场景里,颗粒边缘夹杂大量纹理噪声,这个问题尤其严重。

2.2 polygon、RLE 与 bbox 的几何一致性

COCO 的segmentation字段有两种编码方式:多边形坐标列表(polygon)和 RLE 游程编码。这份数据集如果是从 Roboflow 导出的,默认往往是 polygon 格式,形如[x1, y1, x2, y2, ..., xn, yn]扁平化坐标。而语义分割训练时,多数框架要求把 polygon 转成 RLE 或直接生成 0/1 mask。

import numpy as np from pycocotools import mask as maskUtils # 假设 annotation 是加载后的某条实例标注 seg = annotation['segmentation'] if isinstance(seg, list): rle = maskUtils.frPyObjects(seg, h, w) # polygon -> RLE rle = maskUtils.merge(rle) # 合并多个多边形 else: rle = seg # 已经是 RLE mask_2d = maskUtils.decode(rle) # 解码为 HxW 的 0/1 mask print('mask shape:', mask_2d.shape, '前景像素数:', int(mask_2d.sum()))

代码里做了两层判断:segmentation是 list 就按 polygon 处理,是 dict 就是 RLE。用frPyObjects把扁平化坐标还原成多边形对象,再转 RLE,最后解码成可视化的 mask。这个转换在训练脚本中会反复出现,值得封装成工具函数。

字段类型说明本数据集使用场景
segmentationlist / dictpolygon 或 RLE语义分割监督信号
bbox[x, y, w, h]像素坐标目标检测回归目标
areafloatmask 面积小目标筛选用
iscrowd0 / 1是否密集人群矿物粘连时置 1 需注意
category_idint类别索引分类监督

注意bboxsegmentation并非严格一致:COCO 官方要求的 bbox 是目标外接矩形,但很多标注工具导出时用的是 mask 的最小外接矩,两者在斜向矿物颗粒上差异明显。我一般会在训练前写脚本统计 bbox 边缘与 mask 边缘的最大偏离距离,超过 20 像素就要考虑重新校正。

2.3 为什么这套标注适合做“分割为主、检测为辅”的基线

矿物表面检测的痛点在于目标边界模糊、尺寸变化大、纹理重复度高。纯检测模型只能告诉你“这里有矿物”,不能告诉你“矿物占据多大面积”。而岩石表面的矿物分布对工业指标至关重要,比如选矿回收率估算依赖面积占比。因此这份数据集的 COCO 双标注可以拆出两条训练路线:如果生产环境只做定位,用 bbox;如果要做品位分析,必须用掩码。我倾向于在这份数据上以 Mask R-CNN 或 YOLOv8-seg 为主干,把 bbox 作为辅助监督,而不是反过来。

3. 从 COCO 标注到训练数据的预处理流程

3.1 目录组织与数据划分策略

COCO 格式的目录通常按官方比赛结构组织。对于这份岩石矿物数据集,我建议重新划分目录,而不是直接用原打包结构训练,便于后续增量标注和版本管理。

dataset/ ├── images/ │ ├── train/ # 约 1850 张 │ └── val/ # 约 520 张 └── annotations/ ├── instances_train.json └── instances_val.json

划分策略上,矿物数据集有一个特殊性:同一块岩石的连续采样照片极其相似,如果随机划分,训练集和验证集会泄漏大量相同纹理,导致 mAP 虚高。我一般用基于图像采集时间戳的划分方法,例如这个数据集文件名里的20200608_175240这类字段就是拍摄时间,按时间切分确保同一采样批次只落在训练集或验证集一侧,而不是两边都有。

小目标过滤也是必须要做的事。岩石表面的细小矿物颗粒可能只有几十个像素,标注面积占全图比例低于 0.5%,这类样本在 COCO 评测中被归入 small 类别。如果训练数据里这类占比过高,模型会对整体指标贡献很小,反而分散学习能力。

3.2 用 pycocotools 做数据质量审计

数据质量审计的优先级高于搭模型。这一步的收益在后续实验里会成倍放大。下面这段代码输出每张图的类别分布和 mask 面积分布。

from collections import Counter import numpy as np cat_id_to_name = {c['id']: c['name'] for c in coco['categories']} img_id_to_size = {img['id']: (img['width'], img['height']) for img in coco['images']} cat_counter = Counter() area_list = [] small_cnt = 0 for ann in coco['annotations']: cat_counter[cat_id_to_name[ann['category_id']]] += 1 w, h = img_id_to_size[ann['image_id']] area_ratio = ann['area'] / (w * h) area_list.append(area_ratio) if area_ratio < 0.005: small_cnt += 1 print('类别分布:', dict(cat_counter)) print('面积占比 中位数: %.4f 最小: %.6f' % (np.median(area_list), min(area_list))) print('小目标(占比<0.5%): %d 条' % small_cnt)

这段审计代码有两点意义。第一,确认类别不均衡的严重程度,热词里常见的“小目标检测”问题在此场景就体现为细微矿物颗粒漏检。第二,面积占比信息决定后续数据增强的参数选择——如果中位数占比极低,说明大目标稀少,多尺度训练和 Copy-Paste 类的增强会比固定尺度训练更有效。如果small_cnt占比超过 40%,anchor 尺度的设置就要往下调,Mask R-CNN 默认的[32, 64, 128, 256, 512]在岩石细颗粒上明显偏大。

3.3 Mosaic 增强在多目标标注下的正确打开方式

这份数据集明确提到做了马赛克增强(Mosaic)。Mosaic 最早从 YOLOv4 流行开来,把四张图拼成一张,本质上是增加单张图的背景多样性和目标尺度多样性。但在 COCO 双标注训练里,Mosaic 有个容易被忽略的坑:拼接时四张图的边界框和掩码都要跟着做平移裁剪,如果一张图的掩码区域在拼接边界处被截断,areabbox会变得不一致。

import albumentations as A from albumentations.pytorch import ToTensorV2 transform = A.Compose([ A.RandomResizedCrop(height=640, width=640, scale=(0.5, 1.0)), A.Mosaic(p=0.5), A.HorizontalFlip(p=0.5), A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), ])

albumentations 里的Mosaic支持同步变换 mask 和 bbox,不需要自己写拼接逻辑。但注意scale参数和 mosaic 的min_area设定:拼接后大量目标会被缩放到极小尺寸,训练 Mask R-CNN 时MIN_SIZE太低会导致掩码分支的 RoI 特征分辨率不足。我更推荐的做法是 Mosaic 只在前 30 个 epoch 开启,后面关闭,让模型在接近真实数据分布上做微调。这类数据增强在语义分割数据集制作流程里是标配,但用在矿物数据上,参数要调得更保守。

4. 基于 COCO 双标注的矿物表面检测与分割模型配置

4.1 先跑通 YOLOv8-seg:最小可行基线

在部署层面,YOLOv8-seg 是当前把检测和分割同时落地的最短路径。它对 COCO 格式的原生支持直接省去写 Dataset 类的工作。用一个 yaml 文件定义类别和数据路径即可。

# mineral.yaml path: /data/mineral/ train: images/train val: images/val nc: 4 names: ['hematite', 'malachite', 'quartz', 'pyrite']

这个配置与热词里提到的 yolo 目标检测流程完全一致:nc是类别数,names按训练时类别顺序排列。注意这里的类别顺序必须与 COCO 标注 json 里的categories顺序对齐,否则类别张冠李戴。如果不确定,可以用脚本从 json 里动态生成这个 yaml。

yolo detect train data=mineral.yaml model=yolov8s-seg.pt epochs=50 imgsz=640 batch=8

这个命令默认会读取 COCO 格式标注,yolov8s-seg 是轻量级分割模型,适合第一轮跑通。训练完成后,验证命令如下:

yolo segment val model=runs/segment/train/weights/best.pt data=mineral.yaml

输出里有两个指标需要区分对待:mAP50mAP50-95。如果mAP50高但mAP50-95低,说明主要问题不在分类而在定位精度,大概率是标注框边界偏松,需要回到数据修正而不是加大模型。第一轮基线是个不错的起点,但要满足选矿粒度分析这种要求,往往需要换 Mask R-CNN 做更精细的掩码预测。

4.2 Mask R-CNN 在 mmdetection 下的实践配置

如果追求比 YOLOv8-seg 更精细的掩码边界,可以用 mmdetection 里的 Mask R-CNN 配合 ResNet-50 主干。下面给一份能直接改路径就用的核心配置。

_base_ = [ '../_base_/models/mask_rcnn_r50_fpn.py', '../_base_/datasets/coco_instance.py', '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' ] model = dict( roi_head=dict( bbox_head=dict(num_classes=4), mask_head=dict(num_classes=4) ) ) data = dict( train=dict( ann_file='/data/mineral/annotations/instances_train.json', img_prefix='/data/mineral/images/train/' ), val=dict( ann_file='/data/mineral/annotations/instances_val.json', img_prefix='/data/mineral/images/val/' ) ) optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) lr_config = dict(policy='step', step=[16, 22]) total_epochs = 24

这份配置做了两处关键修改:num_classes从 COCO 默认的 80 改成实际矿物类别数;训练计划从默认的 12 epoch 延长到 24。原因在于矿物数据集类别少,模型容量容易过拟合,用更长的训练周期配合 step 学习率衰减可以稳定收敛。学习率方面,虽然 batch size 通常只有 8,但类别少、任务简单,0.01 的初始学习率不会震荡。

训练命令:

python tools/train.py configs/mineral/mask_rcnn_r50_fpn_1x.py --work-dir work_dirs/mineral

4.3 语义分割与实例分割在矿物场景的选型差异

这份数据集标注同时可用于语义分割和实例分割。热词里的 deeplabv3 语义分割是一个常见对比对象,但在实例相互粘连严重的矿物表面,纯语义分割输出的是像素级类别图,无法区分同一矿物类别下不同的矿石颗粒。而选矿场景往往需要统计颗粒数目、大小分布,实例分割信息不可或缺。如果你的用途仅限面积占比分析,DeepLabV3+ 这类语义分割模型更轻、更快;如果需要粒度分析和计数,Mask R-CNN 或 YOLOv8-seg 是正确选择。这个选型差异在项目开始时就要确定,因为它决定标注数据的最终消费方式。

5. 从标注质量反推训练效果:验证脚本与三类典型坑

5.1 快速验证掩码质量的五步检查法

训练之前,先做一轮掩码可视化验证。直接叠加 mask 到原图上,检查标注是否贴合矿物边缘。这一步比看 mAP 数字更直观。下面是一个简单的可视化检查代码。

import cv2 from pycocotools import mask as maskUtils def draw_mask(img_path, ann): img = cv2.imread(img_path) h, w = img.shape[:2] rle = maskUtils.frPyObjects(ann['segmentation'], h, w) m = maskUtils.decode(maskUtils.merge(rle)) # 彩色掩码叠加 color_img = img.copy() color_img[m > 0] = (0, 0, 255) + color_img[m > 0] * 0.3 x, y, bw, bh = ann['bbox'] cv2.rectangle(color_img, (int(x), int(y)), (int(x + bw), int(y + bh)), (0, 255, 0), 2) return color_img

每张图随机抽 5 个标注实例,人工检查三类问题:掩码是否包含背景纹理、bbox 是否紧贴外轮廓、同一目标的掩码是否有内部空洞。如果空洞多,说明标注工具在复杂纹理处产生断线,训练时模型会学到错误的“环状”掩码输出。

5.2 类别不均衡与背景占比过高

岩石数据集最常见的坑是类别不均衡。从前面审计脚本可以看出,不同矿物类别在数据集里的实例数量可能差 10 倍以上。解决方案有两个层面。数据层面,对少样本类别做过采样,用repeat_factor或者自定义 sampler;损失层面,给交叉熵损失加类别权重。Mask R-CNN 里通过loss_cls_weightloss_mask_weight调整。

model = dict( roi_head=dict( bbox_head=dict( num_classes=4, loss_cls=dict(type='CrossEntropyLoss', use_sigmoid=False, class_weight=[1.0, 3.0, 2.0, 5.0]) ) ) )

这种加权方式让模型对少样本类别给予更多梯度关注。但注意权重不宜过大,超过 5 会引发少样本类别误检率飙升。

背景占比过高是另一个问题。岩石图像中矿物颗粒往往只占画面的一小部分,R-CNN 系列的采样机制对背景候选框已经做了正负样本比例控制,但如果分割分支的 mask 损失把背景像素全算进去,dice loss一类的区域损失会比逐像素交叉熵更稳定。我一般会在掩码分支额外加一个小的 dice loss 辅助项,对抗背景主导。

5.3 边界不确定性与两阶段预测策略

矿物颗粒的边界在图像上经常不清晰,标注者之间的一致性也不高。针对这种边界模糊问题,一个实用技巧是把预测任务拆成两阶段:先用语义分割得到粗略的矿物分布热图,再用检测框加掩码在全图上做精修。第一阶段类似热词里提到的 mtd 动目标检测思想——先框出“变化的区域”,再做精细识别。第二阶段用 Mask R-CNN 的 RoI Align 输出精确边界。这样可以规避单阶段模型在模糊边界处的像素级歧义。

在推理阶段,把置信度阈值调低的收益比调高更明显:矿物检测任务宁可多出几个假阳性框,也不能漏掉稀有矿物颗粒。我一般会把score_thr从默认的 0.5 降到 0.3,再用形态学开闭运算对 mask 后处理一次,去除孤立小噪点,填充内部小洞,输出的面积数据才适合直接用于粒度统计。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询