Ultralytics YOLO27:

Ultralytics YOLO로 세그멘테이션 객체를 분리하는 방법#

인스턴스 세그멘테이션은 감지된 모든 객체에 대해 픽셀 단위로 정밀한 마스크를 생성하므로, 각 객체를 이미지에서 개별적으로 추출할 수 있습니다. 이 가이드에서는 Predict Mode와 OpenCV를 사용하여 Ultralytics YOLO 세그멘테이션 결과를 분리된 객체로 변환하는 방법을 보여 줍니다. 저장 시 단색 검은색 배경 또는 투명 배경을 선택할 수 있으며, 후자의 경우 PNG로 저장할 수 있습니다.



Watch: How to Remove Background and Isolate Objects with Ultralytics YOLO Segmentation & OpenCV in Python 🚀

세그멘테이션 객체를 분리해야 하는 이유는 무엇인가요?#

이미지에서 개별 객체를 추출하면 다양한 후속 워크플로를 활용할 수 있습니다.

  • 제품 사진, 카탈로그 또는 창의적인 편집을 위한 배경 제거입니다.
  • 감지 결과에서 분류 데이터셋을 구축하기 위한 객체별 크롭입니다.
  • 이후 OCR, 색상 분석 또는 측정과 같은 단계에서 주변 장면이 아닌 객체만 처리하도록 하는 집중 처리입니다.
  • 객체를 새로운 배경에 합성하기 위한 투명 PNG 내보내기입니다.

이 방법은 모든 Ultralytics YOLO 세그멘테이션 모델에서 작동하며, 추론 실행각 윤곽선 추출객체 분리결과 저장의 네 단계로 진행됩니다.

세그멘테이션 추론 실행#

필요한 라이브러리를 설치한 다음 세그멘테이션 모델(마스크 생성에 필요한 -seg 접미사)을 로드하고 소스 이미지에 대해 prediction을 실행합니다.

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

source 없이 model.predict()을 호출하면 Ultralytics는 패키지와 함께 제공되는 예제 이미지(bus.jpgzidane.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  # 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].astype(np.int32).reshape(-1, 1, 2)`는 어떤 작업을 수행하나요?
  • c.masks.xy[0]은 이 단일 감지 결과의 객체에 대한 마스크 윤곽선을 (x, y) 포인트 좌표로 반환합니다.
  • .astype(np.int32)float32에서 포인트를 변환합니다. OpenCV의 drawContours()는 해당 형식을 허용하지 않습니다.
  • .reshape(-1, 1, 2)은 포인트를 drawContours()가 예상하는 [N, 1, 2] 레이아웃으로 재구성하며, 여기서 N은 윤곽선 포인트의 개수입니다.

-1 인덱스와 함께 [contour]을 전달하면 제공된 윤곽선의 모든 포인트를 그리고, cv2.FILLED는 둘러싸인 모든 픽셀을 흰색으로 채웁니다.

객체 분리#

이진 마스크가 준비되면 원본 이미지와 결합합니다. 배경을 어떻게 설정할지에 따라 일반적으로 두 가지 방식이 있습니다.

분리 방식 선택

마스크를 3개 채널로 변환하고 객체와 겹치는 픽셀만 유지합니다. 윤곽선 바깥의 모든 영역은 검은색이 됩니다.

# Isolate object with a black background
mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
isolated = cv2.bitwise_and(mask3ch, img)
Example Full size Isolated Object Image Black Background
Full-size object on a black background
바운딩 박스로 크롭

전체 크기 이미지 대신 객체 영역만 유지하려면 감지 결과의 바운딩 박스에 맞게 잘라냅니다.

# 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]
Example Crop Isolated Object Image Black Background
Object cropped to its bounding box
원본 배경이 포함된 크롭이 필요한가요?

기능이 기본 제공됩니다. save_crop=Truepredict()에 전달하면 마스킹 없이 Ultralytics가 바운딩 박스 크롭을 자동으로 저장합니다.

결과 저장(선택 사항)#

각각의 분리된 객체를 어떻게 사용할지는 사용자가 결정합니다. 일반적인 다음 단계는 나중에 사용할 수 있도록 디스크에 저장하는 것입니다.

# Save the isolated object to file
cv2.imwrite(f"{img_name}_{label}-{ci}.png", isolated)

여기서 img_name은 소스 이미지의 스템이고, label은 클래스 이름이며, ci는 감지 인덱스입니다. 따라서 같은 클래스의 여러 인스턴스에도 고유한 파일 이름이 지정됩니다. 위의 선택적 크롭을 적용했다면 isolatediso_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로 세그멘테이션 객체를 분리하는 전체 방법을 익혔습니다. 추론을 실행하고, 각 윤곽선에서 이진 마스크를 만든 다음, 검은색 또는 투명 배경에서 객체를 추출하고 필요에 따라 바운딩 박스에 맞게 크롭하면 됩니다. 전체 Segment TaskPredict Mode 문서를 살펴보고 워크플로를 자체 클래스에 맞게 조정하세요.

FAQ#

  • 세그멘테이션 모델을 로드하고 추론을 실행한 다음, 각 감지 결과의 윤곽선에서 이진 마스크를 만들고 원본 이미지와 결합합니다.

    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 Mode 문서를 참조하세요.

  • Ultralytics YOLO는 정확한 마스크 및 바운딩 박스 생성을 지원하는 빠른 실시간 인스턴스 세그멘테이션과 간단한 Python API를 제공합니다. 이를 통해 몇 줄의 OpenCV 코드만으로 추론 결과를 분리된 객체로 변환할 수 있습니다.

  • 예. predict()에서 save_crop 인수를 사용하면 원본 배경이 포함된 바운딩 박스 크롭을 저장할 수 있습니다.

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

    자세한 내용은 Predict Mode 추론 인수 섹션을 참조하세요.

댓글