基于 YOLOv8-seg 的矿物颗粒分割完整技术文档

基于YOLOv8-seg的矿物颗粒分割完整技术文档

一、环境准备

1.1 依赖库安装

# 安装Labelme(数据标注工具,兼容Python 3.8)
pip install labelme==4.5.6

# 安装YOLOv8及核心依赖(含PyTorch、OpenCV等)
pip install ultralytics==8.3.20 opencv-python numpy pillow

1.2 工作目录结构(固定)

F:/animalrec/test/  # 根目录
├─ mineral_dataset/  # 数据集文件夹
│  ├─ annotations/   # Labelme标注JSON文件存放处
│  └─ train/         # YOLO训练集(自动生成)
│     ├─ images/     # 训练图像
│     └─ labels/     # YOLO格式标签
├─ yolov8x-seg.pt    # YOLOv8-seg预训练模型(需提前下载)
├─ 1234.jpg          # 待分割的矿物电镜图(示例图像)
├─ json2yolo.py      # Labelme JSON转YOLO格式脚本
├─ data.yaml         # YOLO数据集配置文件
├─ train_mineral.py  # 模型训练脚本
└─ infer_mineral.py  # 推理与颗粒提取脚本

1.3 预训练模型下载

从官方链接下载yolov8x-seg.pt,放入根目录:
https://github.com/ultralytics/assets/releases/download/v8.3.0/yolov8x-seg.pt

二、数据标注(Labelme)

2.1 启动Labelme

# 1. 打开PowerShell,切换到根目录
cd F:/animalrec/test

# 2. 启动Labelme
labelme

2.2 标注步骤

  1. 点击菜单栏「File」→「Open」,选择根目录的1234.jpg
  2. 点击左侧工具栏「多边形图标」(快捷键P),沿矿物颗粒边缘点击生成顶点(边缘复杂处多点击);
  3. 双击闭合多边形,弹出「Label」输入框,输入mineral,点击「OK」;
  4. 点击菜单栏「File」→「Save」,选择mineral_dataset/annotations/,保存为1234.json(与图像同名)。

三、Labelme JSON转YOLO格式(关键步骤)

3.1 创建转换脚本(json2yolo.py)

import json
import numpy as np
import cv2
import base64
import os
from labelme import utils

# 路径配置(无需修改,匹配工作目录)
json_path = "mineral_dataset/annotations/1234.json"
output_dir = "mineral_dataset/train"
os.makedirs(output_dir, exist_ok=True)
os.makedirs(os.path.join(output_dir, "images"), exist_ok=True)
os.makedirs(os.path.join(output_dir, "labels"), exist_ok=True)

# 读取JSON并解码图像
with open(json_path, "r", encoding="utf-8") as f:
    data = json.load(f)
image_bytes = base64.b64decode(data["imageData"])
image_np = np.frombuffer(image_bytes, dtype=np.uint8)
img = cv2.imdecode(image_np, cv2.IMREAD_COLOR)

# 保存图像到train/images
img_save_path = os.path.join(output_dir, "images", "1234.jpg")
cv2.imwrite(img_save_path, img)
print(f"图像已保存:{img_save_path}")

# 转换标注为YOLO格式(归一化坐标)
img_h, img_w = img.shape[0], img.shape[1]
yolo_labels = []
for shape in data["shapes"]:
    if shape["label"] == "mineral":
        points = shape["points"]
        normalized = []
        for x, y in points:
            normalized.append(x / img_w)
            normalized.append(y / img_h)
        label_line = f"0 {' '.join(map(str, normalized))}\n"
        yolo_labels.append(label_line)

# 保存TXT标签到train/labels
label_save_path = os.path.join(output_dir, "labels", "1234.txt")
with open(label_save_path, "w", encoding="utf-8") as f:
    f.writelines(yolo_labels)
print(f"YOLO标签已保存:{label_save_path}")

# 验证转换结果
with open(label_save_path, "r") as f:
    print("\nYOLO标签内容:")
    print(f.read())

3.2 执行转换

python json2yolo.py

转换成功标志:

  • 输出“图像已保存:F:/animalrec/test/mineral_dataset/train/images/1234.jpg”
  • 输出“YOLO标签已保存:F:/animalrec/test/mineral_dataset/train/labels/1234.txt”

四、YOLO数据集配置文件(data.yaml)

# 数据集根目录(绝对路径,Windows用/或\\)
path: F:/animalrec/test/mineral_dataset

# 训练集/验证集路径(单图场景:val与train一致,自动拆分)
train: train/images
val: train/images

# 类别配置(仅1类:mineral)
nc: 1
names:
  0: mineral

五、YOLOv8-seg模型训练

5.1 创建训练脚本(train_mineral.py)

from ultralytics import YOLO

# 加载预训练模型
model = YOLO("yolov8x-seg.pt")

# 启动训练(参数适配单图场景,无需修改)
results = model.train(
    data="data.yaml",
    epochs=8,            # 训练轮数(单图8轮足够)
    batch=1,             # CPU必设1,避免内存溢出
    imgsz=640,           # 输入图像尺寸
    lr0=0.0005,          # 初始学习率(CPU训练降低)
    val=True,            # 开启验证
    split=0.2,           # 20%训练集拆分为验证集
    save_period=2,       # 每2轮保存模型
    device="cpu",        # 有GPU改"0"
    augment=True,        # 开启数据增强
    patience=3           # 早停机制
)

# 输出训练结果
val_results = model.val()
print("\n=== 训练结果汇总 ===")
print(f"分割mAP50:{val_results.mask.map50:.3f}")
print(f"分割mAP50-95:{val_results.mask.map:.3f}")
print(f"精确率(P):{val_results.mask.p:.3f}")
print(f"召回率(R):{val_results.mask.r:.3f}")
print(f"最优模型路径:runs/segment/train/weights/best.pt")

5.2 执行训练

python train_mineral.py

训练成功标志:

  • 损失逐步下降(如seg_loss从6+降至3+)
  • 最终输出“8 epochs completed”
  • 验证指标mask.map50>0.9

六、模型推理与矿物颗粒提取

6.1 创建推理脚本(infer_mineral.py)

from ultralytics import YOLO
import cv2
import os
import numpy as np

# 基础配置(无需修改,匹配工作目录)
model_path = "runs/segment/train/weights/best.pt"
img_path = "mineral_dataset/train/images/1234.jpg"
output_root = "mineral_infer_results"

# 创建结果目录
os.makedirs(output_root, exist_ok=True)
overall_dir = os.path.join(output_root, "overall_result")
single_dir = os.path.join(output_root, "single_particles")
os.makedirs(overall_dir, exist_ok=True)
os.makedirs(single_dir, exist_ok=True)

# 加载模型并推理
model = YOLO(model_path)
results = model.predict(
    img_path,
    save=True,
    conf=0.2,
    iou=0.5,
    save_dir=overall_dir
)

# 读取原始图像
raw_img = cv2.imread(img_path)
img_h, img_w = raw_img.shape[:2]

# 按全图框选提取单个矿物
boxes = results[0].boxes
if boxes is not None:
    for idx, box in enumerate(boxes):
        # 提取边界框坐标
        x1, y1, x2, y2 = box.xyxy[0].cpu().numpy()
        # 坐标处理(转整数+防溢出)
        x1 = int(max(0, x1))
        y1 = int(max(0, y1))
        x2 = int(min(img_w, x2))
        y2 = int(min(img_h, y2))
        # 过滤极小框
        if (x2 - x1) < 20 or (y2 - y1) < 20:
            continue
        # 裁剪并保存
        single_particle = raw_img[y1:y2, x1:x2]
        save_path = os.path.join(single_dir, f"mineral_{idx}.jpg")
        cv2.imwrite(save_path, single_particle)
        print(f"已保存单个颗粒:{save_path}")

print(f"\n推理完成!")
print(f"- 全图结果:{os.path.join(overall_dir, 'predict')}")
print(f"- 单个颗粒:{single_dir}")

6.2 执行推理

python infer_mineral.py

推理成功标志:

  • 输出“已保存单个颗粒:F:/animalrec/test/mineral_infer_results/single_particles/mineral_*.jpg”
  • 全图结果目录生成带绿色框的图像,单个颗粒目录生成无偏差裁剪图

七、常见问题排查

问题现象 解决方案
Labelme启动报错“TypeError: 'type' object is not subscriptable” 执行:pip uninstall labelme -y && pip install labelme==4.5.6
训练报错“Dataset 'data.yaml' images not found” 确保data.yamlpath为绝对路径(如F:/animalrec/test/mineral_dataset
推理时单个颗粒截取偏差 确保推理脚本使用results[0].boxes.xyxy坐标(参考6.1节脚本)
训练损失下降缓慢 降低lr0=0.0005,确保augment=True
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容