Chuyển đến nội dung

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

Sau khi thực hiện Tác vụ Phân đoạn, đôi khi bạn muốn trích xuất các đối tượng riêng biệt từ kết quả suy luận. Hướng dẫn này cung cấp một công thức chung về cách thực hiện việc này bằng cách sử dụng Chế độ Dự đoán của Ultralytics.

Ví dụ: Phân Đoạn Đối Tượng Cô Lập

Hướng dẫn từng bước theo công thức

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


  2. Tải một mô hình và chạy predict() phương pháp trên một nguồn.

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

    Không có đối số dự đoán?

    Nếu không chỉ định nguồn, ảnh ví dụ 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 kiểm tra nhanh chóng với predict() phương thức.

    Để biết thêm thông tin về Mô hình Phân đoạn, hãy truy cập Tác vụ phân đoạn trang. Để tìm hiểu thêm về predict() phương thức, xem Chế độ Dự đoán phần của Tài liệu.


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

    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. Để tìm hiểu thêm về cách làm việc với kết quả phát hiện, hãy xem Phần Hộp cho Chế độ Dự đoán.
    2. Để tìm hiểu thêm về predict() kết quả xem Làm việc với Kết quả cho Chế độ Dự đoán
    Vòng lặp For

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


  4. Bắt đầu bằng cách tạo mặt nạ nhị phân từ ảnh gốc, sau đó vẽ một đường viền được tô lên mặt nạ. Điều này sẽ 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 được phát hiện person các đối tượng lớp được hiển thị ở bên phải.

    Ảnh Mặt nạ Nhị phân

    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 xem Phần Mặt Nạ từ Chế Độ Dự Đoán.

    2. Ở đây, các giá trị được chuyển đổi thành np.int32 để tương thích với drawContours() function từ OpenCV.

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

    Mở rộng để hiểu điều gì đang xảy ra khi xác định contour biến.

    - c.masks.xy :: Cung cấp tọa độ của các điểm đường viền mặt nạ theo định dạng (x, y). Để biết thêm chi tiết, hãy tham khảo Phần Mặt Nạ từ Chế Độ Dự Đoán. - .pop() :: Như masks.xy là một danh sách chứa một phần tử duy nhất, phần tử này được trích xuất bằng cách sử dụng pop() phương pháp. - .astype(np.int32) :: Sử dụng masks.xy sẽ trả về với kiểu dữ liệu là float32, nhưng điều này sẽ không tương thích với OpenCV drawContours() function, vì vậy điều này sẽ thay đổi kiểu dữ liệu thành int32 để tương thích. - .reshape(-1, 1, 2) :: Định dạng lại dữ liệu thành hình dạng cần thiết của [N, 1, 2] trong đó N là số lượng điểm đường viền, với mỗi điểm được biểu diễn bằng một mục duy nhất 1, và mục nhập bao gồm 2 giá trị. Các -1 biểu thị số lượng giá trị dọc theo chiều này là linh hoạt.

    Mở rộng để xem giải thích về drawContours() cấu hình.

    - Đóng gói contour biến trong dấu ngoặc vuông, [contour]- Được chứng minh là tạo ra mặt nạ đường viền mong muốn hiệu quả trong quá trình kiểm thử. - Giá trị -1 được chỉ định cho drawContours() tham số hướng dẫn hàm vẽ tất cả các đường viền hiện diện trong hình ảnh. - Cái tuple (255, 255, 255) đại diện cho màu trắng, là màu mong muốn để vẽ đường viền trong mặt nạ nhị phân này. - Việc bổ sung cv2.FILLED sẽ tô màu tất cả các pixel nằm trong biên giới đường viền, trong trường hợp này, tất cả các pixel nằm trong sẽ có màu trắng. - Xem Tài liệu OpenCV về drawContours() để biết thêm thông tin.


  5. Tiếp theo, có 2 tùy chọn về cách tiến hành với hình ảnh từ thời điểm này và một tùy chọn tiếp theo cho mỗi tùy chọn.

    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, mặt nạ nhị phân được chuyển đổi từ ảnh một kênh thà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 mặt nạ và ảnh gốc được kết hợp. Cả hai ảnh phải có cùng số lượng kênh để tương thích với thao tác trộn.

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

    Cô lập bằng Pixel đen: Các tùy chọn phụ

    Ảnh kích thước đầy đủ

    Không cần thêm bước nào nếu giữ nguyên kích thước ảnh đầy đủ.

    Ví dụ: Ảnh Đối Tượng Cô Lập Kích Thước Đầy Đủ Nền Đen
    Ví dụ: Đầu ra kích thước đầy đủ

    Ảnh đối tượng đã cắt

    Các bước bổ sung cần thiết để cắt ảnh chỉ bao gồm vùng đối tượng.

    Ví dụ: Ảnh Cắt Đối Tượng Cô Lập Nền Đen

    # (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ả khung giới hạn, hãy xem Phần Khung từ Chế độ Dự đoán
    Đoạn mã này làm gì?
    • Hàm c.boxes.xyxy.cpu().numpy() gọi truy xuất các hộp giới hạn dưới dạng một mảng NumPy trong xyxy định dạng, trong đó xmin, ymin, xmax, và ymax biểu thị tọa độ của hình chữ nhật bao quanh. Xem Phần Boxes từ Chế độ Dự đoán để biết thêm chi tiết.

    • Hàm squeeze() operation loại bỏ mọi chiều không cần thiết khỏi mảng NumPy, đảm bảo nó có hình dạng như mong đợi.

    • Chuyển đổi các giá trị tọa độ bằng cách sử dụng .astype(np.int32) thay đổi kiểu dữ liệu tọa độ hộp từ float32 đến int32, giúp chúng tương thích để cắt ảnh bằng cách sử dụng các lát chỉ mục.

    • Cuối cùng, vùng bounding box được cắt từ ảnh bằng cách sử dụng index slicing. Các ranh giới được xác định bởi [ymin:ymax, xmin:xmax] tọa độ của hộp giới hạn phát hiện.

    # Isolate object with transparent background (when saved as PNG)
    isolated = np.dstack([img, b_mask])
    
    Điều này hoạt động như thế nào?
    • Sử dụng NumPy dstack() function (xếp chồng mảng dọc theo trục độ sâu) kết hợp với mặt nạ nhị phân được tạo ra, sẽ tạo ra một hình ảnh với bốn kênh. Điều này cho phép tất cả các pixel bên ngoài đường viền đối tượng trở nên trong suốt khi lưu dưới dạng PNG tập tin.

    Cô lập bằng Pixel trong suốt: Các tùy chọn phụ

    Ảnh kích thước đầy đủ

    Không cần thêm bước nào nếu giữ nguyên kích thước ảnh đầy đủ.

    Ví dụ: Ảnh Đối Tượng Cô Lập Kích Thước Đầy Đủ Không Nền
    Ví dụ: Đầu ra kích thước đầy đủ + nền trong suốt

    Ảnh đối tượng đã cắt

    Các bước bổ sung cần thiết để cắt ảnh chỉ bao gồm vùng đối tượng.

    Ví dụ: Ảnh Cắt Đối Tượng Cô Lập Không Nền

    # (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ả khung giới hạn, hãy xem Phần Khung từ Chế độ Dự đoán
    Đoạn mã này làm gì?
    • Khi sử dụng c.boxes.xyxy.cpu().numpy(), các hộp giới hạn được trả về dưới dạng một mảng NumPy, sử dụng xyxy định dạng tọa độ hộp, tương ứng với các điểm xmin, ymin, xmax, ymax cho hộp giới hạn (hình chữ nhật), xem Phần Boxes từ Chế độ Dự đoán để biết thêm thông tin.

    • Đang thêm squeeze() đảm bảo rằng mọi chiều ngoại lai được loại bỏ khỏi mảng NumPy.

    • Chuyển đổi các giá trị tọa độ bằng cách sử dụng .astype(np.int32) thay đổi kiểu dữ liệu tọa độ hộp từ float32 đến int32 sẽ tương thích khi cắt ảnh bằng cách sử dụng các lát chỉ mục.

    • Cuối cùng, vùng ảnh cho bounding box được cắt bằng cách sử dụng index slicing, trong đó các ranh giới được thiết lập bằng cách sử dụng [ymin:ymax, xmin:xmax] tọa độ của hộp giới hạn phát hiện.

    Điều gì xảy ra nếu tôi muốn đối tượng được cắt bao gồm cả nền?

    Đây là một tính năng được tích hợp sẵn cho thư viện Ultralytics. Xem save_crop đối số cho Các đối số suy luận của Chế độ Dự đoán để biết chi tiết.


  6. Bước tiếp theo hoàn toàn tùy thuộc vào bạn với tư cách là nhà phát triển. Một ví dụ cơ bản về một bước tiếp theo có thể (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ụ: 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 phát hiện đối tượng (trong trường hợp nhiều đối tượng 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ẽ tối ưu hơn 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 có trong for-loops, nhưng đó là một 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("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. Dòng điền dữ liệu contour được kết hợp thành một dòng duy nhất ở đây, trong khi trước đó được chia thành nhiều dòng.
  2. Những gì ở đây là tùy thuộc vào bạn!
  3. Xem Chế độ Dự đoán để biết thêm thông tin.
  4. Xem Tác vụ Phân đoạn để biết thêm thông tin.
  5. Tìm hiểu thêm về Làm việc với Kết quả
  6. Tìm hiểu thêm về Kết quả Mặt nạ Phân đoạn

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

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

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

  1. Tải mô hình và chạy suy luận:

    from ultralytics import YOLO
    
    model = YOLO("yolo11n-seg.pt")
    results = model.predict(source="path/to/your/image.jpg")
    
  2. Tạo mặt nạ nhị phân và vẽ đườ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 cách sử dụng mặt nạ nhị phân:

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

Tham khảo hướng dẫn về Chế Độ Dự ĐoánTác Vụ Phân Đoạn để biết thêm thông tin.

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

Ultralytics YOLO11 cung cấp hai tùy chọn chính để lưu các đối tượng bị 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 Chế Độ Dự Đoán.

Làm cách nào để cắt các đối tượng bị cô lập thành các hộp giới hạn của chúng bằng Ultralytics YOLO11?

Để cắt các đối tượng bị cô lập thành các hộp giới hạn của chúng:

  1. Truy xuất tọa độ hộp giới hạn:

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

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

Tìm hiểu thêm về kết quả hộp giới hạn trong tài liệu Chế độ Dự đoán.

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

Ultralytics YOLO11 cung cấp:

  • Tốc độ cao trong 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 để phân lập đối tượng một cách chuẩn xác.
  • Tài liệu đầy đủ và API dễ sử dụng để phát triển hiệu quả.

Khám phá những lợi ích của việc sử dụng YOLO trong tài liệu Nhiệm vụ phân đoạn.

Tôi có thể lưu các đối tượng riêng biệt bao gồm cả nền bằng Ultralytics YOLO11 không?

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

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

Đọc thêm về save_crop đối số trong Các đối số suy luận của Chế độ Dự đoán ở phần này.



📅 Đã tạo 1 năm trước ✏️ Cập nhật 2 tháng trước

Bình luận