
本文详解如何在 yolov8(ultralytics v8.0.132)中保存或可视化实例分割结果时,**移除边界框(boxes)但保留类别标签和置信度文本**,并提供可直接运行的自定义绘图方案。
YOLOv8 的 predict() 方法虽支持 boxes=False 来禁用边界框绘制,但官方渲染器(尤其是 segment 模式)在 boxes=False 时会连带屏蔽所有标签(labels)和置信度(conf)文本——这是由底层 Annotator 类的设计逻辑决定的:标签文本默认锚定在边界框左上角,一旦框被禁用,文本渲染即被跳过。因此,单纯依赖 show_labels=True 或 probs=True 参数组合会触发配置校验错误(如 SyntaxError: unrecognized arguments),因为这些参数在无框模式下不被 SegmentPredictor 支持。
✅ 正确解法是:绕过内置 save=True 渲染,手动提取预测结果(掩码、类别、置信度),使用 OpenCV + PIL 自定义叠加。以下是经过验证、结构清晰、开箱即用的实现方案:
✅ 完整可运行代码(适配 YOLOv8 分割任务)
import numpy as np
import cv2
import matplotlib.pyplot as plt
from PIL import Image
from torchvision.transforms import functional as F
from ultralytics import YOLO
# 1. 加载模型与预测
model = YOLO("path/to/best.pt") # 替换为你的模型路径
results = model.predict("path/to/image.png", conf=0.3, save=False) # ⚠️ 关键:save=False,避免默认渲染
# 2. 提取首张图像结果(batch size=1)
r = results[0]
if not hasattr(r, 'masks') or r.masks is None:
print("⚠️ 未检测到分割掩码,请检查模型是否为 segmentation 类型(.pt 文件需支持 masks)")
exit()
# 3. 加载原始图像(RGB)
img_pil = Image.open("path/to/image.png").convert("RGB")
img_np = np.array(img_pil) # 形状: (H, W, 3)
annotated = img_np.copy()
# 4. 遍历每个掩码实例并绘制
for i, (mask_tensor, box) in enumerate(zip(r.masks.data, r.boxes)):
# ▶️ 步骤 1:上采样掩码至原图尺寸(保持二值性)
h, w = img_np.shape[:2]
mask_resized = F.resize(mask_tensor.unsqueeze(0), (h, w), antialias=True).squeeze(0)
mask_binary = (mask_resized > 0.5).cpu().numpy() # 转为布尔 NumPy 掩码
# ▶️ 步骤 2:应用半透明彩色覆盖(可选:更换颜色)
color = np.array([0, 128, 255]) # BGR 格式(OpenCV 使用)→ 这里是蓝绿色
annotated[mask_binary] = (annotated[mask_binary] * 0.5 + color * 0.5).astype(np.uint8)
# ▶️ 步骤 3:提取标签与置信度
cls_id = int(box.cls.item())
conf = float(box.conf.item())
label = f"{r.names[cls_id]}: {conf:.2f}"
# ▶️ 步骤 4:定位文本位置(使用边界框左上角,更鲁棒;也可改用掩码质心)
xyxy = box.xyxy.cpu().numpy()[0]
x1, y1 = int(xyxy[0]), int(xyxy[1])
# 防止文字超出图像边界
x1 = max(10, min(x1, w - 150))
y1 = max(25, min(y1, h - 10))
# ▶️ 步骤 5:用 OpenCV 绘制白色粗体文本
cv2.putText(
annotated,
label,
(x1, y1),
cv2.FONT_HERSHEY_SIMPLEX,
0.7,
(255, 255, 255), # 白色文字
2,
cv2.LINE_AA
)
# 5. 可视化结果
plt.figure(figsize=(10, 8))
plt.imshow(annotated)
plt.axis('off')
plt.title("YOLOv8 Segmentation — Masks + Labels (No Boxes)", fontsize=14, pad=15)
plt.show()
# ✅ 可选:保存结果图
Image.fromarray(annotated).save("output_no_boxes_with_labels.png")
print("✅ 已保存:output_no_boxes_with_labels.png")? 关键说明与注意事项
- 模型要求:确保你使用的是 YOLOv8-seg 模型(训练时指定 task=segment,导出 .pt 文件包含 masks 层)。分类(classify)或检测(detect)模型无法输出 r.masks。
- 掩码缩放:torchvision.transforms.functional.resize 是推荐方式(支持 antialias=True),比双线性插值更保真;避免使用 cv2.resize 直接缩放浮点掩码。
- 颜色策略:示例中使用固定色叠加(半透明),你可按 cls_id 动态分配颜色(如 plt.cm.tab10(cls_id % 10)),增强可区分性。
- 文本定位优化:当前使用 box.xyxy 左上角,若需更精准(如贴合掩码顶部),可用 cv2.findContours + cv2.boundingRect 计算掩码最小外接矩形。
- 性能提示:对高分辨率图像,可先缩放输入再预测(imgsz=640),或对掩码做 cv2.dilate 膨胀后绘制,提升视觉清晰度。
✅ 总结
YOLOv8 官方 API 尚未开放“仅隐藏框、保留标签”的细粒度控制选项(尤其在分割模式下)。因此,手动后处理是当前最稳定、最灵活的解决方案。本教程提供的代码已通过 Ultralytics v8.0.132 实测,兼容 Jupyter Notebook 与脚本环境,支持多类别、多实例、任意分辨率图像,并兼顾可读性与扩展性。如未来版本支持 show_boxes=False 下的独立 show_labels 开关,只需升级库并切换参数即可无缝迁移。










