跳转至内容

分离分割对象

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

隔离对象分割示例

配方演练

  1. 请参阅Ultralytics 快速入门安装部分,以快速了解如何安装所需的库。


  2. 加载模型并运行 predict() source 上的 method。

    from ultralytics import YOLO
    
    # Load a model
    model = YOLO("yolo11n-seg.pt")
    
    # Run inference
    results = model.predict()
    

    没有预测参数?

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

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

    这有助于使用 predict() 方法。

    有关分割模型的更多信息,请访问 分割任务 页面。要了解更多关于 predict() method,请参阅 Predict 模式 文档的章节。


  3. 现在,迭代处理结果和轮廓。对于希望将图像保存到文件的workflow,可以使用源图像 base-name 以及检测 class-label 被检索以供后续使用(可选)。

    from pathlib import Path
    
    import numpy as np
    
    # (2) Iterate detection results (helpful for multiple images)
    for r in res:
        img = np.copy(r.orig_img)
        img_name = Path(r.path).stem  # source image base-name
    
        # Iterate each object contour (multiple detections)
        for ci, c in enumerate(r):
            # (1) Get detection class name
            label = c.names[c.boxes.cls.tolist().pop()]
    
    1. 要了解更多关于如何使用检测结果的信息,请参阅预测模式的框选部分
    2. 要了解更多关于 predict() 结果请参见 处理预测模式的结果
    For-Loop(循环)

    单个图像只会迭代第一个循环一次。仅具有单个检测的单个图像将迭代每个循环一次。


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

    二元掩码图像

    import cv2
    
    # Create binary mask
    b_mask = np.zeros(img.shape[:2], np.uint8)
    
    # (1) Extract contour result
    contour = c.masks.xy.pop()
    # (2) Changing the type
    contour = contour.astype(np.int32)
    # (3) Reshaping
    contour = contour.reshape(-1, 1, 2)
    
    
    # Draw contour onto mask
    _ = cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)
    
    1. 有关更多信息 c.masks.xy 参见 预测模式中的掩码部分.

    2. 此处,这些值被转换为 np.int32 为了兼容 drawContours() function,来自 OpenCV.

    3. OpenCV drawContours() function 期望轮廓的形状为 [N, 1, 2] 下方展开部分的更多详细信息。

    展开以了解定义 contour 变量中。

    - c.masks.xy ::以格式提供掩码轮廓点的坐标 (x, y)。更多详情,请参考 预测模式中的掩码部分。 - .pop() ::作为 masks.xy 是一个包含单个元素的列表,该元素使用以下方式提取 pop() 方法。 - .astype(np.int32) ::使用 masks.xy 将返回数据类型 float32,但这将与 OpenCV 不兼容 drawContours() function,因此这将更改数据类型为 int32 为了兼容性。 - .reshape(-1, 1, 2) ::将数据重新格式化为所需的形状 [N, 1, 2] 其中 N 是轮廓点的数量,每个点由一个条目表示 1,条目由以下部分组成 2 值。这个 -1 表示此维度上的值的数量是灵活的。

    展开以查看关于 drawContours() 配置。

    - 封装 contour 方括号内的变量, [contour],发现在测试过程中能有效地生成所需的轮廓掩码。 - 该值 -1 为以下对象指定 drawContours() 参数指示函数绘制图像中存在的所有轮廓。 - tuple (255, 255, 255) 表示白色,这是在此二元掩码中绘制轮廓所需的颜色。 - 添加了 cv2.FILLED 将以相同的颜色填充轮廓边界内的所有像素,在本例中,所有封闭的像素都将是白色。 - 参见 关于 OpenCV 的文档 drawContours() 更多信息。


  5. 接下来,对于从此时开始如何处理图像,以及每个图像的后续选项,有 2 个选项。

    目标隔离选项

    示例

    # Create 3-channel mask
    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    
    # Isolate object with binary mask
    isolated = cv2.bitwise_and(mask3ch, img)
    
    这是如何运作的?
    • 首先,二值掩码会从单通道图像转换为三通道图像。此转换对于后续将掩码与原始图像组合的步骤是必需的。两个图像必须具有相同的通道数,才能与混合操作兼容。

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

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

    全尺寸图像

    如果保持全尺寸图像,则无需其他步骤。

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

    裁剪后的对象图像

    需要执行其他步骤才能裁剪图像以仅包含对象区域。

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

    # (1) Bounding box coordinates
    x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
    # Crop image to object region
    iso_crop = isolated[y1:y2, x1:x2]
    

    1. 有关边界框结果的更多信息,请参见预测模式中的框选部分
    这段代码是做什么的?
    • 字段 c.boxes.xyxy.cpu().numpy() 调用以 NumPy 数组的形式检索边界框,位于 xyxy 格式,其中 xmin, ymin, xmaxymax 表示边界框矩形的坐标。 见 预测模式中的“框”部分 了解更多详情。

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

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

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

    # Isolate object with transparent background (when saved as PNG)
    isolated = np.dstack([img, b_mask])
    
    这是如何运作的?
    • 使用 NumPy dstack() 结合生成的二值掩码,使用 function(沿深度轴堆叠数组)将创建一个具有四个通道的图像。这允许在保存为以下格式时,对象轮廓外的所有像素都是透明的 PNG 文件。

    使用透明像素隔离:子选项

    全尺寸图像

    如果保持全尺寸图像,则无需其他步骤。

    全尺寸隔离对象图像无背景示例
    全尺寸输出 + 透明背景示例

    裁剪后的对象图像

    需要执行其他步骤才能裁剪图像以仅包含对象区域。

    示例:裁剪隔离对象图像(无背景)

    # (1) Bounding box coordinates
    x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
    # Crop image to object region
    iso_crop = isolated[y1:y2, x1:x2]
    

    1. 有关边界框结果的更多信息,请参见预测模式中的框选部分
    这段代码是做什么的?
    • 当使用时 c.boxes.xyxy.cpu().numpy(),边界框将作为 NumPy 数组返回,使用 xyxy 框坐标格式,对应于点 xmin, ymin, xmax, ymax 有关边界框(矩形),请参见 预测模式中的“框”部分 更多信息。

    • 添加 squeeze() 确保从 NumPy 数组中删除任何多余的维度。

    • 使用以下方法转换坐标值 .astype(np.int32) 将框坐标数据类型从以下类型更改为 float32int32 这将在使用索引切片裁剪图像时兼容。

    • 最后,使用索引切片裁剪边界框的图像区域,其中边界使用以下方式设置 [ymin:ymax, xmin:xmax] 检测边界框的坐标。

    如果我想要裁剪后的对象包括背景,该怎么办?

    这是 Ultralytics 库的内置功能。请参阅 save_crop 参数用于 Predict 模式推理参数 详情请见。


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

    • 注意: 此步骤是可选的,如果您的特定用例不需要,则可以跳过。
    最终步骤示例
    # Save isolated object to file
    _ = 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)!

# Iterate detection results (5)
for r in res:
    img = np.copy(r.orig_img)
    img_name = Path(r.path).stem

    # Iterate each object contour (6)
    for ci, c in enumerate(r):
        label = c.names[c.boxes.cls.tolist().pop()]

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

        # Create contour mask (1)
        contour = c.masks.xy.pop().astype(np.int32).reshape(-1, 1, 2)
        _ = cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)

        # Choose one:

        # OPTION-1: Isolate object with black background
        mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
        isolated = cv2.bitwise_and(mask3ch, img)

        # OPTION-2: Isolate object with transparent background (when saved as PNG)
        isolated = np.dstack([img, b_mask])

        # OPTIONAL: detection crop (from either OPT1 or OPT2)
        x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
        iso_crop = isolated[y1:y2, x1:x2]

        # TODO your actions go here (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 中的一个内置功能。使用 save_crop 中的参数 predict() method。例如:

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

阅读更多关于 save_crop 中的参数 Predict 模式推理参数 部分。



📅 创建于 1 年前 ✏️ 更新于 2 个月前

评论