본문 바로가기

Data_Analysis_Track_33/Python

Python_Computer_vision_03(yolov8_segmentation)

Segmentation

- 모델명: yolov8?-seg (n, s, m, ...)

 

Segmentation 추론결과 조회

  • segmentation 추론 결과는 Masks를 이용해 분할된 mask 정보와 Boxes를 이용해 추론한 bounding box의 결과를 조회한다.
  • ultralytics.yolo.engine.results.Masks
        - Segmentation 의 결과 type
        - Results.masks 로 조회한다.
        - 주요 속성, 메소드
            - xy : mask의 bounding 좌표(경계선 좌표)를 물체별로 list에 담아서 반환한다.
                - Object의 외곽선을 그리는 좌표들을 반환
                - 개별 object 의 좌표들은 [point개수, x좌표-y좌표] shape의 ndarray로 구성된다.
            - xyn: xy의 결과를 이미지 크기 대비 비율로 normalize한 결과.
  • ultralytics.yolo.engine.results.Boxes
         - Results.boxes로 조회
        - 주요 속성
            - shape: 결과 shape. (찾은 물체개수, 6)
            - boxes
                - 6: 좌상단 x, 좌상단 y, 우하단 x, 우하단 y, confidence score, label
            - xyxy
                - bounding box의 좌상단 x, 좌상단 y, 우하단 x, 우하단 y 좌표 반환
            - xyxyn
                - xyxy를 이미지 대비 비율로 반환
            - xywh
                - bounding box의 center x, center y, 너비, 높이 를 반환
            - xywhn
                - xywh를 이미지 대비 비율로 반환
            - cls: 찾은 물체의 label
            - conf: cls에 대한 confidence score (그 물체일 확률)
            - boxes
                - x, y, x, y, conf, cls tensor를 반환      

 

import

from ultralytics import YOLO
import cv2
import matplotlib.pyplot as plt
import numpy as np

 

 

seg 진행할 사진 파일 경로 지정

- model 지정(yolov8m-seg.pt)

- 결과 저장

file_path = "02_test_image_seg/beatles.jpg"

model = YOLO("models/yolov8m-seg.pt")
result_list = model(file_path, save=True, save_txt=True)

 

 

파일 경로 리스트형식으로 지정

- verbose=False -> 로그 출력 X

- conf=0.5 확률 0.5이상의 object만 출력

model = YOLO("models/yolov8m-seg.pt")
file_path2 = ["02_test_image_seg/beatles.jpg", "02_test_image_seg/bus.jpg"]
result_list2 = model(file_path2, save=True, save_txt=True, conf=0.5, verbose=False)

 

 

print(type(result_list2), len(result_list2), type(result_list2[0])) # len(result_list2) -> 사진이 몇장인지

이미지 출력 함수 정의

def imshow(img):
    cv2.imshow("frame", img)
    cv2.waitKey()
    cv2.destroyAllWindows()

 

 

출력 결과 이미지 확인

# 출력 결과 이미지 확인
result = result_list[0]
imshow(result.plot()) # BGR 모드

 

 

bbox

# Bounding Box 정보
boxes = result.boxes
# print(type(boxes))
# bbox의 위치정보
print(len(boxes)) # 찾은 object 개수
print(boxes.xyxy.shape) # bbox의 좌상단 우하단 x, y 좌표
print(boxes.xyxyn.shape) # bbox의 좌상단 우하단 x, y 좌표 이미지크기 대비 비율
# [15:찾은 object개수, 4:좌표]
print(boxes.xywh.shape) # bbox의 center x, y좌표, bbox의 width, height 크기
print(boxes.xywhn.shape) # bbox의 center x, y좌표, bbox의 width, height 크기 이미지크기 대비 비율

## bbox 내의 object 분류
print(boxes.cls) # object calss index
print(boxes.conf) # object들의 확률

 

 

object들의 값 확인

result.names.items()

 

 

찾아낸 object들의 값 확인

idx2class = np.array([value for key, value in result.names.items()])
idx2class[boxes.cls.to('cpu').numpy().astype('int')]

 

 

segmentation

# segmentation
masks = result.masks
print(type(masks))

 

 

print(len(masks)) # 추론한 대상이 몇 개인지
print(type(masks.xy), len(masks.xy)) # 찾은 object의 point 좌표들을 리스트로 리턴.
print(type(masks.xy[0]), masks.xy[0].shape) # [0]: 첫번째 object. (374:점개수, 2:좌표)
print(type(masks.xy[-1]), masks.xy[-1].shape)

 

 

첫번째 대상(처음으로 검출된)의 좌표점을 시각화

# 첫번째 대상의 좌표점을 시각화
obj = np.zeros(result.orig_shape, dtype='uint8')

idx = masks.xy[0].astype('int')
y_idx, x_idx = idx[:, 0], idx[:, 1]
obj[x_idx, y_idx] = 255

plt.imshow(obj, cmap='gray')
plt.show()

 

 

 

# Masks, Boxes, Keypoints ==> Iterable ==> for in 에서 사용할 수 있는 반복가능 객체
# 여러 object를 찾은 결과 Masks를 for in 으로 조회하면 개별 object의 결과를 가진 Masks가 반환.
len(masks.xy)
for xy in masks.xy:
    print(xy.shape)

 

 

 

# masks: 찾은 모든 object
# mask: 개별 object
for mask in masks:
    print(type(mask), len(mask.xy), mask.xy[0].shape)
    
    
# boxes: 전체 찾은 object들, box: 개별 object
for box in boxes:
    print(type(box), box.xyxy.shape, box.cls.shape, box.conf.shape)

 

 

bus.jpg 물체의 경계를 찾기.(segment)

# bus.jpg 물체의 경계를 찾기.(segment)

import cv2
from ultralytics import YOLO

# 모델 생성
model = YOLO("models/yolov8m-seg.pt")
# 추론
result = model("02_test_image_seg/bus.jpg")[0]

# 원본 이미지 크기
shape = result.orig_shape
# print(shape) # height, width
# 추론 결과를 그릴 원소가 모두 0이고 원본이미지와 같은 크기의 배열
arr = np.zeros(shape, dtype="uint8")
object_mask = np.zeros(shape, dtype="uint8") # 찾은 사람들의 pixcel을 표시하는 마스크. (사람들만 추출하기 위해 사용.)
background_mask = np.full(shape, fill_value=255, dtype='uint8') # 배경 마스크

# 추론 결과
masks = result.masks # segmentation 결과
boxes = result.boxes # detection 결과

for mask, box in zip(masks, boxes): # mask: 개별 Object
    if box.cls.item() == 0: # 찾은 object가 person이라면
        xy = mask.xy[0].astype('int')   # mask.xy: list. 1개 object결과이므로 length=1
        # 찾은 point들 연결
        cv2.polylines(arr, [xy], isClosed=True, color=(255,255,255), thickness=2) # isClosed=True -> 끝점도 연결(default=False)
        # object mask 생성
        cv2.fillPoly(object_mask, # 그릴 대상
                     [xy], # 다각형의 꼭지점들
                     255  # 다각형 안쪽을 채울 값
                    )
        cv2.fillPoly(background_mask, [xy], 0)

imshow(cv2.resize(background_mask, (0,0), fx=0.5, fy=0.5))

 

 

찾은 instance만 따내기

# 찾은 instance만 따내기
person_img = cv2.bitwise_and(result.orig_img, result.orig_img, mask=object_mask)

imshow(cv2.resize(person_img, (0,0), fx=0.5, fy=0.5))

 

 

background_img를 blur

- 배경을 흐리게

# 배경 아웃포커싱
background_img = cv2.bitwise_and(result.orig_img, result.orig_img, mask=background_mask)
# imshow(cv2.resize(background_img, (0,0), fx=0.5, fy=0.5))

# background_img를 blur
blur_background_img = cv2.GaussianBlur(background_img, ksize=(0,0), sigmaX=5)
# imshow(cv2.resize(blur_background_img, (0,0), fx=0.5, fy=0.5))

# 최종결과
result_img = np.where(background_mask[..., np.newaxis]!=0, blur_background_img, result.orig_img)

imshow(cv2.resize(result_img, (0,0), fx=0.5, fy=0.5))

 

 

bitwise_and

# bitwise_and(img1, img2 [, mask]) -> img2과 img2의 공통부분만 추출, 다른 부분은 0을 반환, mask=> 추출할 영역
# img1과 img2의 shape은 같아야 한다.
a = np.array([1, 2, 3, 100, 500])
b = np.array([100, 2, 300, 1, 500])
m = np.array([0, 255, 0, 0, 0], dtype='uint8') # mask: 이진마스크 - (0과 255 두 개 값으로 구성.) 결과는 255가 있는 index의 결과만 사용한다.
cv2.bitwise_and(a, b, mask=m)