news 2026/6/10 16:18:41

YOLO11模型推理实战:保存结果并可视化分割效果

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLO11模型推理实战:保存结果并可视化分割效果

YOLO11模型推理实战:保存结果并可视化分割效果

1. 为什么这次推理要“看得见、留得住”

你训练好了一个YOLO11图像分割模型,但跑完predict()后只看到终端里一串日志——结果在哪?分割掩码长什么样?边界框是否贴合?类别标签对不对?有没有办法把每张图的预测结果原样保存下来,方便后续检查、汇报或集成到业务系统中?

这不是小问题。在真实项目中,可复现、可验证、可交付的推理输出,往往比训练过程本身更关键。本文不讲训练原理,不堆参数配置,只聚焦一件事:如何用YOLO11完成一次干净、可控、结果可视化的图像分割推理,并把所有关键产物(带掩码的图片、标注文件、统计信息)完整保存下来

全程基于CSDN星图提供的YOLO11镜像环境,无需额外安装依赖,开箱即用。所有操作均在Jupyter或SSH终端中完成,代码可直接复制运行。

2. 环境准备与路径确认

2.1 进入标准工作目录

YOLO11镜像已预置完整项目结构。请先确保你在正确路径下执行后续命令:

cd ultralytics-8.3.9/

该目录下应包含:

  • segment/:存放分割任务相关资源(数据、配置、权重、输出)
  • resources/:原始图像、标注、配置文件所在根目录
  • train.py/predict_seg.py等脚本

验证方式:执行ls -l resources/config/data/,应能看到yolo11-seg.yaml;执行ls -l segment/train/weights/,应存在训练好的best.pt权重文件。

2.2 检查输入数据位置

YOLO11分割推理支持多种输入源。本文以本地验证集图像目录为例,路径为:

resources/images/seg/datasets/images/val/

该目录下应有若干.jpg.png格式图像(如001.jpg,002.jpg),与训练时使用的验证集一致。若需测试单张图,也可将图片放入此目录或指定绝对路径。

3. 核心推理脚本详解:不只是predict()

3.1 最简可用版本(快速验证)

新建文件predict_simple.py,内容如下:

from ultralytics import YOLO # 加载训练好的分割模型权重 model = YOLO("segment/train/weights/best.pt") # 执行推理:指定输入源、输出项目名、自动保存结果 results = model.predict( source="resources/images/seg/datasets/images/val", project="segment/predict", # 输出根目录 name="simple_run", # 当前实验子目录名 save=True, # 保存带可视化效果的图片 save_txt=True, # 保存每张图的预测坐标+掩码(txt格式) save_conf=True, # 在保存的图片上显示置信度 imgsz=640, # 统一缩放尺寸 conf=0.4, # 置信度阈值:仅保留≥0.4的检测 iou=0.7, # NMS IoU阈值 device="cpu" # 可选 "cuda:0"(若GPU可用) ) print(f" 推理完成!共处理 {len(results)} 张图像") print(f" 结果保存在:segment/predict/simple_run/")

运行后,你会在segment/predict/simple_run/下看到:

  • labels/:每个.txt文件对应一张图,含类别ID、置信度、归一化掩码点坐标(按顺时针顺序)
  • runs/detect/simple_run/:带彩色分割掩码和边框的可视化图片(.jpg

注意:save=True保存的是叠加了分割效果的可视化图,非原始图像;save_txt=True保存的是纯文本标注,可用于下游解析。

3.2 生产级增强版(推荐用于项目交付)

实际工作中,我们常需:

  • 控制输出精度(如只保存高置信度结果)
  • 区分不同类别掩码颜色
  • 导出为通用格式(PNG透明通道、JSON结构化数据)
  • 记录每张图的耗时与统计信息

以下predict_production.py满足上述需求:

import os import time import json from pathlib import Path from datetime import datetime import numpy as np from PIL import Image, ImageDraw, ImageFont from ultralytics import YOLO # 初始化模型 model = YOLO("segment/train/weights/best.pt") model.names = {0: "person", 1: "car"} # 显式声明类别名,避免yaml读取异常 # 输入与输出配置 source_dir = Path("resources/images/seg/datasets/images/val") output_root = Path("segment/predict") exp_name = f"prod_{datetime.now().strftime('%Y%m%d_%H%M%S')}" output_dir = output_root / exp_name # 创建输出目录 (output_dir / "images").mkdir(parents=True, exist_ok=True) (output_dir / "masks").mkdir(exist_ok=True) (output_dir / "json").mkdir(exist_ok=True) (output_dir / "stats").mkdir(exist_ok=True) # 类别颜色映射(BGR格式,OpenCV使用) colors = { 0: (0, 255, 0), # person → 绿色 1: (255, 0, 0) # car → 红色 } # 统计容器 stats = { "total_images": 0, "total_detections": 0, "by_class": {"person": 0, "car": 0}, "inference_times": [] } print(f" 开始生产级推理 | 输入:{source_dir} | 输出:{output_dir}") for img_path in sorted(source_dir.glob("*.jpg")) + sorted(source_dir.glob("*.png")): stats["total_images"] += 1 start_time = time.time() # 单图推理(禁用自动保存,我们手动控制) results = model.predict( source=str(img_path), imgsz=640, conf=0.45, # 提高阈值,减少误检 iou=0.65, # 更严格NMS device="cpu", verbose=False # 关闭冗余日志 ) infer_time = time.time() - start_time stats["inference_times"].append(infer_time) # 解析结果 result = results[0] orig_img = result.orig_img # 原始BGR数组 h, w = orig_img.shape[:2] # 创建可视化图(RGB) vis_img = cv2.cvtColor(orig_img, cv2.COLOR_BGR2RGB) pil_img = Image.fromarray(vis_img) draw = ImageDraw.Draw(pil_img) # 创建透明掩码图(RGBA) mask_img = Image.new("RGBA", (w, h), (0, 0, 0, 0)) mask_draw = ImageDraw.Draw(mask_img) # 处理每个检测框与掩码 if result.masks is not None: masks = result.masks.data.cpu().numpy() # [N, H, W] boxes = result.boxes.xyxy.cpu().numpy() # [N, 4] classes = result.boxes.cls.cpu().numpy().astype(int) confs = result.boxes.conf.cpu().numpy() for i, (mask, box, cls_id, conf) in enumerate(zip(masks, boxes, classes, confs)): if conf < 0.45: # 再次过滤 continue stats["total_detections"] += 1 class_name = model.names.get(cls_id, "unknown") stats["by_class"][class_name] = stats["by_class"].get(class_name, 0) + 1 # 绘制边界框(带置信度标签) x1, y1, x2, y2 = map(int, box) color = colors.get(cls_id, (128, 128, 128)) draw.rectangle([x1, y1, x2, y2], outline=color, width=2) draw.text((x1, y1-20), f"{class_name} {conf:.2f}", fill=color, font_size=14) # 绘制半透明分割掩码 mask_pil = Image.fromarray((mask * 255).astype(np.uint8)) # 创建彩色掩码层 colored_mask = Image.new("RGBA", (w, h), (*color, 100)) # 100为透明度 mask_resized = mask_pil.resize((w, h), Image.NEAREST) mask_img.paste(colored_mask, (0, 0), mask_resized) # 合并可视化图与掩码图 final_img = Image.alpha_composite(pil_img.convert("RGBA"), mask_img) final_img = final_img.convert("RGB") # 保存三类产物 stem = img_path.stem final_img.save(output_dir / "images" / f"{stem}_vis.jpg", quality=95) # 保存纯掩码(PNG,单通道二值图) if result.masks is not None: mask_sum = np.zeros((h, w), dtype=np.uint8) for mask in result.masks.data.cpu().numpy(): mask_sum = np.maximum(mask_sum, (mask * 255).astype(np.uint8)) Image.fromarray(mask_sum).save(output_dir / "masks" / f"{stem}_mask.png") # 保存结构化JSON(含坐标、面积、置信度) json_data = { "image": str(img_path.name), "timestamp": datetime.now().isoformat(), "inference_time_sec": round(infer_time, 3), "detections": [] } if result.masks is not None: for i, (mask, box, cls_id, conf) in enumerate(zip(masks, boxes, classes, confs)): if conf >= 0.45: # 计算掩码面积(像素数) area_px = int(np.sum(mask)) json_data["detections"].append({ "class_id": int(cls_id), "class_name": model.names.get(cls_id, "unknown"), "confidence": float(conf), "bbox": [float(x) for x in box], "area_pixels": area_px, "mask_shape": [int(x) for x in mask.shape] }) with open(output_dir / "json" / f"{stem}.json", "w", encoding="utf-8") as f: json.dump(json_data, f, indent=2, ensure_ascii=False) print(f" {stem}: {len(json_data['detections'])} 个目标 | {infer_time:.3f}s") # 保存全局统计 stats["avg_inference_time"] = round(np.mean(stats["inference_times"]), 3) stats["max_inference_time"] = round(np.max(stats["inference_times"]), 3) with open(output_dir / "stats" / "summary.json", "w", encoding="utf-8") as f: json.dump(stats, f, indent=2, ensure_ascii=False) print(f"\n 推理完成!总计 {stats['total_images']} 张图,{stats['total_detections']} 个检测") print(f" 统计报告:{output_dir / 'stats' / 'summary.json'}") print(f"🖼 可视化图:{output_dir / 'images'}") print(f"🧩 掩码图:{output_dir / 'masks'}") print(f" 结构化数据:{output_dir / 'json'}")

关键增强点:

  • 显式类别映射:避免names读取失败导致标签错乱
  • 双层置信度过滤conf参数 + 代码内二次判断,提升结果纯净度
  • 透明掩码叠加:使用PIL Alpha通道实现专业级可视化
  • 多格式输出:JPEG(人眼查看)、PNG(掩码提取)、JSON(程序解析)
  • 全量统计:单图耗时、总目标数、按类别分布、平均/最大推理延迟

4. 结果解读与常见问题排查

4.1 三类核心输出文件说明

文件类型路径示例用途查看方式
可视化图segment/predict/prod_20250401_103022/images/001_vis.jpg直观验证分割质量:掩码是否贴合、颜色是否区分、标签是否准确任意图片查看器
二值掩码图segment/predict/prod_20250401_103022/masks/001_mask.png供下游算法使用:抠图、面积计算、形态学处理Pythoncv2.imread(..., cv2.IMREAD_GRAYSCALE)
结构化JSONsegment/predict/prod_20250401_103022/json/001.json程序化接入:获取每个目标的坐标、置信度、面积等元数据文本编辑器或Pythonjson.load()

4.2 典型问题与解决方案

❌ 问题1:save=True生成的图片全是黑的或无掩码

原因:YOLO11默认使用OpenCV绘图,而镜像中OpenCV可能未正确链接GUI后端(尤其Jupyter环境)。
解法:改用PIL绘图(如3.2节脚本),或强制指定plt后端:

import matplotlib matplotlib.use('Agg') # 在import ultralytics前执行
❌ 问题2:results[0].masksNone

原因:模型未正确加载分割头,或权重文件损坏。
验证:运行print(model.model.head),应看到Segment模块;检查best.pt文件大小是否 >100MB。
解法:重新下载权重,或确认训练时使用了yolo11-seg.yaml配置。

❌ 问题3:JSON中掩码坐标是浮点数,无法直接用于OpenCV

原因:YOLO11保存的是归一化坐标(0~1范围)。
解法:在解析时还原为像素坐标:

h, w = 640, 640 # 或从原图读取 x_norm, y_norm = coords # 归一化点 x_px, y_px = int(x_norm * w), int(y_norm * h)

5. 进阶技巧:让结果更实用

5.1 批量导出为视频(动态演示)

images/下所有_vis.jpg按序号排序,用OpenCV合成MP4:

import cv2 import glob import os img_paths = sorted(glob.glob("segment/predict/*/images/*_vis.jpg")) if not img_paths: print("❌ 未找到可视化图片") exit() # 读取第一张图获取尺寸 frame = cv2.imread(img_paths[0]) h, w = frame.shape[:2] out = cv2.VideoWriter( "segment/predict/demo.mp4", cv2.VideoWriter_fourcc(*'mp4v'), 2, (w, h) ) for p in img_paths: out.write(cv2.imread(p)) out.release() print(" 视频已生成:segment/predict/demo.mp4")

5.2 一键生成HTML报告(交互式查看)

创建generate_report.py,自动生成带缩略图和点击放大功能的静态页面:

# 此处省略具体HTML生成代码(因篇幅限制) # 实际可使用jinja2模板渲染,包含: # - 每张图缩略图网格 # - 点击弹出高清图+JSON数据 # - 统计图表(matplotlib生成SVG嵌入)

5.3 与业务系统对接建议

  • Web服务封装:用Flask/FastAPI包装predict_production.py逻辑,提供HTTP API
  • 定时任务:用cron定期扫描新图片目录并触发推理
  • 云存储同步:推理完成后自动上传images/json/到OSS/S3

6. 总结:一次可靠推理的四个关键动作

1. 环境确认

务必执行cd ultralytics-8.3.9/并验证best.pt存在,避免路径错误导致静默失败。

2. 参数精调

conf(置信度)和iou(重叠阈值)不是固定值。建议:

  • 初次运行设conf=0.3全量观察;
  • 交付前调至conf=0.45~0.55平衡召回与精度;
  • iou保持0.6~0.7,过高易漏检,过低易重复。

3. 输出分层

永远同时保存三类产物:

  • images/:给人看的最终效果(JPEG)
  • masks/:给机器用的掩码(PNG)
  • json/:给系统用的元数据(JSON)
    缺失任一者,都意味着交付不完整。

4. 验证闭环

不要只信终端日志。打开images/目录,随机抽查5张图:

  • 掩码边缘是否锯齿严重?→ 检查imgsz是否过小(建议≥640)
  • 同一物体是否被重复检测?→ 降低iou或提高conf
  • 类别标签是否错位?→ 检查model.names是否与训练yaml一致

推理不是训练的终点,而是价值落地的起点。当你能稳定产出可验证、可交付、可集成的结果时,YOLO11才真正成为你工具箱里的一把快刀。

--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 11:01:05

效果惊艳!cv_resnet18_ocr-detection生成的检测框可视化展示

效果惊艳&#xff01;cv_resnet18_ocr-detection生成的检测框可视化展示 你是否见过一张图里文字被精准“圈出来”的瞬间&#xff1f;不是粗略的矩形&#xff0c;而是紧紧贴合每个字块边缘的四边形&#xff1b;不是模糊的轮廓&#xff0c;而是连倾斜角度、弯曲弧度都如实还原的…

作者头像 李华
网站建设 2026/6/10 10:51:40

个人IP打造:自媒体博主形象统一设计方案

个人IP打造&#xff1a;自媒体博主形象统一设计方案 在自媒体时代&#xff0c;一个辨识度高、风格统一的视觉形象&#xff0c;往往比内容本身更快被记住。你有没有发现&#xff0c;那些粉丝量百万的博主&#xff0c;无论出现在小红书、抖音还是公众号&#xff0c;头像、封面、…

作者头像 李华
网站建设 2026/6/10 1:21:19

NH2-PEG2k-RVG29,NH2-PEG2000-RVG29,氨基-聚乙二醇-RVG29,Amine-PEG2k-RVG29

NH2-PEG2k-RVG29&#xff0c;NH2-PEG2000-RVG29&#xff0c;氨基-聚乙二醇-RVG29&#xff0c;Amine-PEG2k-RVG29 NH₂-PEG2k-RVG29 是一种以聚乙二醇&#xff08;PEG&#xff09;为连接骨架、RVG29 多肽为靶向配体、末端带有氨基功能基团的功能化生物高分子复合分子。该分子通…

作者头像 李华
网站建设 2026/6/10 11:01:48

实测fft npainting lama对复杂背景的修复能力

实测FFT NPainting LaMa对复杂背景的修复能力 在图像编辑领域&#xff0c;移除图片中的干扰元素——无论是水印、路人、电线还是多余物体——始终是高频需求。但真正考验算法实力的&#xff0c;从来不是干净背景下的简单擦除&#xff0c;而是复杂纹理、多层结构、高对比边缘与…

作者头像 李华
网站建设 2026/6/9 21:02:00

识别结果能复制吗?手把手教你导出Paraformer文本

识别结果能复制吗&#xff1f;手把手教你导出Paraformer文本 你刚用Speech Seaco Paraformer ASR模型识别完一段会议录音&#xff0c;屏幕上跳出一行清晰的中文&#xff1a;“今天我们重点讨论大模型在客服场景的落地路径……”——可下一秒你就愣住了&#xff1a;这行字怎么保…

作者头像 李华