Skip to content

隔离分割对象

在执行分割任务后,有时需要从推理结果中提取孤立的对象。本指南提供了一个通用方法,介绍如何使用Ultralytics的预测模式来实现这一目标。

示例隔离对象分割

逐步指南

  1. 查看Ultralytics快速入门安装部分,了解快速安装所需库的步骤。


  2. 加载模型并在源上运行predict()方法。

    from ultralytics import YOLO
    
    # 加载模型
    model = YOLO("yolo11n-seg.pt")
    
    # 运行推理
    results = model.predict()
    

    没有预测参数?

    如果没有指定源,将使用库中的示例图像:

    'ultralytics/assets/bus.jpg'
    'ultralytics/assets/zidane.jpg'
    

    这对于使用predict()方法进行快速测试很有帮助。

    有关分割模型的更多信息,请访问分割任务页面。要了解更多关于predict()方法的信息,请参阅文档中的预测模式部分。


  3. 现在遍历结果和轮廓。对于希望将图像保存到文件的工作流程,检索源图像的base-name和检测的class-label以供后续使用(可选)。

    from pathlib import Path
    
    import numpy as np
    
    # (2) 遍历检测结果(有助于处理多张图像)
    for r in res:
        img = np.copy(r.orig_img)
        img_name = Path(r.path).stem  # 源图像的base-name
    
        # 遍历每个对象轮廓(多个检测)
        for ci, c in enumerate(r):
            # (1) 获取检测类名
            label = c.names[c.boxes.cls.tolist().pop()]
    
    1. 要了解更多关于处理检测结果的信息,请参阅预测模式的Boxes部分
    2. 要了解更多关于predict()结果的信息,请参阅预测模式的处理结果
    For-Loop

    单张图像只会遍历第一个循环一次。单张图像且只有一个检测时,每个循环只会遍历一次。


  4. 从源图像生成二进制掩码,然后在掩码上绘制填充的轮廓。这将允许从图像的其他部分中隔离对象。右侧显示了bus.jpg中检测到的person类对象之一的示例。

    二进制掩码图像

    import cv2
    
    # 创建二进制掩码
    b_mask = np.zeros(img.shape[:2], np.uint8)
    
    # (1) 提取轮廓结果
    contour = c.masks.xy.pop()
    # (2) 更改类型
    contour = contour.astype(np.int32)
    # (3) 重塑形状
    contour = contour.reshape(-1, 1, 2)
    
    
    # 在掩码上绘制轮廓
    _ = cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)
    
    1. 有关c.masks.xy的更多信息,请参阅预测模式的Masks部分

    2. 这里将值转换为np.int32,以与OpenCVdrawContours()函数兼容。

    3. OpenCV的drawContours()函数期望轮廓具有[N, 1, 2]的形状,展开下面的部分以获取更多详细信息。

    展开以理解定义contour变量时发生的情况。

    • c.masks.xy :: 提供掩码轮廓点的坐标,格式为(x, y)。更多详情请参阅预测模式的Masks部分

    • .pop() :: 由于masks.xy是一个包含单个元素的列表,使用pop()方法提取该元素。

    • .astype(np.int32) :: 使用masks.xy将返回float32数据类型,但这与OpenCV的drawContours()函数不兼容,因此将其数据类型更改为int32以实现兼容性。

    • .reshape(-1, 1, 2) :: 将数据重新格式化为所需的形状 [N, 1, 2],其中 N 是轮廓点的数量,每个点由一个条目 1 表示,该条目由 2 个值组成。-1 表示该维度上的值的数量是灵活的。

    展开以解释 drawContours() 配置。

    • 在测试中发现,将 contour 变量封装在方括号 [contour] 中,可以有效地生成所需的轮廓掩码。

    • drawContours() 参数指定的值 -1 指示函数绘制图像中存在的所有轮廓。

    • tuple (255, 255, 255) 表示白色,这是在二值掩码中绘制轮廓所需的颜色。

    • 添加 cv2.FILLED 将使轮廓边界内的所有像素着色为相同颜色,在这种情况下,所有封闭的像素都将为白色。

    • 有关更多信息,请参阅 OpenCV 文档中的 drawContours()


  5. 接下来,从这一点开始处理图像有两种选择,每种选择都有后续的子选项。

    对象隔离选项

    Example

    # 创建三通道掩码
    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    
    # 使用二值掩码隔离对象
    isolated = cv2.bitwise_and(mask3ch, img)
    
    这是如何工作的?
    • 首先,二值掩码从单通道图像转换为三通道图像。这种转换对于后续步骤是必要的,因为在该步骤中掩码和原始图像将被合并。两张图像必须具有相同数量的通道才能兼容混合操作。

    • 使用 OpenCV 函数 bitwise_and() 将原始图像和三通道二值掩码合并。此操作仅保留两张图像中大于零 (> 0) 的像素值。由于掩码像素仅在轮廓区域内大于零 (> 0),因此从原始图像中保留的像素是与轮廓重叠的像素。

    使用黑色像素隔离:子选项

    全尺寸图像

    如果保持全尺寸图像,则不需要额外的步骤。

    示例全尺寸隔离对象图像黑色背景
    示例全尺寸输出

    裁剪对象图像

    需要额外的步骤来裁剪图像,仅包括对象区域。

    示例裁剪隔离对象图像黑色背景

    # (1) 边界框坐标
    x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
    # 裁剪图像到对象区域
    iso_crop = isolated[y1:y2, x1:x2]
    

    1. 有关 边界框 结果的更多信息,请参阅 预测模式中的 Boxes 部分
    这段代码做了什么?
    • c.boxes.xyxy.cpu().numpy() 调用以 xyxy 格式检索边界框作为 NumPy 数组,其中 xminyminxmaxymax 表示边界框矩形的坐标。有关更多详细信息,请参阅 预测模式中的 Boxes 部分

    • squeeze() 操作从 NumPy 数组中移除任何不必要的维度,确保其具有预期的形状。

    • 使用 .astype(np.int32) 转换坐标值将框坐标数据类型从 float32 更改为 int32,使其兼容使用索引切片进行图像裁剪。

    • 最后,使用索引切片从图像中裁剪边界框区域。边界由检测边界框的 [ymin:ymax, xmin:xmax] 坐标定义。

    # 使用透明背景隔离对象(保存为 PNG 时)
    isolated = np.dstack([img, b_mask])
    
    这是如何工作的?
    • 使用NumPy的dstack()函数(沿深度轴进行数组堆叠)与生成的二进制掩码结合,将创建一个具有四个通道的图像。这使得在保存为PNG文件时,对象轮廓外的所有像素都可以透明。
      ### 带有透明像素的隔离:子选项
      
      ??? info "全尺寸图像"
      
          如果保持全尺寸图像,则不需要额外的步骤。
      
          <figure markdown>
              ![无背景的全尺寸隔离对象示例图像](https://github.com/ultralytics/docs/releases/download/0/example-full-size-isolated-object-image-no-background.avif){ width=240 }
              <figcaption>示例全尺寸输出 + 透明背景</figcaption>
          </figure>
      
      ??? info "裁剪对象图像"
      
          需要额外的步骤来裁剪图像,仅包含对象区域。
      
          ![无背景的裁剪隔离对象示例图像](https://github.com/ultralytics/docs/releases/download/0/example-crop-isolated-object-image-no-background.avif){ align="right" }
          ```{ .py .annotate }
          # (1) 边界框坐标
          x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
          # 裁剪图像至对象区域
          iso_crop = isolated[y1:y2, x1:x2]
          ```
      
          1.  有关边界框结果的更多信息,请参见[预测模式中的边界框部分](../modes/predict.md/#boxes)
      
          ??? question "这段代码是做什么的?"
      
              - 使用`c.boxes.xyxy.cpu().numpy()`时,边界框以NumPy数组的形式返回,使用`xyxy`边界框坐标格式,对应于边界框(矩形)的点`xmin, ymin, xmax, ymax`,更多信息请参见[预测模式中的边界框部分](../modes/predict.md/#boxes)。
      
              - 添加`squeeze()`确保从NumPy数组中移除任何多余的维度。
      
              - 使用`.astype(np.int32)`转换坐标值将边界框坐标数据类型从`float32`更改为`int32`,这在使用索引切片裁剪图像时将兼容。
      
              - 最后,使用索引切片裁剪边界框的图像区域,其中边界使用检测边界框的`[ymin:ymax, xmin:xmax]`坐标设置。
      
    如果我想裁剪的对象包括背景怎么办?

    这是Ultralytics库的内置功能。有关详细信息,请参见预测模式推理参数中的save_crop参数。


  6. 接下来做什么完全取决于你作为开发者。 这里展示了一个可能的下一步的基本示例(将图像保存到文件以供将来使用)。

    • 注意: 此步骤是可选的,如果不需要,可以跳过。
    示例最终步骤
    # 将隔离的对象保存到文件
    _ = cv2.imwrite(f"{img_name}_{label}-{ci}.png", iso_crop)
    
    • 在此示例中,img_name是源图像文件的基本名称,label是检测到的类别名称,ci对象检测的索引(以防同一类别名称有多个实例)。

完整示例代码

在这里,将前一节中的所有步骤组合成一个代码块。为了重复使用,最好定义一个函数来执行for循环中包含的部分或全部命令,但这留给读者作为练习。

from pathlib import Path

import cv2
import numpy as np

from ultralytics import YOLO

m = YOLO("yolo11n-seg.pt")  # (4)!
res = m.predict()  # (3)!

# 迭代检测结果 (5)
for r in res:
    img = np.copy(r.orig_img)
    img_name = Path(r.path).stem

    # 迭代每个对象轮廓 (6)
    for ci, c in enumerate(r):
        label = c.names[c.boxes.cls.tolist().pop()]

        b_mask = np.zeros(img.shape[:2], np.uint8)

        # 创建轮廓掩码 (1)
        contour = c.masks.xy.pop().astype(np.int32).reshape(-1, 1, 2)
        _ = cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)

        # 选择其一:

        # 选项-1: 隔离对象,黑色背景
        mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
        isolated = cv2.bitwise_and(mask3ch, img)

        # 选项-2: 隔离对象,透明背景(保存为PNG时)
        isolated = np.dstack([img, b_mask])

        # 可选: 检测裁剪(从选项1或选项2)
        x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
        iso_crop = isolated[y1:y2, x1:x2]

        # TODO 你的操作在这里 (2)
1. 这里将填充 contour 的代码行合并为一行,而在上面它被拆分为多行。 2. 这里的内容由你决定! 3. 有关更多信息,请参阅 预测模式。 4. 有关更多信息,请参阅 分割任务。 5. 了解更多关于 处理结果 6. 了解更多关于 分割掩码结果

常见问题

如何使用 Ultralytics YOLO11 进行分割任务中的对象隔离?

要使用 Ultralytics YOLO11 隔离对象,请按照以下步骤操作:

  1. 加载模型并运行推理:

    from ultralytics import YOLO
    
    model = YOLO("yolo11n-seg.pt")
    results = model.predict(source="path/to/your/image.jpg")
    
  2. 生成二进制掩码并绘制轮廓:

    import cv2
    import numpy as np
    
    img = np.copy(results[0].orig_img)
    b_mask = np.zeros(img.shape[:2], np.uint8)
    contour = results[0].masks.xy[0].astype(np.int32).reshape(-1, 1, 2)
    cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)
    
  3. 使用二进制掩码隔离对象:

    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    isolated = cv2.bitwise_and(mask3ch, img)
    

有关更多信息,请参阅 预测模式分割任务 的指南。

分割后保存隔离对象的选项有哪些?

Ultralytics YOLO11 提供了两种主要选项来保存隔离对象:

  1. 带黑色背景:

    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    isolated = cv2.bitwise_and(mask3ch, img)
    
  2. 带透明背景:

    isolated = np.dstack([img, b_mask])
    

有关更多详细信息,请访问 预测模式 部分。

如何使用 Ultralytics YOLO11 将隔离对象裁剪到其边界框?

要将隔离对象裁剪到其边界框:

  1. 获取边界框坐标:

    x1, y1, x2, y2 = results[0].boxes.xyxy[0].cpu().numpy().astype(np.int32)
    
  2. 裁剪隔离图像:

    iso_crop = isolated[y1:y2, x1:x2]
    

有关边界框结果的更多信息,请参阅 预测模式 文档。

为什么我应该使用 Ultralytics YOLO11 进行分割任务中的对象隔离?

Ultralytics YOLO11 提供:

  • 高速 实时对象检测和分割。
  • 准确的边界框和掩码生成 以实现精确的对象隔离。
  • 全面的文档 和易于使用的 API 以提高开发效率。

探索使用 YOLO 的好处,请参阅 分割任务文档

我可以使用 Ultralytics YOLO11 保存包括背景的隔离对象吗?

是的,这是 Ultralytics YOLO11 的内置功能。在 predict() 方法中使用 save_crop 参数。例如:

results = model.predict(source="path/to/your/image.jpg", save_crop=True)

有关 save_crop 参数的更多信息,请参阅 预测模式推理参数 部分。


📅 Created 10 months ago ✏️ Updated 11 days ago

Comments