Ultralytics YOLO로 분할 객체 분리하기#
인스턴스 분할은 탐지된 각 객체에 대해 픽셀 단위로 정밀한 마스크를 생성하므로, 이미지에서 각 객체를 개별적으로 추출할 수 있습니다. 이 가이드에서는 Ultralytics YOLO 분할 결과와 OpenCV를 사용해 객체를 분리하는 방법을 설명합니다. 단색 검은색 배경이나 PNG로 저장할 수 있는 투명 배경을 사용할 수 있습니다. 이 작업에는 Predict 모드를 사용합니다.
시청: Python에서 Ultralytics YOLO 세그멘테이션 및 OpenCV로 배경을 제거하고 객체를 분리하는 방법 🚀
분할 객체를 분리하는 이유#
이미지에서 개별 객체를 추출하면 다양한 후속 워크플로를 활용할 수 있습니다:
- 제품 사진, 카탈로그 또는 크리에이티브 편집을 위한 배경 제거.
- 탐지 결과를 활용해 분류 데이터 세트를 구축하기 위한 객체별 크롭.
- OCR, 색상 분석, 측정 등의 후속 단계에서 주변 장면이 아니라 객체만 처리하도록 하는 대상 집중 처리.
- 객체를 새로운 배경에 합성하기 위한 투명 PNG 내보내기.
이 방법은 모든 Ultralytics YOLO 분할 모델에서 사용할 수 있으며, 다음 네 단계로 진행됩니다: 추론 실행 → 각 윤곽선 추출 → 객체 분리 → 결과 저장.
분할 추론 실행#
필요한 라이브러리를 설치한 다음 분할 모델(마스크 생성에 필요한 -seg 접미사가 있는 모델)을 불러와 원본 이미지에 대해 예측을 실행하세요:
from ultralytics import YOLO
# 분할 모델 불러오기
model = YOLO("yolo26n-seg.pt")
# 원본 이미지에 대해 추론 실행
results = model.predict(source="path/to/image.jpg")source 없이 model.predict()을 호출하면 Ultralytics는 패키지에 포함된 예제 이미지(bus.jpg 및 zidane.jpg)를 대신 사용합니다. 따라서 워크플로를 빠르게 테스트할 때 편리합니다.
객체 윤곽선 추출#
results의 각 항목은 하나의 이미지에 해당하며, 결과를 반복하면 한 번에 하나의 탐지 결과를 가져옵니다. 각 탐지 결과마다 원본 이미지를 복사하고 클래스 레이블을 읽은 다음, 빈 이진 마스크에 객체 마스크의 윤곽선을 그리세요. 이 마스크의 흰색 영역은 객체에 속하는 픽셀을 정확히 표시합니다.
이 절과 다음 절의 코드 조각은 아래 탐지 루프 내부에서 실행합니다. 복사해 바로 실행할 수 있는 전체 스크립트는 전체 예제에 있습니다.
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 # 원본 이미지의 기본 이름
# 이미지에서 탐지된 각 객체 반복 처리
for ci, c in enumerate(r):
label = c.names[c.boxes.cls.tolist().pop()] # 클래스 이름
# 이진 마스크를 만들고 객체 윤곽선을 그립니다.
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]은 단일 탐지 결과에서 객체의 마스크 윤곽선을(x, y)점 좌표로 반환합니다..astype(np.int32)은float32의 점을 변환합니다. OpenCV의drawContours()는 해당 점을 입력으로 받을 수 없습니다..reshape(-1, 1, 2)은 점을[N, 1, 2]레이아웃으로 재구성하며, 이 레이아웃은drawContours()에서 기대하는 형식입니다. 여기서N은 윤곽선 점의 개수입니다.
-1 인덱스와 함께 [contour]을 전달하면 지정된 윤곽선의 모든 점을 그리며, cv2.FILLED는 둘러싸인 모든 픽셀을 흰색으로 채웁니다.
객체 분리#
이진 마스크가 준비되면 원본 이미지와 결합하세요. 배경으로 원하는 항목에 따라 일반적으로 두 가지 방식을 사용할 수 있습니다:
마스크를 3개 채널로 변환하고 객체와 겹치는 픽셀만 유지합니다. 윤곽선 바깥쪽은 모두 검은색이 됩니다:
# 검은색 배경으로 객체 분리
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
isolated = cv2.bitwise_and(mask3ch, img)
전체 크기 이미지 대신 객체 영역만 유지하려면 탐지 결과의 바운딩 박스에 맞춰 이미지를 슬라이싱하세요:
# 바운딩 박스 좌표
x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
# 분리된 이미지를 객체 영역에 맞춰 자르기
iso_crop = isolated[y1:y2, x1:x2]
기본 제공 기능입니다. save_crop=True을 predict()에 전달하면 Ultralytics가 마스킹 없이 바운딩 박스 크롭을 자동으로 저장합니다.
결과 저장(선택 사항)#
분리된 객체를 어떻게 사용할지는 사용자가 결정합니다. 일반적인 다음 단계는 나중에 사용할 수 있도록 객체를 디스크에 저장하는 것입니다:
# Save the isolated object to file
cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated)여기서 img_name은 원본 이미지의 파일명에서 확장자를 제외한 부분이고, label은 클래스 이름이며, ci는 탐지 인덱스입니다. 따라서 같은 클래스의 여러 인스턴스에도 고유한 파일명이 지정됩니다. 위에서 선택적으로 크롭을 적용했다면 isolated을 iso_crop로 바꾸세요.
전체 예제#
아래 스크립트는 모든 단계를 하나의 실행 가능한 코드 블록으로 결합합니다. 기본적으로 검은색 배경을 사용하며, 투명 PNG로 저장하려면 표시된 한 줄을 np.dstack([img, b_mask])으로 바꾸세요:
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])반복해서 사용하려면 루프 본문을 함수로 감싸 여러 이미지에 호출할 수 있도록 하세요.
결론#
이제 Ultralytics YOLO로 분할 객체를 분리하는 전체 방법을 확인했습니다. 추론을 실행하고, 각 윤곽선에서 이진 마스크를 만든 다음, 검은색 또는 투명 배경으로 객체를 추출하고 선택적으로 바운딩 박스에 맞춰 자르면 됩니다. 워크플로를 자체 클래스에 맞게 조정하려면 분할 작업 및 Predict 모드 문서를 살펴보세요.
자주 묻는 질문#
분할 모델을 불러와 추론을 실행하고, 각 탐지 결과의 윤곽선에서 이진 마스크를 만든 다음, 원본 이미지와 결합하세요:
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)탐지 결과별 전체 루프는 전체 예제를 참조하세요.
주요 방식은 두 가지입니다. 검은색 배경을 사용하려면 마스크를 3개 채널로 변환하고
cv2.bitwise_and()을 사용하세요. 투명 배경(PNG로 저장하는 경우)을 사용하려면 마스크를 네 번째 알파 채널로 쌓고np.dstack([img, b_mask])을 사용하세요. 두 방식 모두 객체 분리에 설명되어 있습니다.탐지 결과에서 바운딩 박스 좌표를 읽고 분리된 이미지를 슬라이싱하세요:
x1, y1, x2, y2 = results[0].boxes.xyxy[0].cpu().numpy().astype(np.int32) iso_crop = isolated[y1:y2, x1:x2]바운딩 박스 결과에 관한 자세한 내용은 Predict 모드 문서를 참조하세요.
Ultralytics YOLO는 정확한 마스크와 바운딩 박스를 생성하는 빠른 실시간 인스턴스 세그멘테이션을 제공하며, 몇 줄의 OpenCV 코드로 추론 결과에서 객체를 분리할 수 있는 간단한 Python API도 제공합니다.
예.
predict()에서save_crop인수를 사용하면 원래 배경이 포함된 바운딩 박스 크롭을 저장할 수 있습니다:results = model.predict(source="path/to/your/image.jpg", save_crop=True)Predict Mode Inference Arguments 섹션에서 자세히 알아보세요.