基于Mask R-CNN的缺陷检测Python工程:从框到轮廓的分割实践

发布时间:2026/10/1 3:03:49
基于Mask R-CNN的缺陷检测Python工程:从框到轮廓的分割实践 简介针对图像缺陷检测任务打造的完整Python实现包面向本科与硕士阶段进行计算机视觉、工业质检相关教研学习的学生。内容以Defect Eye缺陷检测为主线覆盖数据示例、模型推理、评估验证等环节。压缩包共227个文件以py源码为核心配合jpg样例图像、md说明文档以及少量c/cpp/pyx扩展模块和ckpt预训练权重整体约49.66MB目录结构便于按检测、评估、工具脚本分类查阅。其中包含mask、bbox、nms等检测相关实现和pycocoDemo等COCO风格评估示例可直接用于理解缺陷区域标注、候选框处理与结果评估流程。已有657人学习适合需要动手复现缺陷检测项目、参考完整代码组织方式的研究者。1. Defect Eye 缺陷检测一套把“框住缺陷”升级成“抠出缺陷轮廓”的 Python 工程做工业缺陷检测的朋友大多经历过这种尴尬拿公开的 YOLO 模型去检测钢材表面划痕框是框住了但轮廓歪得没法用因为缺陷边界本身就是不规则的。Defect Eye 是一套基于 Mask R-CNN ResNet-101 的缺陷检测 Python 代码包自带预训练权重 resnet_v1_101.ckpt外加 pycocoDemo / pycocoEvalDemo 两个验证入口解决的是“既要框住缺陷、又要像素级分割缺陷轮廓”这一类任务。适合刚入缺陷检测方向的硕博生也适合工厂里想快速验证 Mask R-CNN 方案能否落地的算法工程师。我先说一个反直觉结论这套资源常被归到 matlab 图像处理分享里解压后却全是 .c、.ckpt、.ipynb 文件是标准的 Python 工程按 Python 环境去搭才能跑通。2. 选型与结构Mask R-CNN ResNet-101 COCO 评测这份代码到底由什么组成2.1 为什么缺陷检测场景首选 Mask R-CNN而不是 YOLO 或 FCN工业缺陷检测的麻烦在于“不知道边界在哪”。表面划痕、麻点、凹坑、脏污形态不规则很多缺陷只有几百个像素放到 512×512 的图像里就是几个点。YOLO 系列检测器虽然部署友好但输出只有矩形框框住缺陷很容易框住“缺陷的实际占据区域”却做不到。后续要做缺陷面积统计、方向判断、等级分类时矩形框给出的面积误差能到 30%50%对焊接气孔、硅片划痕、轴承滚道凹坑这类缺陷来说这个误差不可接受。Mask R-CNN 在 Faster R-CNN 的检测分支基础上加了一条并行的掩膜分支先通过 RoIAlign 把每个候选框内的特征对齐到固定尺寸再输出 14×14 或 28×28 的二值掩膜上采样到原图尺寸后与真值掩膜做损失。训练时整体是一个多任务损失公式大致是 L L_cls L_box L_mask。L_cls 负责判断框内缺陷类别L_box 用 smooth-L1 回归修正框位置L_mask 用逐像素二分类损失保证缺陷轮廓准确。这套设计天然适合缺陷检测框负责召回区域掩膜负责精确表达边界。另一个原因和“实例数量”有关。像电子元件引脚表面十几个瑕疵可能挤在一个连通区域内语义分割FCN、U-Net会把它们当成一个整体无法区分每个独立缺陷Mask R-CNN 的掩膜是 instance-level 的能输出每个缺陷的独立掩膜方便后续按单个缺陷编号统计。这正好命中缺陷检测最常被问的一个问题同一区域内多个缺陷怎么分组怎么按缺陷逐个做面积和周长统计。那为什么用 ResNet-101 而不是 ResNet-50代码包里的 resnet_v1_101.ckpt 基本说明了一切。更深网络配合 FPN 做多尺度特征融合对小目标召回一般比 ResNet-50 好代价是显存和推理时间。产线相机分辨率高时1280×1024 的输入在 ResNet-101 下显存压力非常大。我的习惯是验证阶段用 ResNet-101 出精度落地阶段换 ResNet-50 做裁剪和量化两套权重分开维护。2.2 代码包文件地图从 maskApi 到 resnet_v1_101.ckpt 各管什么解压后的文件列表很有代表性基本就是 Mask R-CNN 官方工程和 COCO PythonAPI 的常见组合。我整理了一张文件职责表文件类型在缺陷检测里负责什么resnet_v1_101.ckpt预训练权重ResNet-101 骨干初始权重在 ImageNet 上预训练迁移到缺陷特征pycocoDemo.ipynb演示 Notebook加载训练好的模型对单张图像做推理并可视化 mask 结果pycocoEvalDemo.ipynb演示 Notebook按 COCO 指标算 mAP评估模型在验证集上的效果maskApi.c / maskApi.hC 源码掩膜的 RLERun-Length Encoding编解码压缩存储缺陷掩膜_mask.cCython 扩展把 maskApi 封装成 Python 接口训练时每个 step 都要调用bbox.cC 源码COCO 格式包围框的计算与转换nms.cC 源码非极大值抑制的 CPU 实现抑制同一缺陷上的重复框gason.cpp / gason.hJSON 解析器读取 COCO JSON 标注文件解析类别、多边形、bbox 字段先说结论这几个 C 文件不是给人肉看的是为了性能存在的。一次训练里一个 batch 几十张图每张图几百个候选框每个候选框的 mask 都要做 RLE 编解码如果用纯 Python 处理单个 epoch 会多出几十分钟训练时间。maskApi.c 的作用就是把二值掩膜压缩成 RLE 字符串存进 JSON训练时再解压回 mask。bbox.c 和 nms.c 同理都是频繁路径上的性能优化。gason.cpp 是一个轻量 JSON 解析器COCO 格式的标注文件常常到几十 MB解析速度直接决定数据加载耗时。gason.c 的代码量很小读起来不费劲但它不是某个隐藏框架只是 PythonAPI 自带组件。这份工程在数据处理流上很清楚COCO JSON 标注 → gason 解析标注 → maskApi 解码 RLE 掩膜 → 喂给 Mask R-CNN 模型训练。我实际调试时就是按这个链路排查问题基本能定位到具体环节。提示pycocoDemo 和 pycocoEvalDemo 都是基于 COCO 数据集的经典演示入口很多缺陷检测项目把它们保留下来当验收脚本。不是每个文件都需要二次开发先跑通再改。2.3 环境兼容矩阵Python / TensorFlow / Cython 的版本配对这套工程不是“最新版本安装即用”的现代项目而是 TensorFlow 1.x 时代的产物环境版本卡得比较死。以下是我在复现时确认可行的组合组件推荐版本说明Python3.7.93.8 编译 pycocotools 时坑多3.10 容易直接编译失败TensorFlow1.15.0 GPU 版resnet_v1_101.ckpt 是 TF1 checkpoint 格式Keras2.3.1Defect Eye 的模型层依赖这个版本Cython0.29.24新版 Cython 对 .pyx 语法放宽反而容易出兼容问题numpy1.19.51.24 以上删了部分 dtype APIpycocotools2.0.2pip 装通用版本即可源码目录里有 build_ext 也可以我的建议是直接用 conda单独建一个环境别在系统环境里硬塞否则大概率在导入阶段纠缠半天conda create -n defect python3.7.9 -y conda activate defect pip install tensorflow-gpu1.15.0 keras2.3.1 cython0.29.24 numpy1.19.5 pip install opencv-python pillow matplotlib pycocotools2.0.2这里每一行都有用意TensorFlow 1.15 对应 CUDA 10.0 / cuDNN 7.6装新版本 CUDA 反而跑不起来Keras 必须 2.3.1因为模型代码用到了当时旧 Keras 的 API新 Keras 会直接报 cannot import nameCython 锁 0.29 是保险更高版本在 Python 3.7 下也能编但没必要冒险。opencv 是后面做数据增强、画掩膜轮廓要用的图像处理项目绕不开这一点。pycocotools 直接走 pip如果 pip 装出来的包和你手头的 PythonAPI 源码不符再用本地目录编译。还有个我差点漏掉的细节pycocoDemo.ipynb 打开后很可能选不中刚建好的 conda 环境需要补一个 kernel 注册pip install ipykernel python -m ipykernel install --user --name defect --display-name defect-tf1这一步不是可选项。很多人解压后在 jupyter 里打开两个 ipynbKernel 菜单里根本没有刚建的环境就是少了这个注册步骤。两个 Notebook 都是按 jupyter kernel 名匹配环境的名字对不上就会用默认 kernel加载 TensorFlow 1.15 直接失败。3. 把 Defect Eye 跑起来数据、训练、推理三步走3.1 数据准备从 labelme 标注到 COCO JSON 格式转换Mask R-CNN 训练需要的不只是框还有每个缺陷的多边形或掩膜。最常用的标注工具是 labelme多边形标注后保存为独立 JSON但模型框架吃的是 COCO 格式数据集目录所以第一步是转换。COCO 标注文件有三个顶层字段images 记录每张图的 id、宽高、文件名categories 记录缺陷类别名称和 idannotations 记录每个缺陷实例包含 image_id、category_id、多边形 segmentation、bbox、area。下面这个转换脚本是我常用的核心逻辑负责把 labelme 的多边形转成 COCO 需要的 segmentation 和 bboximport json from pycocotools import mask as mask_utils def polygon_to_coco_item(image_id, annotation, height, width): # annotation[points] 是 labelme 里的多边形坐标 poly [float(x) for pt in annotation[points] for x in pt] # frPyObjects 输入要求坐标展平顺序是 [x0, y0, x1, y1, ...] rle mask_utils.frPyObjects([poly], height, width) rle_merged mask_utils.merge(rle) # 统一编码成 COCO 推荐的 RLE segmentation seg mask_utils.encode(mask_utils.decode(rle_merged)) bbox mask_utils.toBbox(seg).tolist() return { image_id: image_id, category_id: annotation[category_id], segmentation: seg, bbox: bbox, area: float(mask_utils.area(seg)) }这段代码里 frPyObjects 的输入要求是“多边形坐标展平后的列表”每个点必须按 [x0, y0, x1, y1, ...] 顺序排列漏掉 float() 转换在部分 pycocotools 版本下会报 cannot convert to RLE。merge 是把同一个缺陷的多段多边形合并成一块避免一个断开的标注被当成多个实例。bbox 用 mask_utils.toBbox 从掩膜计算比用多边形顶点极值更准确因为掩膜已经在图像坐标系里对齐过了。数据目录建议按官方工程惯例组织datasets/ defect_train/ train/ image_001.jpg image_002.jpg val/ image_003.jpg train.json val.jsontrain.json 与 val.json 里 categories 要统一比如 {1: scratch, 2: pit}。一个小坑COCO 的 image id 必须全局唯一如果 train 和 val 各自从 0 开始编号后面 pycocoEvalDemo 出的 mAP 会串数据。我的习惯是所有图像 id 用文件名 hash 生成宁可多占几个字节也不怕重。3.2 训练配置与权重加载预训练权重、anchor 参数、batch size 怎么设工程里需要一个继承 Config 的类核心参数如下class DefectConfig(Config): NAME defect NUM_CLASSES 1 2 # 背景 划痕 凹坑 IMAGE_MIN_DIM 512 IMAGE_MAX_DIM 1024 BATCH_SIZE 2 # 8GB 显存上限16GB 可以到 4 STEPS_PER_EPOCH 500 VALIDATION_STEPS 50 RPN_ANCHOR_SCALES (16, 32, 64, 128, 256) LEARNING_RATE 0.001NUM_CLASSES 必须是 1 缺陷类别数这个 1 是背景类忘掉就等着模型把所有像素都当缺陷。IMAGE_MIN_DIM 和 IMAGE_MAX_DIM 决定图像缩放上限工业相机 1280×1024 的图会被压到最大 1024但小缺陷可能因此缩没了所以批次里应保留原图分辨率并在验证时不要缩小。RPN_ANCHOR_SCALES 默认对齐 COCO 的大目标统计缺陷场景常需要把最小锚点降到 8甚至 4否则小划痕在特征图上只有几个像素正样本都采不到。权重加载分两步。第一步加载预训练骨干model MaskRCNN(modetraining, configconfig, model_dir./logs) model.load_weights(resnet_v1_101.ckpt, by_nameTrue)第二步训练时注意冻结策略model.train(train_dataset, val_dataset, learning_rateconfig.LEARNING_RATE, epochs40, layersheads) # 先只训练 RPN 和检测头 model.train(train_dataset, val_dataset, learning_rateconfig.LEARNING_RATE / 10, epochs100, layersall) # 解冻全部 backboneby_nameTrue 是关键ckpt 里只有骨干变量不匹配 head 变量是正常的它会按变量名把 ResNet 卷积和 BN 层填进来。layersheads 阶段学习率保持 0.001等 head 收敛后再以 0.0001 解冻 backbone否则 backbone 老权重被大步长打乱loss 会先涨一波。显存只有 8GB 时BATCH_SIZE 建议直接设为 1STEPS_PER_EPOCH 相应加到 800不然训练后期基本必 OOM。训练中间也可以加一点随机增强比如左右翻转、旋转 90 度、随机亮度扰动。对于钢材表面划痕这类方向性较强的缺陷翻转要谨慎横着和竖着的划痕可能不是同一类而螺栓表面缺陷这类旋转不变性强的样本增强空间可以大一点。这个差异会在验证集 AP 上表现得非常明显。3.3 训练与推理从加载权重到 pycocoDemo 的完整链路训练日志要盯三个量总 loss、rpn_bbox_loss、mrcnn_mask_loss。总 loss 稳但 mask loss 不动说明掩膜分支没学到东西多半是标注里 segmentation 为空或全部是背景。交互式 Notebook 里模型加载与推理代码是这样的from mrcnn.model import MaskRCNN model MaskRCNN(modeinference, configconfig, model_dir./logs) model.load_weights(mask_rcnn_defect_0100.h5, by_nameTrue) results model.detect([image], verbose1)[0] for i, score in enumerate(results[scores]): if score 0.5: mask results[masks][:, :, i] # 布尔掩膜 class_id results[class_ids][i] roi results[rois][i] # [y1, x1, y2, x2]detect 返回的 rois 顺序是 y1, x1, y2, x2不是 x, y, w, h很多人画框时把 x 和 y 换错看到 mask 和框错位才回头查。masks 的第三个维度是实例索引每张图最多输出的实例数就是这个维度长度。score 默认阈值 0.7工业场景我一般降到 0.5 以保召回。调试阶段建议顺手把 mask 叠加在图像上用 opencv 画出来看看肉眼比指标更容易发现方向性问题import cv2 vis image.copy() for i, score in enumerate(results[scores]): if score 0.5: continue m results[masks][:, :, i].astype(uint8) * 255 contours, _ cv2.findContours(m, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(vis, contours, -1, (0, 255, 0), 2)cv2.findContours 把布尔掩膜转成轮廓再用 drawContours 画出轮廓线这是 opencv 图像处理项目里很标准的可视化套路。如果画出来的轮廓和标注图对不上先检查数据转换再怀疑训练。推理阶段全部就绪后下一步就是用 pycocoEvalDemo 算指标。4. Defect Eye 避坑实录5 个我在复现时踩过的坑4.1 坑一resnet_v1_101.ckpt 加载失败提示 Unknown opcode现象代码执行到 model.load_weights(resnet_v1_101.ckpt, by_nameTrue) 时直接抛 ValueError错误类似 Unknown opcode 或 No variables to save也有人遇到 checkpoint 读取后所有变量列表为空。原因resnet_v1_101.ckpt 是 TensorFlow 1.x 保存的 checkpoint 文件内部记录的计算图 opcode 与 TensorFlow 2.x 不兼容。TF 2 用 compat.v1 模块读取也可能因为变量作用域命名不一致而找不到匹配项。还有一个隐含原因checkpoint 只有数据没有图结构必须等模型定义完成后才能 load而模型定义依赖 configconfig 里 NUM_CLASSES 改错也会导致变量名不匹配。解决先确认环境是 TF 1.15 而不是 TF 2.x。如果必须留在 TF 2则要先把 ckpt 转成 h5转换思路是遍历 checkpoint 变量名逐个赋给 Keras 模型不同工程的导出姿势略有差异。实际操作中我绕过转换直接把整个训练流程都放在 TF 1.15 环境里反正工业项目也不需要依赖 TF 2 的新特性。还有一个排查偏方先用脚本列出 checkpoint 里所有变量名检查 backbone 变量的前缀是不是 resnet_v1_101/conv1/...如果前缀不对说明这个 ckpt 是从别的 ResNet 变体重命名的加载时就要做变量名映射。python -c from tensorflow.python.training import checkpoint_utils; print(len(checkpoint_utils.list_variables(resnet_v1_101.ckpt)[0]))4.2 坑二编译 maskApi.c 时报错找不到 gason.h 或头文件冲突现象在 PythonAPI 目录下跑 python setup.py build_ext --inplace 报错 fatal error: gason.h: No such file or directory或者编译通过但 import pycocotools 失败提示 undefined symbol。原因cocoapi 官方源码里 gason.cpp 与 gason.h 在 common/ 子目录而 setup.py 的 include 路径没有加 common/旧版 cocoapi 对 Python 3.7 以上版本兼容性也不好。更常见的是下载到的压缩包本身缺了 gason.h只保留了 gason.cpp自然编译不过。解决先确认源码完好从 cocoapi 源码包把 common/gason.h 补进对应目录然后统一执行编译cd coco/PythonAPI export CFLAGS-I./common python setup.py build_ext --inplace编译完成后一定要在 Python 里做一次冒烟测试 import pycocotools 并执行一次 RLE 编解码确认扩展库真的生效。还有内存对齐问题新版 gcc 默认优化级别在某些平台下会导致 nms.c 的行为变怪表现是同一输入两次运行结果不同这时候把优化级别降到 -O0 再编一次。Windows 下没有完整 Visual Studio 工具链的直接用 WSL 或者 MinGW别在第三方源里碰“预编译 wheel”版本签名对不上反而多耗几个小时。4.3 坑三训练 loss 卡在 1.8 附近不降mAP 全为 0现象训练 50 个 epoch总 loss 一直在 1.82.0 之间震荡验证集 mAP 始终是 0检测结果全是空白框或者只输出背景。原因最常见的是正样本太少。缺陷尺寸相对整图极小默认 RPN_ANCHOR_SCALES 从 32 起跳小缺陷的正样本在锚点上几乎没有命中。第二个原因是类别不平衡严重划痕类有 1000 个实例、凹坑只有 50 个模型退化成把缺陷都往划痕类上贴。第三个原因是被我耽误最久的标注里 segmentation 字段为空只在 bbox 里给了框掩膜分支没有真值可学mrcnn_mask_loss 永远得不到下降信号。解决第一个动作先做可视化核查直接把标注掩膜画在图上import cv2, json from pycocotools import mask as mask_utils anns json.load(open(data/train.json))[annotations] for ann in anns: m mask_utils.decode(ann[segmentation]) cv2.imwrite(fmask_{ann[image_id]}_{ann[id]}.png, m * 255)确认掩膜不是全黑也不是全白。如果掩膜区域太小说明 anchor 尺度要往下调把 RPN_ANCHOR_SCALES 改为 (8, 16, 32, 64, 128)并在训练数据里做随机裁剪让缺陷占比变大。类别不平衡则给少数类加权实践做法是在损失加权项里把 pit 类的 loss 权重乘 25。做了这些还没起色就检查是不是 backbone 解冻太早导致特征被破坏把 layersall 之后的学习率从 0.001 直接降到 0.0001再多跑 20 个 epoch。mAP 全 0 还有一种常见路径验证集和训练集的类 ID 没有对齐COCO 的 category_id 从 1 开始而某些脚本里用的是 0-index两个数据集类编号对不齐评估时所有预测被标成未知类。4.4 坑四检测结果同一缺陷出现十几个重叠框NMS 等于没做现象推理结果里一个真实缺陷被输出十几个不同大小的方框和掩膜置信度从 0.9 到 0.4 都有。肉眼看着是同一块区域但模型就是一股脑全给出来。原因NMS 没有正常执行。常见有两层一是 nms.c 编译失败模型代码里 import 不到自定义 NMS就退回一个极弱的后处理二是 NMS 的 IoU 阈值默认 0.3 太严工业图像背景干净、缺陷框之间重叠度极高0.3 会把同一缺陷的多个 proposal 全部保留等于没有抑制。第三种是被忽略的场景mask 分支叠加在多个 proposal 上每个 proposal 都有自己的 mask最终结果是多份掩膜叠加而不是去重后的唯一输出。解决先确认 NMS 是否真的生效在推理脚本里加一个调试点打印 proposals 数量和经过 NMS 后的数量from mrcnn.utils import apply_nms keep apply_nms(proposals, scores, 0.5) print(fbefore: {len(scores)}, after: {len(keep)})如果 before 和 after 完全一样说明 NMS 函数没有接入正路径。然后按实际重叠度调阈值缺陷本身有粘连时把 NMS IoU 从 0.3 放宽到 0.50.6能保留不同缺陷但过滤同一缺陷。还有一个容易忽略的参数是 DETECTION_MIN_CONFIDENCE默认 0.7如果我降到 0.3 去追召回NMS 就要面对大量低分框。经验是先 NMS 后阈值要么先把置信度压到 0.5 再进 NMS要么让 NMS 按 confidence 排序后直接截断数量。COCO 评测里的 maxDets100 也是 NMS 之后最多保留 100 个结果别指望它替你清理重叠框。4.5 坑五CUDA OOMbatch size 调到 1 仍然显存不足现象训练启动后报 CUDA_ERROR_OUT_OF_MEMORY或者运行到某一步突然卡死控制台输出 Resource exhausted: OOM when allocating tensor with shape。有人把 BATCH_SIZE 改成 1 还是不够。原因ResNet-101 特征图大Mask R-CNN 的 FPN 又保留多层特征图显存占用是 YOLO 的好几倍。一个容易被忽视的显存黑洞是 IMAGE_MAX_DIM设成 1024 时FPN 多层特征图加上 RPN proposal 的 ROI 特征一张图就可能吃掉 34 GBbatch1 也不能兜底。解决显存预算要按特征图尺寸算而不是只调 batch size。先把图片上限降下来IMAGE_MIN_DIM 480 IMAGE_MAX_DIM 640 RPN_ANCHOR_SCALES (8, 16, 32, 64, 128)这种配置下缺陷占比变大小目标锚点也够用整体显存能压到 2GB 以内。训练脚本入口处加显存自适应的代码能兜住不同显卡import tensorflow as tf from tensorflow.compat.v1 import ConfigProto config ConfigProto() config.gpu_options.allow_growth True sess tf.Session(configconfig)allow_growth 让 TensorFlow 按需吃显存不再一次性把整张卡占满。TF 2 则换 tf.config.experimental.set_memory_growth(gpus[0], True)。再不行就按通道裁剪 FPN 深度从 256 降到 128mAP 会掉一点但训练能跑起来。撞过这面墙之后我的习惯是新数据集第一次训练闭眼先用 640 上限把链路跑通再逐步加到 1024绝不一上来就挑战最大分辨率。5. 进阶用 pycocoEvalDemo 验证 mAP、按阈值反推改参再做 ROI 裁剪推理5.1 pycocoEvalDemo 的四个关键参数iouType、maxDets、areaRng、置信度pycocoEvalDemo 的评估入口是 COCOeval初始化时最容易调错的是 iouType。iouTypesegm 按掩膜 IoU 评估对缺陷轮廓边界的轻微偏移非常敏感iouTypebbox 只看包围框评估结果更乐观。我的习惯是两个都跑中间差太多就说明轮廓精度不够。maxDets 一般设 [1, 10, 100]缺陷密度高时 10 和 100 的差距能直观反映漏检。areaRng 控制按面积范围过滤针对微小缺陷要单独看小面积区间的 AR否则被大缺陷的平均值掩盖。from pycocotools.coco import COCO from pycocotools.cocoeval import COCOeval coco_gt COCO(data/val.json) coco_dt coco_gt.loadRes(predictions_file) coco_eval COCOeval(coco_gt, coco_dt, segm) coco_eval.params.maxDets [1, 10, 100] coco_eval.evaluate() coco_eval.accumulate() coco_eval.summarize()loadRes 需要 predictions 文件每项包含 image_id、category_id、score、segmentation、bbox。如果预测里少了 bbox在 bbox 模式下会直接 KeyError。这一步别偷懒把 mask 用 mask_utils.encode 转成 RLE 再放进去否则 loadRes 报 segmentation 无法解析。5.2 按 mAP 反推阈值决定要不要砍掉 Mask 分支mAP 在 0.5 以下很正常先看 PR 曲线AP0.5 正常但 AP0.75 直接腰斩说明掩膜轮廓偏离真值在 25% IoU 附近徘徊问题在掩膜分支而不在框分支所有阈值都低就从 NMS 阈值和 DETECTION_MIN_CONFIDENCE 查起先提置信度到 0.8 压掉低分误报再放开 NMS 到 0.6 让粘连缺陷得以区分。这里有一个“砍分支”的决策可做如果业务只要缺陷框不要轮廓就在推理阶段跳过 mask 头只保留 RPN 和检测头推理速度大约快 30%。5.3 工业落地ROI 裁剪后再推理把单张耗时压下来测试阶段最实际的经验是别让 Mask R-CNN 直接吃整张高分辨率图。工业相机动不动 500 万像素全图推理单张一秒钟以上。我的做法是按正方形滑动窗口裁图重叠率 25%先在小窗口上推理再把 mask 按坐标偏移贴回原图def crop_infer(model, image, crop_size512, stride384): h, w image.shape[:2] masks np.zeros((h, w), dtypeuint8) for y in range(0, h - crop_size 1, stride): for x in range(0, w - crop_size 1, stride): crop image[y:ycrop_size, x:xcrop_size] r model.detect([crop], verbose0)[0] for i in range(len(r[masks][0])): m r[masks][:, :, i] masks[y:ycrop_size, x:xcrop_size][m] 255 return masksstride 比 crop_size 小让相邻窗口有重叠。重叠区同一缺陷可能被重复检测合并时以分数最高的实例为准mask 重叠 IoU 超过 0.5 就取并集边界处面积占比低于 30% 的碎片掩膜直接丢弃。从那以后我每次复现一个视觉检测项目第一件事就是按“ckpt 加载 → 扩展编译 → NMS 生效 → 显存预估 → 小窗验证”的顺序强制走一遍自检流程这也是我把 5 个坑沉淀成固定动作的习惯。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询