Cách cô lập các đối tượng phân đoạn bằng Ultralytics YOLO#
Phân đoạn instance tạo ra một mask chính xác đến từng pixel cho mỗi đối tượng được phát hiện, nghĩa là bạn có thể tách riêng từng đối tượng khỏi ảnh. Hướng dẫn này chỉ cho bạn cách chuyển kết quả phân đoạn của Ultralytics YOLO thành các đối tượng đã được cô lập bằng Predict Mode và OpenCV, với nền đen đồng nhất hoặc nền trong suốt để lưu dưới dạng PNG.
Watch: How to Remove Background and Isolate Objects with Ultralytics YOLO Segmentation & OpenCV in Python 🚀
Tại sao nên cô lập các đối tượng phân đoạn?#
Việc tách từng đối tượng riêng lẻ khỏi ảnh mở ra nhiều quy trình xử lý tiếp theo:
- Loại bỏ nền cho ảnh sản phẩm, catalog hoặc chỉnh sửa sáng tạo.
- Cắt riêng từng đối tượng để xây dựng dataset phân loại từ các đối tượng được phát hiện.
- Xử lý tập trung để các bước tiếp theo như OCR, phân tích màu hoặc đo lường chỉ nhìn thấy đối tượng, không phải toàn bộ khung cảnh xung quanh.
- Xuất PNG trong suốt để ghép các đối tượng lên nền mới.
Công thức này hoạt động với mọi model phân đoạn Ultralytics YOLO và gồm bốn giai đoạn: chạy suy luận → trích xuất từng đường bao → cô lập đối tượng → lưu kết quả.
Chạy suy luận phân đoạn#
Cài đặt các thư viện cần thiết, sau đó tải một model phân đoạn (hậu tố -seg, cần thiết để tạo mask) và chạy dự đoán trên ảnh nguồn:
from ultralytics import YOLO
# Load a segmentation model
model = YOLO("yolo26n-seg.pt")
# Run inference on a source
results = model.predict(source="path/to/image.jpg")Nếu gọi model.predict() mà không cung cấp source, Ultralytics sẽ chuyển sang sử dụng các ảnh ví dụ được đóng gói cùng package (bus.jpg và zidane.jpg), rất tiện để nhanh chóng kiểm thử workflow.
Trích xuất đường bao đối tượng#
Mỗi phần tử trong results tương ứng với một ảnh, và việc lặp qua một kết quả sẽ trả về từng detection một. Với mỗi detection, hãy sao chép ảnh gốc, đọc nhãn class và vẽ đường bao mask của đối tượng lên một binary mask trống. Vùng màu trắng của mask này đánh dấu chính xác các pixel thuộc về đối tượng.
Các đoạn code trong phần này và phần tiếp theo chạy bên trong vòng lặp detection bên dưới; script hoàn chỉnh có thể sao chép và chạy được nằm trong Ví dụ đầy đủ.
from pathlib import Path
import cv2
import numpy as np
for r in results:
img = np.copy(r.orig_img)
img_name = Path(r.path).stem # source image base-name
# Iterate each detected object in the image
for ci, c in enumerate(r):
label = c.names[c.boxes.cls.tolist().pop()] # class name
# Build a binary mask and draw the object contour onto it
b_mask = np.zeros(img.shape[:2], np.uint8)
contour = c.masks.xy[0].astype(np.int32).reshape(-1, 1, 2)
cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)c.masks.xy[0]trả về đường bao mask dưới dạng tọa độ điểm(x, y)cho đối tượng trong kết quả chỉ có một detection này..astype(np.int32)chuyển đổi các điểm từfloat32, định dạng màdrawContours()của OpenCV không chấp nhận..reshape(-1, 1, 2)reshape các điểm thành bố cục[N, 1, 2]màdrawContours()mong đợi, trong đóNlà số điểm của đường bao.
Truyền [contour] cùng chỉ mục -1 sẽ vẽ tất cả các điểm của đường bao được cung cấp, còn cv2.FILLED sẽ tô màu trắng mọi pixel nằm bên trong đường bao.
Cô lập đối tượng#
Khi binary mask đã sẵn sàng, hãy kết hợp nó với ảnh gốc. Có hai kiểu phổ biến, tùy thuộc vào nền mà bạn muốn sử dụng:
Chuyển mask thành ba channel và chỉ giữ lại các pixel chồng lên đối tượng. Mọi phần bên ngoài đường bao sẽ chuyển thành màu đen:
# Isolate object with a black background
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
isolated = cv2.bitwise_and(mask3ch, img)
Để chỉ giữ lại vùng của đối tượng thay vì toàn bộ ảnh, hãy cắt ảnh theo bounding box của detection:
# Bounding box coordinates
x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
# Crop the isolated image to the object region
iso_crop = isolated[y1:y2, x1:x2]
Tính năng này đã được tích hợp sẵn. Truyền save_crop=True vào predict(), và Ultralytics sẽ tự động lưu các ảnh cắt theo bounding box mà không cần masking.
Lưu kết quả (tùy chọn)#
Bạn sử dụng mỗi đối tượng đã cô lập như thế nào là tùy bạn. Một bước tiếp theo phổ biến là ghi đối tượng đó vào ổ đĩa để dùng sau:
# Save the isolated object to file
cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated)Ở đây, img_name là phần tên không có phần mở rộng của ảnh nguồn, label là tên class và ci là chỉ mục detection, vì vậy nhiều instance của cùng một class sẽ nhận được tên file duy nhất. Thay isolated bằng iso_crop nếu bạn đã áp dụng bước cắt tùy chọn ở trên.
Ví dụ đầy đủ#
Script bên dưới kết hợp mọi bước thành một block duy nhất có thể chạy được. Theo mặc định, script sử dụng nền đen; hãy thay dòng được đánh dấu bằng np.dstack([img, b_mask]) để tạo PNG trong suốt:
from pathlib import Path
import cv2
import numpy as np
from ultralytics import YOLO
model = YOLO("yolo26n-seg.pt")
results = model.predict(source="path/to/image.jpg")
for r in results:
img = np.copy(r.orig_img)
img_name = Path(r.path).stem
for ci, c in enumerate(r):
label = c.names[c.boxes.cls.tolist().pop()]
# Build a binary mask from the object contour
b_mask = np.zeros(img.shape[:2], np.uint8)
contour = c.masks.xy[0].astype(np.int32).reshape(-1, 1, 2)
cv2.drawContours(b_mask, [contour], -1, (255, 255, 255), cv2.FILLED)
# Isolate the object (black background)
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
isolated = cv2.bitwise_and(mask3ch, img) # transparent PNG: isolated = np.dstack([img, b_mask])
# Save or add your custom post-processing here
cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated)
# Optional: crop to the bounding box before saving
# x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
# cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated[y1:y2, x1:x2])Nếu sử dụng lặp lại, hãy đóng phần thân vòng lặp vào một function để có thể gọi function đó trên nhiều ảnh.
Kết luận#
Bạn đã có công thức hoàn chỉnh để cô lập các đối tượng phân đoạn bằng Ultralytics YOLO: chạy suy luận, xây dựng binary mask từ từng đường bao, sau đó trích xuất đối tượng trên nền đen hoặc trong suốt và tùy chọn cắt theo bounding box. Xem tài liệu đầy đủ về Segment Task và Predict Mode để điều chỉnh workflow cho các class riêng của bạn.
FAQ#
Tải một model phân đoạn, chạy suy luận, xây dựng binary mask từ đường bao của từng detection và kết hợp mask đó với ảnh gốc:
import cv2 import numpy as np from ultralytics import YOLO model = YOLO("yolo26n-seg.pt") results = model.predict(source="path/to/your/image.jpg") 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) mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR) isolated = cv2.bitwise_and(mask3ch, img)Xem Ví dụ đầy đủ để biết vòng lặp hoàn chỉnh cho từng detection.
Có hai kiểu chính. Với nền đen, hãy chuyển mask thành ba channel và sử dụng
cv2.bitwise_and(). Với nền trong suốt (khi lưu dưới dạng PNG), hãy xếp mask thành channel alpha thứ tư bằngnp.dstack([img, b_mask]). Cả hai cách đều được trình bày trong phần Cô lập đối tượng.Đọc tọa độ bounding box từ detection và cắt ảnh đã cô lập:
x1, y1, x2, y2 = results[0].boxes.xyxy[0].cpu().numpy().astype(np.int32) 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.
Ultralytics YOLO cung cấp khả năng phân đoạn instance nhanh theo thời gian thực với việc tạo mask và bounding box chính xác, cùng một Python API đơn giản giúp chuyển kết quả suy luận thành các đối tượng đã cô lập chỉ với vài dòng code OpenCV.
Có. Sử dụng đối số
save_croptrongpredict()để lưu các ảnh cắt theo bounding box cùng với nền gốc của chúng:results = model.predict(source="path/to/your/image.jpg", save_crop=True)Đọc thêm trong phần Đối số suy luận của Predict Mode.