μ½˜ν…μΈ λ‘œ κ±΄λ„ˆλ›°κΈ°

μ„ΈλΆ„ν™” 개체 격리

μ„Έκ·Έλ¨ΌνŠΈ μž‘μ—…μ„ μˆ˜ν–‰ν•œ ν›„ μΆ”λ‘  κ²°κ³Όμ—μ„œ 고립된 개체λ₯Ό μΆ”μΆœν•˜λŠ” 것이 λ°”λžŒμ§ν•  λ•Œκ°€ μžˆμŠ΅λ‹ˆλ‹€. 이 κ°€μ΄λ“œλŠ” Ultralytics 예츑λͺ¨λ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 이λ₯Ό μˆ˜ν–‰ν•˜λŠ” 방법에 λŒ€ν•œ 일반적인 방법을 μ œκ³΅ν•©λ‹ˆλ‹€.

격리된 개체 μ„ΈλΆ„ν™” μ˜ˆμ‹œ

λ ˆμ‹œν”Ό μ›Œν¬μŠ€λ£¨

  1. ν•„μš”ν•œ κ°€μ Έμ˜€κΈ°λΆ€ν„° μ‹œμž‘ν•˜μ„Έμš”.

    from pathlib import Path
    
    import cv2
    import numpy as np
    from ultralytics import YOLO
    
    Ultralytics μ„€μΉ˜

    ν•„μš”ν•œ 라이브러리 μ„€μΉ˜μ— λŒ€ν•œλΉ λ₯Έ μ•ˆλ‚΄λŠ” Ultralytics λΉ λ₯Έ μ‹œμž‘ μ„€μΉ˜ μ„Ήμ…˜μ„ μ°Έμ‘°ν•˜μ„Έμš”.


  2. λͺ¨λΈμ„ λ‘œλ“œν•˜κ³  μ‹€ν–‰ predict() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

    from ultralytics import YOLO
    
    # Load a model
    model = YOLO('yolov8n-seg.pt')
    
    # Run inference
    results = model.predict()
    

    예츑 μΈμˆ˜κ°€ μ—†λ‚˜μš”?

    μ†ŒμŠ€λ₯Ό μ§€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ λΌμ΄λΈŒλŸ¬λ¦¬μ— μžˆλŠ” 예제 이미지가 μ‚¬μš©λ©λ‹ˆλ‹€:

    'ultralytics/assets/bus.jpg'
    'ultralytics/assets/zidane.jpg'
    

    μ΄λŠ” μ‹ μ†ν•œ ν…ŒμŠ€νŠΈμ— μœ μš©ν•©λ‹ˆλ‹€. predict() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

    μ„ΈλΆ„ν™” λͺ¨λΈμ— λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ€ λ‹€μŒμ„ μ°Έμ‘°ν•˜μ„Έμš”. μ„Έκ·Έλ¨ΌνŠΈ μž‘μ—… νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€. λ‹€μŒμ— λŒ€ν•΄ μžμ„Ένžˆ μ•Œμ•„λ³΄λ €λ©΄ predict() λ©”μ„œλ“œμ— λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ€ 예츑 λͺ¨λ“œ μ„Ήμ…˜μ„ μ°Έμ‘°ν•˜μ„Έμš”.


  3. 이제 결과와 μœ€κ³½μ„ μ„ λ°˜λ³΅ν•©λ‹ˆλ‹€. 이미지λ₯Ό 파일둜 μ €μž₯ν•˜λ €λŠ” μ›Œν¬ν”Œλ‘œμš°μ˜ 경우 μ†ŒμŠ€ 이미지 base-name 및 탐지 class-label λŠ” λ‚˜μ€‘μ— μ‚¬μš©ν•  수 μžˆλ„λ‘ κ²€μƒ‰λ©λ‹ˆλ‹€(선택 사항).

    # (2) Iterate detection results (helpful for multiple images)
    for r in res:
        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. 탐지 κ²°κ³Ό μž‘μ—…μ— λŒ€ν•΄ μžμ„Ένžˆ μ•Œμ•„λ³΄λ €λ©΄ 예츑 λͺ¨λ“œμ˜ λ°•μŠ€ μ„Ήμ…˜μ„ μ°Έμ‘°ν•˜μ„Έμš”.
    2. μžμ„Ένžˆ μ•Œμ•„λ³΄κΈ° predict() κ²°κ³Ό μ°Έμ‘° 예츑 λͺ¨λ“œμ˜ κ²°κ³Ό μž‘μ—…
    For-Loop

    단일 μ΄λ―Έμ§€λŠ” 첫 번째 루프λ₯Ό ν•œ 번만 λ°˜λ³΅ν•©λ‹ˆλ‹€. 단일 κ°μ§€λ§Œ μžˆλŠ” 단일 μ΄λ―Έμ§€λŠ” 각 루프λ₯Ό ν•œ 번만 λ°˜λ³΅ν•©λ‹ˆλ‹€.


  4. λ¨Όμ € μ†ŒμŠ€ μ΄λ―Έμ§€μ—μ„œ 이진 마슀크λ₯Ό μƒμ„±ν•œ λ‹€μŒ 마슀크 μœ„μ— μ±„μ›Œμ§„ μœ€κ³½μ„ κ·Έλ¦½λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ 개체λ₯Ό μ΄λ―Έμ§€μ˜ λ‹€λ₯Έ λΆ€λΆ„κ³Ό 뢄리할 수 μžˆμŠ΅λ‹ˆλ‹€. μ˜ˆμ‹œ bus.jpg νƒμ§€λœ 것 쀑 ν•˜λ‚˜μ— λŒ€ν•΄ person 클래슀 객체λ₯Ό 였λ₯Έμͺ½μ— ν‘œμ‹œν•©λ‹ˆλ‹€.

    λ°”μ΄λ„ˆλ¦¬ 마슀크 이미지

    # 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)
    
    1. λ‹€μŒμ— λŒ€ν•œ μžμ„Έν•œ 정보 c.masks.xy μ°Έμ‘° 예츑 λͺ¨λ“œμ˜ 마슀크 μ„Ήμ…˜.

    2. μ—¬κΈ°μ„œ 값은 λ‹€μŒκ³Ό 같이 μΊμŠ€νŒ…λ©λ‹ˆλ‹€. np.int32 μ™€μ˜ ν˜Έν™˜μ„±μ„ μœ„ν•΄ drawContours() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

    3. OpenCV drawContours() ν•¨μˆ˜λŠ” μœ€κ³½μ„ μ΄ λ‹€μŒκ³Ό 같은 λͺ¨μ–‘을 κ°€μ§ˆ κ²ƒμœΌλ‘œ μ˜ˆμƒν•©λ‹ˆλ‹€. [N, 1, 2] μ•„λž˜ μ„Ήμ…˜μ„ ν™•μž₯ν•˜μ—¬ μžμ„Έν•œ λ‚΄μš©μ„ ν™•μΈν•˜μ„Έμš”.

    ν™•μž₯ν•˜μ—¬ μ •μ˜ν•  λ•Œ μ–΄λ–€ 일이 λ°œμƒν•˜λŠ”μ§€ μ΄ν•΄ν•©λ‹ˆλ‹€. contour λ³€μˆ˜μž…λ‹ˆλ‹€.

    • c.masks.xy :: 마슀크 윀곽점의 μ’Œν‘œλ₯Ό λ‹€μŒκ³Ό 같은 ν˜•μ‹μœΌλ‘œ μ œκ³΅ν•©λ‹ˆλ‹€. (x, y). μžμ„Έν•œ λ‚΄μš©μ€ 예츑 λͺ¨λ“œμ˜ 마슀크 μ„Ήμ…˜.

    • .pop() :: As masks.xy κ°€ 단일 μš”μ†Œλ₯Ό ν¬ν•¨ν•˜λŠ” λͺ©λ‘μΈ 경우, 이 μš”μ†ŒλŠ” pop() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

    • .astype(np.int32) :: μ‚¬μš© masks.xy 은 데이터 μœ ν˜•μ΄ float32λ₯Ό μ‚¬μš©ν•  수 μžˆμ§€λ§Œ, μ΄λŠ” OpenCV drawContours() ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ 데이터 μœ ν˜•μ΄ λ‹€μŒκ³Ό 같이 λ³€κ²½λ©λ‹ˆλ‹€. int32 ν˜Έν™˜μ„±μ„ ν™•μΈν•©λ‹ˆλ‹€.

    • .reshape(-1, 1, 2) :: 데이터λ₯Ό ν•„μš”ν•œ λͺ¨μ–‘μœΌλ‘œ λ‹€μ‹œ ν¬λ§·ν•©λ‹ˆλ‹€. [N, 1, 2] μ–΄λ”” N λŠ” 윀곽 점의 수이며, 각 점은 단일 ν•­λͺ©μœΌλ‘œ ν‘œμ‹œλ©λ‹ˆλ‹€. 1ν•­λͺ©μ€ λ‹€μŒκ³Ό 같이 κ΅¬μ„±λ©λ‹ˆλ‹€. 2 κ°’μž…λ‹ˆλ‹€. The -1 λŠ” 이 μ°¨μ›μ˜ κ°’ μˆ˜κ°€ μœ μ—°ν•˜λ‹€λŠ” 것을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

    ν™•μž₯ν•˜λ©΄ drawContours() ꡬ성.

    • μΊ‘μŠν™” contour λ³€μˆ˜λ₯Ό λŒ€κ΄„ν˜Έ μ•ˆμ— λ„£μŠ΅λ‹ˆλ‹€, [contour]λ₯Ό μ‚¬μš©ν•˜λ©΄ ν…ŒμŠ€νŠΈ 쀑에 μ›ν•˜λŠ” 윀곽 마슀크λ₯Ό 효과적으둜 μƒμ„±ν•˜λŠ” κ²ƒμœΌλ‘œ λ‚˜νƒ€λ‚¬μŠ΅λ‹ˆλ‹€.

    • κ°’ -1 에 μ§€μ •λœ drawContours() λ§€κ°œλ³€μˆ˜λŠ” 이미지에 μ‘΄μž¬ν•˜λŠ” λͺ¨λ“  μœ€κ³½μ„ μ„ 그리도둝 ν•¨μˆ˜μ— μ§€μ‹œν•©λ‹ˆλ‹€.

    • 그리고 tuple (255, 255, 255) λŠ” 이 이진 λ§ˆμŠ€ν¬μ—μ„œ μœ€κ³½μ„ μ„ 그릴 λ•Œ μ›ν•˜λŠ” 색상인 흰색을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

    • μΆ”κ°€ cv2.FILLED λŠ” 윀곽 κ²½κ³„λ‘œ λ‘˜λŸ¬μ‹ΈμΈ λͺ¨λ“  ν”½μ…€μ˜ 색을 λ™μΌν•˜κ²Œ μ§€μ •ν•˜λ©°, 이 경우 λ‘˜λŸ¬μ‹ΈμΈ λͺ¨λ“  픽셀은 흰색이 λ©λ‹ˆλ‹€.

    • μ°Έμ‘° OpenCV λ¬Έμ„œ drawContours() μ—μ„œ μžμ„Έν•œ λ‚΄μš©μ„ ν™•μΈν•˜μ„Έμš”.


  5. λ‹€μŒμœΌλ‘œ 이 μ‹œμ μ—μ„œ 이미지λ₯Ό μ§„ν–‰ν•˜λŠ” 방법에 λŒ€ν•œ 두 가지 μ˜΅μ…˜κ³Ό 각 μ˜΅μ…˜μ— λŒ€ν•œ 후속 μ˜΅μ…˜μ΄ μžˆμŠ΅λ‹ˆλ‹€.

    개체 격리 μ˜΅μ…˜

    # Create 3-channel mask
    mask3ch = cv2.cvtColor(b_mask, cv2.COLOR_GRAY2BGR)
    
    # Isolate object with binary mask
    isolated = cv2.bitwise_and(mask3ch, img)
    
    μ–΄λ–»κ²Œ μž‘λ™ν•˜λ‚˜μš”?
    • λ¨Όμ € λ°”μ΄λ„ˆλ¦¬ λ§ˆμŠ€ν¬κ°€ λ¨Όμ € 단일 채널 μ΄λ―Έμ§€μ—μ„œ 3채널 μ΄λ―Έμ§€λ‘œ λ³€ν™˜λ©λ‹ˆλ‹€. 이 λ³€ν™˜μ€ λ§ˆμŠ€ν¬μ™€ 원본 이미지가 κ²°ν•©λ˜λŠ” 후속 단계에 ν•„μš”ν•©λ‹ˆλ‹€. λΈ”λ Œλ”© μž‘μ—…κ³Ό ν˜Έν™˜λ˜λ €λ©΄ 두 μ΄λ―Έμ§€μ˜ 채널 μˆ˜κ°€ κ°™μ•„μ•Ό ν•©λ‹ˆλ‹€.

    • 원본 이미지와 3채널 λ°”μ΄λ„ˆλ¦¬ λ§ˆμŠ€ν¬λŠ” OpenCV ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ λ³‘ν•©λ©λ‹ˆλ‹€. bitwise_and(). 이 μž‘μ—…μ€ λ‹€μŒμ„ μœ μ§€ν•©λ‹ˆλ‹€. 만 0보닀 큰 ν”½μ…€ κ°’ (> 0) λ₯Ό μ œκ±°ν•©λ‹ˆλ‹€. 마슀크 픽셀이 0보닀 ν¬λ―€λ‘œ (> 0) 만 μœ€κ³½μ„  μ˜μ—­ λ‚΄μ—μ„œ 원본 μ΄λ―Έμ§€μ—μ„œ 남은 픽셀은 μœ€κ³½μ„ κ³Ό κ²ΉμΉ˜λŠ” ν”½μ…€μž…λ‹ˆλ‹€.

    검은색 ν”½μ…€λ‘œ 격리: ν•˜μœ„ μ˜΅μ…˜

    전체 크기 이미지

    전체 크기 이미지λ₯Ό μœ μ§€ν•˜λŠ” 경우 μΆ”κ°€ 단계가 ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

    전체 크기 고립된 개체 이미지 검정색 λ°°κ²½ μ˜ˆμ‹œ
    전체 크기 좜λ ₯ μ˜ˆμ‹œ

    잘린 개체 이미지

    객체 μ˜μ—­λ§Œ ν¬ν•¨ν•˜λ„λ‘ 이미지λ₯Ό 자λ₯΄λ €λ©΄ μΆ”κ°€ 단계가 ν•„μš”ν•©λ‹ˆλ‹€.

    격리된 개체 이미지 자λ₯΄κΈ° μ˜ˆμ‹œ 검은색 λ°°κ²½

    # (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]
    

    1. λ°”μš΄λ”© λ°•μŠ€ 결과에 λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ€ 예츑 λͺ¨λ“œμ˜ λ°•μŠ€ μ„Ήμ…˜μ„ μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€.
    이 μ½”λ“œλŠ” μ–΄λ–€ κΈ°λŠ₯을 ν•˜λ‚˜μš”?
    • 그리고 c.boxes.xyxy.cpu().numpy() ν˜ΈμΆœμ€ λ°”μš΄λ”© λ°•μŠ€λ₯Ό NumPy λ°°μ—΄λ‘œ κ²€μƒ‰ν•©λ‹ˆλ‹€. xyxy ν˜•μ‹μœΌλ‘œ, μ—¬κΈ°μ„œ xmin, ymin, xmax및 ymax λŠ” λ°”μš΄λ”© λ°•μŠ€ μ§μ‚¬κ°ν˜•μ˜ μ’Œν‘œλ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€. μ°Έμ‘° 예츑 λͺ¨λ“œμ˜ λ°•μŠ€ μ„Ήμ…˜ μ—μ„œ μžμ„Έν•œ λ‚΄μš©μ„ ν™•μΈν•˜μ„Έμš”.

    • 그리고 squeeze() 연산은 NumPy λ°°μ—΄μ—μ„œ λΆˆν•„μš”ν•œ 치수λ₯Ό μ œκ±°ν•˜μ—¬ μ˜ˆμƒλ˜λŠ” λͺ¨μ–‘을 갖도둝 ν•©λ‹ˆλ‹€.

    • λ‹€μŒμ„ μ‚¬μš©ν•˜μ—¬ μ’Œν‘œ κ°’ λ³€ν™˜ν•˜κΈ° .astype(np.int32) μ—μ„œ μƒμž μ’Œν‘œ 데이터 μœ ν˜•μ„ λ³€κ²½ν•©λ‹ˆλ‹€. float32 에 int32λ₯Ό μ‚¬μš©ν•˜μ—¬ 인덱슀 슬라이슀λ₯Ό μ‚¬μš©ν•œ 이미지 자λ₯΄κΈ°μ— ν˜Έν™˜λ©λ‹ˆλ‹€.

    • λ§ˆμ§€λ§‰μœΌλ‘œ 인덱슀 μŠ¬λΌμ΄μ‹±μ„ μ‚¬μš©ν•˜μ—¬ μ΄λ―Έμ§€μ—μ„œ λ°”μš΄λ”© λ°•μŠ€ μ˜μ—­μ„ μž˜λΌλƒ…λ‹ˆλ‹€. κ²½κ³„λŠ” [ymin:ymax, xmin:xmax] 감지 경계 μƒμžμ˜ μ’Œν‘œμž…λ‹ˆλ‹€.

    # Isolate object with transparent background (when saved as PNG)
    isolated = np.dstack([img, b_mask])
    
    μ–΄λ–»κ²Œ μž‘λ™ν•˜λ‚˜μš”?
    • NumPy μ‚¬μš© dstack() ν•¨μˆ˜(깊이 좕을 따라 λ°°μ—΄ μŠ€νƒœν‚Ή)λ₯Ό μƒμ„±λœ 이진 λ§ˆμŠ€ν¬μ™€ ν•¨κ»˜ μ‚¬μš©ν•˜λ©΄ 4개의 채널이 μžˆλŠ” 이미지가 μƒμ„±λ©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ 였브젝트 μœ€κ³½μ„  μ™ΈλΆ€μ˜ λͺ¨λ“  픽셀을 투λͺ…ν•˜κ²Œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€. PNG νŒŒμΌμ„ λ§Œλ“­λ‹ˆλ‹€.

    투λͺ… ν”½μ…€λ‘œ 격리: ν•˜μœ„ μ˜΅μ…˜

    전체 크기 이미지

    전체 크기 이미지λ₯Ό μœ μ§€ν•˜λŠ” 경우 μΆ”κ°€ 단계가 ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

    전체 크기 고립된 개체 이미지 μ˜ˆμ‹œ λ°°κ²½ μ—†μŒ
    전체 크기 좜λ ₯ + 투λͺ… λ°°κ²½ μ˜ˆμ‹œ

    잘린 개체 이미지

    객체 μ˜μ—­λ§Œ ν¬ν•¨ν•˜λ„λ‘ 이미지λ₯Ό 자λ₯΄λ €λ©΄ μΆ”κ°€ 단계가 ν•„μš”ν•©λ‹ˆλ‹€.

    λ°°κ²½ 없이 고립된 개체 이미지 자λ₯΄κΈ° μ˜ˆμ‹œ

    # (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]
    

    1. λ°”μš΄λ”© λ°•μŠ€ 결과에 λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ€ 예츑 λͺ¨λ“œμ˜ λ°•μŠ€ μ„Ήμ…˜μ„ μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€.
    이 μ½”λ“œλŠ” μ–΄λ–€ κΈ°λŠ₯을 ν•˜λ‚˜μš”?
    • μ‚¬μš© μ‹œ c.boxes.xyxy.cpu().numpy()λ₯Ό μ‚¬μš©ν•˜μ—¬ 경계 μƒμžλ₯Ό NumPy λ°°μ—΄λ‘œ λ°˜ν™˜ν•©λ‹ˆλ‹€. xyxy μƒμž μ’Œν‘œ ν˜•μ‹μœΌλ‘œ, ν¬μΈνŠΈμ— ν•΄λ‹Ήν•˜λŠ” xmin, ymin, xmax, ymax λ°”μš΄λ”© λ°•μŠ€(μ§μ‚¬κ°ν˜•)의 경우, λ‹€μŒμ„ μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€. 예츑 λͺ¨λ“œμ˜ λ°•μŠ€ μ„Ήμ…˜ μ—μ„œ μžμ„Έν•œ λ‚΄μš©μ„ ν™•μΈν•˜μ„Έμš”.

    • μΆ”κ°€ squeeze() λŠ” λΆˆν•„μš”ν•œ 차원이 NumPy λ°°μ—΄μ—μ„œ μ œκ±°λ˜λ„λ‘ ν•©λ‹ˆλ‹€.

    • λ‹€μŒμ„ μ‚¬μš©ν•˜μ—¬ μ’Œν‘œ κ°’ λ³€ν™˜ν•˜κΈ° .astype(np.int32) μ—μ„œ μƒμž μ’Œν‘œ 데이터 μœ ν˜•μ„ λ³€κ²½ν•©λ‹ˆλ‹€. float32 에 int32 인덱슀 슬라이슀λ₯Ό μ‚¬μš©ν•˜μ—¬ 이미지λ₯Ό 자λ₯Ό λ•Œ ν˜Έν™˜λ©λ‹ˆλ‹€.

    • λ§ˆμ§€λ§‰μœΌλ‘œ 인덱슀 μŠ¬λΌμ΄μ‹±μ„ μ‚¬μš©ν•˜μ—¬ 경계 μƒμžμ— λŒ€ν•œ 이미지 μ˜μ—­μ„ 자λ₯΄κ³ , μ—¬κΈ°μ„œ κ²½κ³„λŠ” [ymin:ymax, xmin:xmax] 감지 경계 μƒμžμ˜ μ’Œν‘œμž…λ‹ˆλ‹€.

    배경을 ν¬ν•¨ν•˜μ—¬ 잘린 개체λ₯Ό μ›ν•˜λ©΄ μ–΄λ–»κ²Œ ν•˜λ‚˜μš”?

    이 κΈ°λŠ₯은 Ultralytics λΌμ΄λΈŒλŸ¬λ¦¬μ— λ‚΄μž₯된 κΈ°λŠ₯μž…λ‹ˆλ‹€. λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ save_crop 에 λŒ€ν•œ 인수 예츑 λͺ¨λ“œ μΆ”λ‘  인수 λ₯Ό μ°Έμ‘°ν•˜μ„Έμš”.


  6. λ‹€μŒμ— μˆ˜ν–‰ν•  μž‘μ—…μ€ μ „μ μœΌλ‘œ κ°œλ°œμžμ—κ²Œ 달렀 μžˆμŠ΅λ‹ˆλ‹€. κ°€λŠ₯ν•œ λ‹€μŒ 단계(λ‚˜μ€‘μ— μ‚¬μš©ν•  수 μžˆλ„λ‘ 이미지λ₯Ό νŒŒμΌμ— μ €μž₯)의 κΈ°λ³Έ μ˜ˆκ°€ λ‚˜μ™€ μžˆμŠ΅λ‹ˆλ‹€.

    • μ°Έκ³ : 이 λ‹¨κ³„λŠ” 선택 사항이며 νŠΉμ • μ‚¬μš© 사둀에 ν•„μš”ν•˜μ§€ μ•Šμ€ 경우 κ±΄λ„ˆλ›Έ 수 μžˆμŠ΅λ‹ˆλ‹€.
    μ΅œμ’… 단계 μ˜ˆμ‹œ
    # Save isolated object to file
    _ = cv2.imwrite(f'{img_name}_{label}-{ci}.png', iso_crop)
    
    • 이 μ˜ˆμ œμ—μ„œλŠ” img_name 은 μ†ŒμŠ€ 이미지 파일의 κΈ°λ³Έ μ΄λ¦„μž…λ‹ˆλ‹€, label 은 κ°μ§€λœ 클래슀 이름이고 ci λŠ” 객체 κ°μ§€μ˜ μΈλ±μŠ€μž…λ‹ˆλ‹€(λ™μΌν•œ 클래슀 이름을 가진 μΈμŠ€ν„΄μŠ€κ°€ μ—¬λŸ¬ 개 μžˆλŠ” 경우).

전체 예제 μ½”λ“œ

μ—¬κΈ°μ—μ„œλŠ” 이전 μ„Ήμ…˜μ˜ λͺ¨λ“  단계λ₯Ό ν•˜λ‚˜μ˜ μ½”λ“œ λΈ”λ‘μœΌλ‘œ κ²°ν•©ν•©λ‹ˆλ‹€. 반볡적으둜 μ‚¬μš©ν•˜λ €λ©΄ 일뢀 λ˜λŠ” λͺ¨λ“  λͺ…령을 μˆ˜ν–‰ν•˜λŠ” ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜λŠ” 것이 κ°€μž₯ μ’‹μŠ΅λ‹ˆλ‹€. for-루프λ₯Ό μ‚¬μš©ν•  μˆ˜λ„ μžˆμ§€λ§Œ, μ΄λŠ” λ…μžμ˜ νŒλ‹¨μ— λ§‘κΈ°κ² μŠ΅λ‹ˆλ‹€.

from pathlib import Path

import cv2
import numpy as np
from ultralytics import YOLO

m = YOLO('yolov8n-seg.pt')#(4)!
res = m.predict()#(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]

        # TODO your actions go here (2)
  1. 쀄 μ±„μš°κΈ° contour λŠ” μœ„μ—μ„œ μ—¬λŸ¬ μ€„λ‘œ λ‚˜λ‰˜μ—ˆλ˜ 것을 μ—¬κΈ°μ„œλŠ” ν•œ μ€„λ‘œ ν•©μ³€μŠ΅λ‹ˆλ‹€.
  2. 여기에 무엇을 λ„£μ„μ§€λŠ” μ—¬λŸ¬λΆ„μ—κ²Œ 달렀 μžˆμŠ΅λ‹ˆλ‹€!
  3. μžμ„Έν•œ λ‚΄μš©μ€ 예츑 λͺ¨λ“œλ₯Ό μ°Έμ‘°ν•˜μ„Έμš”.
  4. μžμ„Έν•œ λ‚΄μš©μ€ μ„Έκ·Έλ¨ΌνŠΈ μž‘μ—…μ„ μ°Έμ‘°ν•˜μ„Έμš”.
  5. κ²°κ³Ό μž‘μ—…μ— λŒ€ν•΄ μžμ„Ένžˆ μ•Œμ•„λ³΄κΈ°
  6. μ„ΈλΆ„ν™” 마슀크 결과에 λŒ€ν•΄ μžμ„Ένžˆ μ•Œμ•„λ³΄κΈ°


2023-11-27 생성, 2024-04-27 μ—…λ°μ΄νŠΈλ¨
μž‘μ„±μž: glenn-jocher (6), RizwanMunawar (1), Burhan-Q (1)

λŒ“κΈ€