Ultralytics YOLO27:
Get Started

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")
입력 이미지가 없나요? YOLO에 포함된 샘플 이미지를 사용합니다.

source 없이 model.predict()을 호출하면 Ultralytics는 패키지에 포함된 예제 이미지(bus.jpg 및 zidane.jpg)를 대신 사용합니다. 따라서 워크플로를 빠르게 테스트할 때 편리합니다.

객체 윤곽선 추출#

results의 각 항목은 하나의 이미지에 해당하며, 결과를 반복하면 한 번에 하나의 탐지 결과를 가져옵니다. 각 탐지 결과마다 원본 이미지를 복사하고 클래스 레이블을 읽은 다음, 빈 이진 마스크에 객체 마스크의 윤곽선을 그리세요. 이 마스크의 흰색 영역은 객체에 속하는 픽셀을 정확히 표시합니다.

이 절과 다음 절의 코드 조각은 아래 탐지 루프 내부에서 실행합니다. 복사해 바로 실행할 수 있는 전체 스크립트는 전체 예제에 있습니다.

Binary Mask Image
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].astype(np.int32).reshape(-1, 1, 2)`은 어떤 작업을 하나요?
  • 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)
Example Full size Isolated Object Image Black Background
검은색 배경의 전체 크기 객체
바운딩 박스에 맞춰 자르기

전체 크기 이미지 대신 객체 영역만 유지하려면 탐지 결과의 바운딩 박스에 맞춰 이미지를 슬라이싱하세요:

# 바운딩 박스 좌표
x1, y1, x2, y2 = c.boxes.xyxy.cpu().numpy().squeeze().astype(np.int32)
# 분리된 이미지를 객체 영역에 맞춰 자르기
iso_crop = isolated[y1:y2, x1:x2]
Example Crop Isolated Object Image Black Background
바운딩 박스에 맞게 자른 객체
원래 배경을 유지한 채로 크롭해야 하나요?

기본 제공 기능입니다. 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 섹션에서 자세히 알아보세요.

댓글