尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

机器学习与语义分割在岩石薄片自动鉴定中的工程实践

发布时间:2026/9/25 1:23:41

资讯中心
01
ARTICLE

机器学习与语义分割在岩石薄片自动鉴定中的工程实践

机器学习与语义分割在岩石薄片自动鉴定中的工程实践
简介一份面向地质学与计算机交叉方向学习者的机器学习实战项目围绕岩石薄片图像自动鉴定任务整合了从数据集标注、特征提取、模型训练到测试评估的完整流程。资源既包含CNN等深度学习模型的构建与训练代码也提供随机森林、SVM等传统算法的特征统计模块可用于对比不同方法的识别效果适合毕业设计、课程设计或期末大作业的快速入门与二次开发。压缩包共含28个文件以15个Python脚本为主体涵盖模型网络定义、训练器、数据集处理以及颜色统计、GLCM纹理、LBP特征提取等模块另有4个Markdown文档、2个文本要求和1个Excel结果表便于核对项目结构、运行依赖与输出指标。整包仅758KB轻量紧凑无需大型数据集即可启动实验。目前已有42人学习下载适合希望快速复现岩石薄片分类实验并在此基础上扩展图像增强、交叉验证或评估指标分析的地学专业学生。通过实践读者能掌握图像预处理、特征工程与模型评估的具体写法并借助自带数据与示意图直观完成一次自动鉴定演示解决传统鉴定依赖人工经验、耗时且主观的痛点为进一步研究打下基础。1. 岩石薄片自动鉴定为什么值得做人工镜检的瓶颈与机器学习的切入点你拿到的这个压缩包名字里有两个关键词机器学习和岩石薄片。前者是近年来被反复验证的图像识别技术路线后者是地质行业里最依赖老师傅眼力的一项日常工作。两者撞在一起要解决的是个非常现实的痛点岩矿鉴定工程师在偏光显微镜前一坐就是大半天一片薄片从单偏光到正交偏光反复切换再数几百个矿物颗粒做统计耗时、费眼、而且培养周期很长。用机器学习把“看图说话”这一步自动化并不是要取代鉴定人员而是把重复劳动先接走让系统产出可复核的矿物分割结果和定量含量再由人来完成地质解释和最终定名。适合做这件事的人主要是手里攒着大量历史薄片和镜下照片的实验室、要做钻孔岩屑快速鉴定的地质队、以及想往地质行业落地的算法工程师——这是一条认知门槛高但竞争相对少的落地路线。2. 选对任务与技术路线图像分类、语义分割还是目标检测2.1 三种范式的边界与选择逻辑接到“自动鉴定”这个需求第一件事不是选模型而是先想清楚把任务定义成什么。图像分类输出一个整体标签只回答“这块石头是花岗岩还是大理岩”语义分割对每个像素做类别预测输出一张与输入同尺寸的掩码目标检测用矩形框定位图像里的目标颗粒。三者的能力边界完全不同。岩石定名不是看一眼就能定的需要矿物成分的定量数据。图像分类最大的问题就是信息粒度太粗告诉你“这是二长花岗岩”但你无法复核这个结论的依据是什么中间过程完全是一个黑匣子。目标检测则对颗粒状矿物比如砂岩碎屑能做粒度统计但对大多数岩浆岩和变质岩来说矿物相互镶嵌交织成不规则的边界矩形框无法贴合这种形态。语义分割是唯一能同时输出矿物种类和空间分布、并能支撑后续含量计算的方案。实际落地时我一般建议直接从语义分割切入不要先拿分类模型做可行性验证。原因是分类模型验证得出的“能做/不能做”结论不具备参考价值一旦薄片里出现两种相似岩性混搭分类模型就失效了而分割模型至少还能把每个区域的矿物类别标记出来。从工程看分割模型的推理结果能直接叠回原图展示给鉴定工程师复核这种可解释性是从业人员接受这套系统的必要条件。2.2 数据是最大瓶颈从零构建岩石薄片数据集的路径岩矿方向没有公开的、带像素级矿物标注的薄片数据集这是整个项目里最大的现实约束。做这个方向数据来源通常有三条路。第一条是委托专业制片室磨新片一片30到50元成本一批次可以做几十片第二条是翻实验室的历史薄片库很多地勘单位攒了几十年薄片这是性价比最高的数据来源只需要用显微镜自动扫描平台逐片翻拍第三条是直接采集岩屑颗粒制作树脂薄片适合石油钻井场景。三条路可以并行不必等到数据凑齐再开始标注。标注工具方面常见做法是用 Labelme 画多边形或者用 EISeg 这类交互式分割工具做预标注再人工修正。EISeg 能显著提速但前提是你先有一个粗模型所以第一版数据还是得靠纯人工画。标注人员不能是只会点鼠标的标注员必须是有地质背景的人否则会把蚀变矿物混进原生矿物类别。一个视域的薄片图像标注耗时一到两小时并不夸张计划工作量和工期时务必把这个数字算进去。初始方案的类别不要贪多控制在 15 类以内。常见造岩矿物里优先覆盖石英、钾长石、斜长石、黑云母、白云母、角闪石、辉石、橄榄石、方解石再加上胶结物和孔隙。启动阶段可以先定 8 到 10 个高优先级类别体积比例比较小的副矿物如锆石、磷灰石等放到第二迭代再加否则类别不均衡会让模型训练难度陡增。这里必须强调划分数据的原则按薄片划分 train/val/test而不是按切出来的图像块划分。同一块薄片相邻视域图像高度相似如果训练集和验证集来自同一片薄片验证集指标会虚高很多相当于把数据泄漏当成了模型能力。这个错误我在第一个版本就犯过换回按薄片划分后 mIoU 直接掉了 8 个点但心里反而踏实了。2.3 先分割后定名我给这条路线的理由整体技术路线我推荐做成两段式第一段用语义分割模型输出像素级矿物类别掩码第二段根据掩码计算各矿物面积百分比再套用岩石定名规则输出岩石名称。这样拆分是出于三个层面的考量。从地质业务层面看矿物含量是岩石定名的核心定量依据传统鉴定流程里的“网格计数法”就是这么做的——在目镜里装一个网格数几百个交点点落在哪种矿物上按点数占比估算含量。机器学习分割模型本质上做的是同一件事只是从抽样统计变成了全像素统计业务逻辑完全兼容老师们理解起来没有障碍。从工程容错层面看两段式比端到端定名多了一个可检查的中间产物。端到端模型输出一个岩石名称错了只能认栽分割模型的输出掩码可以叠在原图上让鉴定工程师指出哪一类矿物被认错了然后针对性地补数据重训。从数据积累层面看分割标注得到的掩码是长期资产项目做到后期分类类别扩展、硬度识别、孔隙率计算等功能都能复用。而一个端到端的定名模型除了最终标签以外什么都沉淀不下来。3. 制作训练数据偏振光图像采集、标注与增强3.1 单偏光与正交偏光配对双通道输入的必要性岩石薄片在偏光显微镜下有两种标准观测状态。单偏光PPL只用一个偏光片可以观察矿物的本色、多色性、解理纹和突起正交偏光XPL让上下两个偏光片呈九十度正交矿物表现出特征干涉色这是鉴定长石、石英、橄榄石等大多数透明矿物的关键依据。有经验的鉴定师会在两种状态下反复切换这是因为单靠一种光下特征不足以把易混淆矿物区分开。机器学习模型也应该同时看到两种光下的图像而不是只喂其中一种。项目里我用的是双通道方案在同一视域下分别采集 PPL 和 XPL 图像严格对齐后作两个通道输入网络。实际采集时需要注意电动载物台采图要固定对焦参数和光源强度这样不同批次图像的亮度直方分布才一致。以下代码处理配对图像的加载import cv2 import numpy as np def load_ppl_xpl_pair(base_path, sample_id, view_id): ppl_path f{base_path}/{sample_id}_v{view_id}_PPL.tif xpl_path f{base_path}/{sample_id}_v{view_id}_XPL.tif ppl cv2.imread(ppl_path, cv2.IMREAD_UNCHANGED) xpl cv2.imread(xpl_path, cv2.IMREAD_UNCHANGED) assert ppl.shape[:2] xpl.shape[:2], fPPL/XPL shape mismatch: {sample_id}_v{view_id} # 转为 RGB 三通道方便与神经网络输入对齐 if ppl.ndim 2: ppl cv2.cvtColor(ppl, cv2.COLOR_GRAY2RGB) if xpl.ndim 2: xpl cv2.cvtColor(xpl, cv2.COLOR_GRAY2RGB) # 将双通道并成输入字典后续增强和训练统一处理 return {image: ppl, xpl: xpl, mask: None}这段代码的逻辑核心是保证 PPL 和 XPL 图像尺寸一致、通道格式统一。注意读图时要用 IMREAD_UNCHANGED 保留原位数偏光显微镜相机输出通常带 16bit 灰阶如果直接另存为 jpg 会把灰阶压到 8bit导致一些干涉色差异被抹掉。文件名里的 sample_id 和 view_id 是配对的关键采集时一定要按这个规范命名别在采集现场省略掉 view 编号后面要补对应关系会非常痛苦。3.2 像素级标注工具选择与标注规范标注阶段我用 Labelme 作为主力工具理由很务实它可以导出 JSON 格式的多边形标注与 geojson 结构接近转换为语义分割掩码只要写一个脚本不依赖商业软件授权。以下代码是 Labelme 标注结果转掩码的常规实现import json import numpy as np import cv2 def labelme_json_to_mask(json_path, h, w, class_name_to_id): with open(json_path, moder, encodingutf-8) as f: data json.load(f) mask np.zeros((h, w), dtypenp.uint8) # 每个 shape 是一条多边形标注逐条填充到空白掩码上 for shape in data[shapes]: class_name shape[label] label_id class_name_to_id.get(class_name) if label_id is None: continue polygon np.array(shape[points]).astype(np.int32) cv2.fillPoly(mask, [polygon], colorlabel_id) return mask这段脚本的核心是遍历标注文件里的每条多边形按类别映射表填充掩码。参数 class_name_to_id 必须是全局统一的字典类别顺序一旦确定就不要中途变更否则掩码类别索引就全乱套了。我踩过的坑是早期把“斜长石”和“钾长石”合并为一个长石类后来想拆开重新标注几乎等于全部返工。标注规范应当在动手前写清楚颗粒中心清楚、边缘模糊的按边缘外扩两个像素圈定被其他矿物包裹的细小包裹体不单独标注蚀变强烈的部分单独设类不并入原生矿物类别。对多视域大图一个薄片通常有几十个视域逐一标注工作量巨大。实践上可以先用随机采样把每片薄片的视域图像裁成 1024 像素左右的小块再抽样 20% 做标注这样能控制初期数据量又不会因为单视域特征太强导致模型记住特定图像。3.3 针对薄片特性的数据增强策略数据增强不能照搬 ImageNet 那套做法。薄片图像有几个独特性质矿物在岩石中通常没有固定朝向旋转增强非常有效PPL 和 XPL 下的颜色和干涉色是矿物鉴定的关键依据所以色相变化和强烈的饱和度抖动是禁忌边界模糊恰恰是需要模型学习的信息不能用模糊增强去抹掉。下面是一组我实测下来比较可靠的增强配置import albumentations as A train_transform A.Compose([ A.RandomRotate90(p0.5), A.HorizontalFlip(p0.3), A.VerticalFlip(p0.3), A.RandomBrightnessContrast(brightness_limit0.05, contrast_limit0.05, p0.3), A.RandomCrop(height512, width512, p0.8), A.Resize(height512, width512, always_applyTrue), ]) valid_transform A.Compose([ A.Resize(height512, width512, always_applyTrue), ])逻辑说明前三个几何增强利用了矿物没有方向偏好这一强先验代价几乎为零。亮度对比度抖动幅度只给 0.05是因为同一实验室固定光强采集的图像不需要大幅度亮度迁移但不同批次磨片厚度差异会带来轻微亮度波动这个幅度刚好能吸收一部分批次差异。RandomCrop 放在几何增强之后配合 Resize 统一尺寸训练时每张图看到的是不同的局部区域相当于又放大了一倍数据量。注意不要把 Mask 和图像分开增强。albumentations 允许同时传入 mask 与 image同一套几何变换才能保证掩码和图像对齐。掩码用的是最近邻插值图像用双线性这两者在增强库内部会自动处理不需要你额外操心。4. 训练岩石薄片分割模型关键参数与损失函数设置4.1 模型选型与输入尺寸U-Net 和 DeepLabV3 怎么选模型骨架的选择要考虑数据集规模、薄片图像特点、可解释性三个因素。U-Net 的编码器-解码器结构擅长保留细粒度空间信息对中小数据集非常友好DeepLabV3 靠空洞卷积扩大感受野适合语义连贯性要求高的场景比如街景分割但代价是参数量大、小目标细节保持不如短连接结构。岩石薄片里矿物的空间尺度跨度极大石英和长石颗粒动辄占据图像大面积而锆石可能只有十几个像素。如果第一阶段用 DeepLabV3 这类偏重语义的模型大量细小矿物会被吞成大类别区域后期含量统计就失真了。我通常让团队用 U-Net ResNet34 编码器作为第一个版本输入分辨率设 512x512。理由很直接更大的输入尺寸对显存要求高训练速度慢很多而在矿物分类这个任务上512 已经能看清大多数矿物的干涉色特征先用这个基线把数据管线跑通再说。如果后续发现细小矿物边界丢失严重可以换 U-Net 或 DeepLabV3 与 U-Net 的集合体也可以保持模型不变、只提高输入分辨率到 768 并缩小 patch 重叠。模型选型不是一步到位的事我的习惯是先选定一个能跑通的配置用数据瓶颈逼出真实短板再针对短板换模型。4.2 损失函数设计类别不均衡与矿物边界模糊薄片数据集的类别分布极不均衡一块典型的花岗岩薄片中石英和长石可能占七成以上黑云母占一成磷灰石许多视域根本看不见。直接用交叉熵损失模型会倾向于把所有像素预测成头部类别矿物边界也容易被我之前提到的池化与上采样操作磨平。我用的组合损失是 Dice Loss 与 Focal Loss 的加权和。Dice Loss 天然不依赖类别像素数量能直接推动边界处小类别被正确分割Focal Loss 用调制因子把难分类像素的梯度放大薄片里最难的正是矿物之间过渡区的模糊像素。组合方式见下面的代码import torch import torch.nn as nn import torch.nn.functional as F class DiceFocalLoss(nn.Module): def __init__(self, alpha0.5, gamma2.0, smooth1e-6): super().__init__() self.alpha alpha self.gamma gamma self.smooth smooth def forward(self, logits, targets): num_classes logits.shape[1] logits logits.permute(0, 2, 3, 1).contiguous() targets_onehot F.one_hot(targets, num_classesnum_classes) preds F.softmax(logits, dim-1) # Dice Loss按 batch 和类别独立计算再取平均 inter (preds * targets_onehot).sum(dim(0, 1, 2)) union preds.sum(dim(0, 1, 2)) targets_onehot.sum(dim(0, 1, 2)) dice (2.0 * inter self.smooth) / (union self.smooth) dice_loss 1.0 - dice.mean() # Focal Loss针对难分类像素加大梯度 pt (preds * targets_onehot).sum(dim-1) focal_weight (1.0 - pt) ** self.gamma ce F.cross_entropy(logits.permute(0, 3, 1, 2), targets, reductionnone) focal_loss (focal_weight * ce).mean() return self.alpha * dice_loss (1.0 - self.alpha) * focal_loss参数说明alpha 是 Dice 与 Focal 的平衡权重一般 0.3 到 0.5 之间。gamma 是 Focal Loss 的调制系数取 2.0 是默认的经验值对薄片数据已经够用。smooth 是为了防止某类在 batch 内完全不出现时分母为 0。dice 损失在时间维度上也应该按类别独立计算而非全局汇总否则会倾向于优化样本量大的类别类别不均衡问题又被带回模型里。一个被许多踩坑帖验证过的观察是Dice 系数在训练初始阶段会有剧烈震荡不必急于调低学习率这是它正常的行为一般到第 20 轮左右才会稳定。4.3 训练策略与评估指标别只看 mIoU训练参数方面我常用 RAdam 或 AdamW 优化器初始学习率 1e-4weight decay 设 1e-4 防止在类别少量数据集上过拟合。batch size 在单张 12G 显存显卡上输入 512x512 时最多开到 10 左右再大容易显存溢出。训练轮数建议以验证集表现动态决定下面给一个标准的主循环片段for epoch in range(max_epochs): model.train() epoch_loss 0.0 for images, masks in train_loader: images images.cuda() masks masks.cuda() optimizer.zero_grad() logits model(images) loss criterion(logits, masks) loss.backward() optimizer.step() epoch_loss loss.item() model.eval() val_miou, val_f1 evaluate(model, valid_loader, num_classes) if val_miou best_miou: torch.save(model.state_dict(), fbest_model_epoch{epoch}_miou{val_miou:.4f}.pth) best_miou val_miou print(fEpoch {epoch}: loss{epoch_loss / len(train_loader):.4f}, fmIoU{val_miou:.4f}, F1{val_f1:.4f})训练策略说明验证集在每个 epoch 结束后评估一次保存 mIoU 最高的权重作为候选版本。早停条件是验证 mIoU 连续 15 个 epoch 不上升就终止训练比固定 100 轮更稳定也更省机器。评估指标要看三类。第一类是逐类别的 mIoU必须把每个类别的 IoU 单独打出来不要只报均值第二类是 F1 分数因为它对小目标更敏感第三类也是我强烈建议加的是矿物含量误差——把预测掩码和真实掩码各自统计面积百分比算绝对偏差。这个指标直接对应业务目标按我的经验含量平均偏差从 6% 压到 3% 以内模型上线后鉴定工程师的接受度会有本质差别。5. 岩石薄片鉴定模型落地避坑5条值得记录的踩坑与排查5.1 现象胶结物被识别成矿物第一个版本跑出来预测掩码里大片“石英”区域其实是硅质胶结物。原因在于薄片中胶结物与一些矿物在可见光下光学性质高度相似标注时又没有把胶结物单独列为类别导致模型把它们并进了矿物类别。解决方法是标注规范里增加“胶结物基质”类别并保证每张训练图都完整标注胶结物区域推理时它的含量不计入矿物百分比这样结果才和人工鉴定的口径一致。5.2 现象同一矿物在 PPL 与 XPL 下分割结果不一致现象是模型在 XPL 通道输出中把一块黑云母正确分出来了但在 PPL 通道里同一位置被标记成了普通角闪石推理时两通道独立预测边界打架。根因是训练时没有把双通道严格配对输入导致模型只会偷懒地学某个通道的强特征。解决方法是按前文代码强制 PPL 与 XPL 配对在网络输入层维度上拼接两个通道推理时必须同样传入配对图像否则绝对不能单独推理。5.3 现象训练精度高但新磨薄片效果突然变差模型在自己扫描仪采到的数据上 mIoU 能到 0.87换成另一台显微镜采集的新薄片就掉到 0.6。原因是不同薄片批次的磨片厚度、载物台光源强度、以及相机白平衡设置不一致产生了明显的域偏移。解决思路分三层彻底做不到跨仪器通用时优先做光源与白平衡校准让所有采集端输出相同色域训练数据里刻意加入多个批次不同光强的样本如果条件允许在模型里加一个简单的亮度直方图匹配预处理把推理图像拉伸到与训练集相同的直方分布。5.4 现象细小矿物颗粒边界严重丢失锆石、磷灰石这类体积占比小于 1% 的矿物在预测结果里几乎消失留下的只有大颗粒矿物的边界残影。原因是卷积与池化操作天然对高频细节有平滑效应抑制了不连续边界梯度。解决方法是改用带 edge-aware 的损失函数在边界像素上加大权重但更有效的是修改后处理用形态学开运算和连通域分析把预测结果里像素数少于阈值的孤立区域剔除或合并这一步可以把噪声去掉同时保留真正的小矿物区域。5.5 现象标注文件格式与训练框架不兼容标注员交付的是 labelme JSON训练脚本读的是 PNG 掩码两者在类别索引上对不上——比如 labelme 里“钾长石”排在第三位但 mask 生成脚本的 class_name_to_id 字典顺序不同导致训练出的模型把钾长石分成了斜长石。表面看是指标很差实际是数据管线错误。解决方法是统一一个 mask 生成脚本并在每次生成后做一致性抽检随机抽 5 张图像把自然索引与掩码颜色同时打印成图人工确认类别对应无误再进入训练流程。教训是这类错位问题隐蔽、浪费算力一定要尽早设计自动校验逻辑。6. 从分割掩码到矿物含量与岩石定名最后一公里的实现6.1 矿物含量计算与视域统计方法模型输出掩码后第一步就是计算各矿物的面积百分比。这个计算逻辑异常简单但要注意统计口径import numpy as np def mineral_content(pred_mask, class_names): total pred_mask.size ignore_ids set([0]) # 0 作为背景/胶结物不计入矿物总量 results {} for idx, name in enumerate(class_names): if idx in ignore_ids: continue count int((pred_mask idx).sum()) results[name] round(count / total * 100, 2) return results这段代码的逻辑是统计每个类别像素占整张图的百分比忽略背景和胶结物。注意这里应该除以整张图的像素总数而不是除以已识别矿物的像素总数否则含量会被夸大。实际统计时不能只取一个视域矿物分布不均匀是常态我一般在每个薄片上选 10 到 20 个视域分别推理取平均接近传统点计数的统计效果。6.2 定名逻辑与含量阈值表拿到各矿物含量后岩石定名就是一套查表逻辑。下表是岩浆岩简化定名规则只考虑主要矿物的体积占比石英含量碱性长石 vs 斜长石比例岩石名称 20%碱长石占长石总量 60%碱长花岗岩 20%碱长石占长石总量 30% - 60%二长花岗岩 20%碱长石占长石总量 30%花岗闪长岩5% - 20%碱长石 斜长石石英二长岩 5%碱长石为主碱长正长岩 5%斜长石为主闪长岩注意这套表只适用于中粗粒岩浆岩不含喷出岩和常见变质岩。如果薄片来自沉积岩或碳酸盐岩换对应方案例如碳酸盐岩按方解石、白云石含量占比与颗粒结构做 Dunham 分类。定名逻辑代码里如果出现一个薄片的含量落在表格区间之外应当标记为“待人工复核”而不是强行输出一个岩石名称。这在业务上是一条必须坚持的原则能显著提升系统的可信度。6.3 验证方法与人工鉴定的双盲对比流程项目验收阶段只做内部指标对比是不够的必须要做双盲验证。流程是选取一条岩心不同深度的 30 块薄片让一位资深鉴定工程师先独立完成人工鉴定同时让模型输出鉴定结论两者都不看对方结果最后统一比对两个结论的差异。比对的维度一是最终岩石定名是否一致二是在鉴定结果中带矿物含量的主要矿物含量差值是否在 5 个百分点以内。我的实测经验是初期版本岩石定名一致率能达到 80% 左右时已经可以进入辅助鉴定阶段稳定达到 90% 以上才有资格尝试交付主要的鉴定工作流。这个方案做到后来我自己学到的一件事是模型指标再好看都不如下队采一批新样本回来重新验一轮因为实验室的样本明显比野外钻进岩屑更洁净、磨损程度更低。每次模型迭代我都会坚持先过双盲对比再上生产磨刀不误砍柴工。希望这个流程能帮你少走一些我在这个项目里走过的弯路也祝你把这套自动鉴定管线做成真正能被地质工程师信任的实用工具。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。