Cô lập các đối tượng phân đoạn

Sau khi thực hiện Segment Task, đôi khi bạn muốn trích xuất các đối tượng đã được cô lập từ kết quả dự đoán. Hướng dẫn này cung cấp một quy trình tổng quát để thực hiện việc này bằng cách sử dụng Predict Mode của Ultralytics.



Watch: How to Remove Background and Isolate Objects with Ultralytics YOLO Segmentation & OpenCV in Python 🚀

Hướng dẫn các bước thực hiện

  1. Xem phần Ultralytics Quickstart Installation section để biết hướng dẫn nhanh về cách cài đặt các thư viện cần thiết.


  2. Tải model và chạy phương thức predict() trên một nguồn dữ liệu.

    from ultralytics import YOLO
    
    # Load a model
    model = YOLO("yolo26n-seg.pt")
    
    # Run inference
    results = model.predict()
Không có đối số dự đoán?

Nếu không chỉ định nguồn dữ liệu, các hình ảnh mẫu từ thư viện sẽ được sử dụng:

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

Điều này hữu ích cho việc thử nghiệm nhanh với phương thức predict().

Để biết thêm thông tin về các Segmentation Models, hãy truy cập trang Segment Task. Để tìm hiểu thêm về phương thức predict(), hãy xem phần Predict Mode trong Tài liệu.

***

Bây giờ hãy lặp qua các kết quả và các đường viền. Đối với các quy trình cần lưu hình ảnh vào tệp, base-name của hình ảnh nguồn và class-label của đối tượng phát hiện sẽ được truy xuất để sử dụng sau này (tùy chọn).

```{ .py .annotate }
from pathlib import Path

import numpy as np

# (2) Iterate detection results (helpful for multiple images)
for r in results:
    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. To learn more about working with detection results, see [Boxes Section for Predict Mode](../modes/predict.md#boxes).
2. To learn more about `predict()` results see [Working with Results for Predict Mode](../modes/predict.md#working-with-results)
Vòng lặp For

Một hình ảnh đơn lẻ sẽ chỉ lặp qua vòng lặp đầu tiên một lần. Một hình ảnh đơn lẻ chỉ với một phát hiện duy nhất sẽ lặp qua mỗi vòng lặp chỉ một lần.


  1. Bắt đầu bằng việc tạo mặt nạ nhị phân (binary mask) từ hình ảnh nguồn, sau đó vẽ một đường viền được tô đầy lên mặt nạ đó. Điều này cho phép đối tượng được cô lập khỏi các phần khác của hình ảnh. Một ví dụ từ bus.jpg cho một trong các đối tượng thuộc lớp person được phát hiện hiển thị ở bên phải.

    Binary Mask Image{ width="240", align="right" }

    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. Để biết thêm thông tin về c.masks.xy, hãy xem Masks Section from Predict Mode.

    2. Ở đây các giá trị được ép kiểu sang np.int32 để tương thích với hàm drawContours() từ OpenCV.

    3. Hàm OpenCV drawContours() yêu cầu các đường viền có hình dạng [N, 1, 2], hãy mở rộng phần bên dưới để biết thêm chi tiết.

    Expand to understand what is happening when defining the contour variable.

    - `c.masks.xy` :: Provides the coordinates of the mask contour points in the format `(x, y)`. For more details, refer to the [Masks Section from Predict Mode](../modes/predict.md#masks). - `.pop()` :: As `masks.xy` is a list containing a single element, this element is extracted using the `pop()` method. - `.astype(np.int32)` :: Using `masks.xy` will return with a data type of `float32`, but this won't be compatible with the OpenCV `drawContours()` function, so this will change the data type to `int32` for compatibility. - `.reshape(-1, 1, 2)` :: Reformats the data into the required shape of `[N, 1, 2]` where `N` is the number of contour points, with each point represented by a single entry `1`, and the entry is composed of `2` values. The `-1` denotes that the number of values along this dimension is flexible.

    Expand for an explanation of the drawContours() configuration.

    - Encapsulating the `contour` variable within square brackets, `[contour]`, was found to effectively generate the desired contour mask during testing. - The value `-1` specified for the `drawContours()` parameter instructs the function to draw all contours present in the image. - The `tuple` `(255, 255, 255)` represents the color white, which is the desired color for drawing the contour in this binary mask. - The addition of `cv2.FILLED` will color all pixels enclosed by the contour boundary the same, in this case, all enclosed pixels will be white. - See [OpenCV Documentation on `drawContours()`](https://docs.opencv.org/4.8.0/d6/d6e/group__imgproc__draw.html#ga746c0625f1781f1ffc9056259103edbc) for more information.


  2. Tiếp theo, có 2 tùy chọn về cách tiếp tục với hình ảnh từ điểm này và một tùy chọn bổ sung cho mỗi trường hợp.

    Các tùy chọn cô lập đối tượng

Ví dụ
# Create 3-channel mask
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)

# Isolate object with binary mask
isolated = cv2.bitwise_and(mask3ch, img)
Điều này hoạt động như thế nào?
  • Đầu tiên, binary mask được chuyển đổi từ hình ảnh đơn kênh sang hình ảnh ba kênh. Việc chuyển đổi này là cần thiết cho bước tiếp theo, nơi mask và hình ảnh gốc được kết hợp. Cả hai hình ảnh phải có cùng số lượng kênh để tương thích với thao tác hòa trộn.

  • Hình ảnh gốc và binary mask ba kênh được hợp nhất bằng hàm bitwise_and() của OpenCV. Thao tác này chỉ giữ lại các giá trị pixel lớn hơn không (> 0) từ cả hai hình ảnh. Vì các pixel mask lớn hơn không (> 0) chỉ nằm trong vùng đường viền, các pixel còn lại từ hình ảnh gốc chính là những pixel trùng lặp với đường viền.

Cô lập với các pixel đen: Các tùy chọn phụ

Hình ảnh kích thước đầy đủ

Không cần thêm các bước bổ sung nếu giữ nguyên kích thước đầy đủ của hình ảnh.

![Example Full size Isolated Object Image Black Background](https://cdn.jsdelivr.net/gh/ultralytics/assets@main/docs/full-size-isolated-object-black-background.avif){ width=240 }
Example full-size output
Hình ảnh đối tượng đã cắt

Cần thêm các bước để cắt hình ảnh chỉ bao gồm vùng đối tượng.

Example Crop Isolated Object Image Black Background{ align="right" }

# (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. Để biết thêm thông tin về kết quả bounding box, hãy xem Boxes Section from Predict Mode
Mã này làm gì?
  • Lệnh c.boxes.xyxy.cpu().numpy() truy xuất các bounding box dưới dạng một NumPy array ở định dạng xyxy, trong đó xmin, ymin, xmax, và ymax đại diện cho tọa độ của hình chữ nhật bao quanh. Xem Boxes Section from Predict Mode để biết thêm chi tiết.

  • Thao tác squeeze() loại bỏ bất kỳ chiều dư thừa nào từ NumPy array, đảm bảo nó có hình dạng như mong đợi.

  • Việc chuyển đổi các giá trị tọa độ bằng .astype(np.int32) thay đổi kiểu dữ liệu của tọa độ box từ float32 sang int32, làm cho chúng tương thích để cắt hình ảnh bằng cách sử dụng lát cắt chỉ mục (index slices).

  • Cuối cùng, vùng bounding box được cắt từ hình ảnh bằng cách sử dụng lát cắt chỉ mục. Các biên được xác định bởi tọa độ [ymin:ymax, xmin:xmax] của bounding box phát hiện.

Nếu tôi muốn đối tượng đã cắt **bao gồm cả** nền thì sao?

Đây là một tính năng tích hợp sẵn của thư viện Ultralytics. Xem đối số save_crop cho Predict Mode Inference Arguments để biết chi tiết.


  1. Việc cần làm tiếp theo hoàn toàn phụ thuộc vào bạn với tư cách là lập trình viên. Một ví dụ cơ bản về một bước tiếp theo khả thi (lưu hình ảnh vào tệp để sử dụng trong tương lai) được hiển thị.
    • LƯU Ý: bước này là tùy chọn và có thể bỏ qua nếu không cần thiết cho trường hợp sử dụng cụ thể của bạn.
Ví dụ về bước cuối cùng
# Save isolated object to file
_ = cv2.imwrite(f"{img_name}_{label}-{ci}.png", iso_crop)
  • Trong ví dụ này, img_name là tên cơ sở của tệp hình ảnh nguồn, label là tên lớp được phát hiện, và ci là chỉ số của object detection (trong trường hợp có nhiều thực thể cùng tên lớp).

Mã ví dụ đầy đủ

Ở đây, tất cả các bước từ phần trước được kết hợp thành một khối mã duy nhất. Để sử dụng lặp lại, sẽ là tối ưu nếu định nghĩa một hàm để thực hiện một số hoặc tất cả các lệnh chứa trong các vòng lặp for, nhưng đó là bài tập dành cho người đọc.

from pathlib import Path

import cv2
import numpy as np

from ultralytics import YOLO

m = YOLO("yolo26n-seg.pt")  # (4)!
res = m.predict(source="path/to/image.jpg")  # (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]

        # Add your custom post-processing here (2)
  1. Dòng điền vào contour được kết hợp thành một dòng duy nhất tại đây, trong khi nó đã được chia thành nhiều dòng ở trên.
  2. {==Những gì ở đây là tùy thuộc vào bạn!==}
  3. Xem Predict Mode để biết thêm thông tin.
  4. Xem Segment Task để biết thêm thông tin.
  5. Tìm hiểu thêm về Working with Results
  6. Tìm hiểu thêm về Segmentation Mask Results

Câu hỏi thường gặp (FAQ)

Làm thế nào để tôi cô lập các đối tượng bằng Ultralytics YOLO26 cho các tác vụ phân đoạn?

Để cô lập các đối tượng bằng Ultralytics YOLO26, hãy làm theo các bước sau:

  1. Tải model và chạy suy luận:

    from ultralytics import YOLO
    
    model = YOLO("yolo26n-seg.pt")
    results = model.predict(source="path/to/your/image.jpg")
  2. Tạo binary mask và vẽ các đường viền:

    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. Cô lập đối tượng bằng binary mask:

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

Tham khảo hướng dẫn về Predict ModeSegment Task để biết thêm thông tin.

Có những tùy chọn nào để lưu các đối tượng đã cô lập sau khi phân đoạn?

Ultralytics YOLO26 cung cấp hai tùy chọn chính để lưu các đối tượng đã cô lập:

  1. Với nền đen:

    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    isolated = cv2.bitwise_and(mask3ch, img)
  2. Với nền trong suốt:

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

Để biết thêm chi tiết, hãy truy cập phần Predict Mode.

Làm thế nào tôi có thể cắt các đối tượng đã cô lập theo bounding box của chúng bằng Ultralytics YOLO26?

Để cắt các đối tượng đã cô lập theo bounding box:

  1. Truy xuất tọa độ bounding box:

    x1, y1, x2, y2 = results[0].boxes.xyxy[0].cpu().numpy().astype(np.int32)
  2. Cắt hình ảnh đã cô lập:

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

Tìm hiểu thêm về kết quả bounding box trong tài liệu Predict Mode.

Tại sao tôi nên sử dụng Ultralytics YOLO26 cho việc cô lập đối tượng trong các tác vụ phân đoạn?

Ultralytics YOLO26 cung cấp:

  • Tốc độ cao trong việc phát hiện và phân đoạn đối tượng theo thời gian thực.
  • Tạo bounding box và mask chính xác cho việc cô lập đối tượng một cách chuẩn xác.
  • Tài liệu toàn diện và API dễ sử dụng cho việc phát triển hiệu quả.

Khám phá các lợi ích khi sử dụng YOLO trong Segment Task documentation.

Tôi có thể lưu các đối tượng đã cô lập bao gồm cả nền bằng Ultralytics YOLO26 không?

Có, đây là một tính năng tích hợp sẵn trong Ultralytics YOLO26. Sử dụng đối số save_crop trong phương thức predict(). Ví dụ:

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

Đọc thêm về đối số save_crop trong phần Predict Mode Inference Arguments.

Bình luận