Cô lập các Đối tượng Phân đoạn
Sau khi thực hiện Segment Task, đôi khi người dùng muốn trích xuất các đối tượng đã được cô lập từ kết quả inference. Hướng dẫn này cung cấp phương pháp tổng quát để thực hiện việc này bằng cách sử dụng Chế độ Predict.
Watch: How to Remove Background and Isolate Objects with Ultralytics YOLO Segmentation & OpenCV in Python 🚀
Recipe Walkthrough
-
Xem phần Ultralytics Quickstart Installation section để xem hướng dẫn nhanh về việc cài đặt các thư viện cần thiết.
-
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()
Nếu không chỉ định nguồn, các hình ả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 thử 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(), xem phần Chế độ Predict trong Tài liệu.
***
3. Bây giờ hãy lặp qua các kết quả và contours. Đối với các quy trình làm việc cần lưu hình ảnh vào tệp, hình ảnh nguồn base-name và kết quả phát hiện class-label 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 sẽ lặp qua mỗi vòng lặp chỉ một lần.
-
Bắt đầu bằng việc tạo một mask nhị phân từ hình ảnh nguồn và sau đó vẽ một contour đã được tô đầy lên mask. Đ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.jpgcho một trong các đối tượng thuộcpersonclass được hiển thị ở bên phải.{ 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)-
Để biết thêm thông tin về
c.masks.xyxemMasks Section from Predict Mode. -
Tại đây các giá trị được chuyển đổi thành
np.int32để tương thích với hàmdrawContours()từ OpenCV. -
Hàm OpenCV
drawContours()mong đợi contours có định dạng[N, 1, 2]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
contourvariable.- `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.
-
-
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 bổ sung cho mỗi trường hợp.
Tùy chọn cô lập đối tượng
# Create 3-channel mask
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
# Isolate object with binary mask
isolated = cv2.bitwise_and(mask3ch, img)Cách thức hoạt động?
-
Đầu tiên, mask nhị phân đượ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ố kênh để tương thích với thao tác trộn.
-
Hình ảnh gốc và mask nhị phân ba kênh được hợp nhất bằng cách sử dụng hàm OpenCV
bitwise_and(). Thao tác này giữ lại chỉ 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ỉ trong vùng contour, các pixel còn lại từ hình ảnh gốc là những pixel trùng với contour.
Cô lập với các pixel màu đen: Các tùy chọn phụ
Hình ảnh kích thước đầy đủ
Không cần thực hiện thêm bước nào nếu giữ nguyên kích thước hình ảnh đầy đủ.
Hình ảnh đối tượng đã crop
Cần thực hiện các bước bổ sung để crop hình ảnh chỉ bao gồm vùng đối tượng.
{ 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]- Để biết thêm thông tin về bounding box kết quả, xem Boxes Section from Predict Mode
Đoạn mã này làm gì?
-
Phương thức
c.boxes.xyxy.cpu().numpy()lệnh gọi truy xuất các bounding box dưới dạng một mảng NumPy trong định dạngxyxy, nơixmin,ymin,xmax, vàymaxđại diện cho tọa độ của hình chữ nhật bounding box. Xem Boxes Section from Predict Mode để biết thêm chi tiết. -
Phương thức
squeeze()thao tác loại bỏ bất kỳ kích thước không cần thiết nào 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đếnint32, giúp chúng tương thích để crop hình ảnh bằng cách sử dụng các lát cắt chỉ mục. -
Cuối cùng, vùng bounding box được crop 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
[ymin:ymax, xmin:xmax]tọa độ của bounding box phát hiện.
Nếu tôi muốn đối tượng đã crop **bao gồm cả** nền thì sao?
Đây là một tính năng tích hợp cho thư viện Ultralytics. Xem đối số save_crop cho Predict Mode Inference Arguments để biết chi tiết.
- 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ể được 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_namelà tên cơ sở của tệp hình ảnh nguồn,labellà tên lớp được phát hiện, vàcilà chỉ mục của object detection (trong trường hợp có nhiều thực thể với cùng một tên lớp).
Ví dụ mã đầy đủ
Tại đâ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, tốt nhất nên định nghĩa một hàm để thực hiện một phần hoặc tất cả các lệnh chứa trong for-vòng lặp, 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("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)- Dòng điền dữ liệu vào
contourđược kết hợp thành một dòng duy nhất ở đây, trong khi nó đã được chia thành nhiều dòng ở trên. - {==Nội dung đặt ở đây tùy thuộc vào bạn!==}
- Xem Chế độ Predict để biết thêm thông tin.
- Xem Segment Task để biết thêm thông tin.
- Tìm hiểu thêm về Làm việc với các kết quả (Results)
- Tìm hiểu thêm về Kết quả Mask phân đoạn
Câu hỏi thường gặp (FAQ)
Làm thế nào để tách biệt đối tượng bằng Ultralytics YOLO26 cho các tác vụ phân đoạn?
Để tách biệt đối tượng bằng Ultralytics YOLO26, hãy thực hiện theo các bước sau:
-
Tải model và chạy inference:
from ultralytics import YOLO model = YOLO("yolo26n-seg.pt") results = model.predict(source="path/to/your/image.jpg") -
Tạo binary mask và vẽ đường viền (contours):
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) -
Tách biệt đố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 tại Chế độ Predict và Segment Task để biết thêm thông tin.
Có những tùy chọn nào để lưu các đối tượng đã tách biệt 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 đã tách biệt:
-
Với nền đen (Black Background):
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR) isolated = cv2.bitwise_and(mask3ch, img) -
Với nền trong suốt (Transparent Background):
isolated = np.dstack([img, b_mask])
Để biết thêm chi tiết, hãy truy cập Chế độ Predict .
Làm cách nào để crop các đối tượng đã tách biệt vào BBox của chúng bằng Ultralytics YOLO26?
Để crop các đối tượng đã tách biệt vào BBox:
-
Truy xuất tọa độ BBox:
x1, y1, x2, y2 = results[0].boxes.xyxy[0].cpu().numpy().astype(np.int32) -
Crop ảnh đã tách biệt:
iso_crop = isolated[y1:y2, x1:x2]
Tìm hiểu thêm về kết quả BBox trong Chế độ Predict.
Tại sao nên sử dụng Ultralytics YOLO26 để tách biệt đối tượng trong các tác vụ phân đoạn?
Ultralytics YOLO26 cung cấp:
- Tốc độ cao nhận diện và phân đoạn đối tượng theo thời gian thực.
- Tạo BBox và mask chính xác để tách biệt đối tượng một cách chuẩn xác.
- Tài liệu hướng dẫn 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 của việc sử dụng YOLO trong Tài liệu tác vụ Segment.
Tôi có thể lưu các đối tượng đã tách biệt 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 tham 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ề save_crop trong phương thức Predict Mode Inference Arguments .