본문 바로가기

Data_Analysis_Track_33/Python

Python_Computer_vision_01(yolov8_object_detection)

사전 작업(YOLOv8 설치)

  • pytorch를 먼저 설치
  • pip install ultralytics
  • 주피터노트북에서 실행할 경우 프로그래스바를 실행하기 위해서 다음을 설치한다. (필수는 아님)
        - pip install ipywidgets` or `conda install -y -c conda-forge ipywidgets

 

!pip3 install torch torchvision torchaudio
!pip install ultralytics

 

 

사용

  • CLI (command line interface)에서 터미널 명령어로 추론/평가/학습을 진행할 수 있다.
  • Python lib 를 이용해 코드상에 원하는 추론/평가/학습을 진행할 수 있다.

 

CLI 기본 명령어 구조

 

  • 구문
     - yolo task=detect|classify|segment|pose mode=train|val|predict model=yolov8n.yaml|yolov8n.pt|.. args  
    - task: [detect, classify, segment, pose] 중 하나를 지정한다. [optional]로 생략하면 모델을 보고 추측해서 task를 정한다.
            - detect: Object detection
            - classify: Image classification
            - segment: Instance segmentation
            - pose Pose estimation
    mode: [train, val, predict, export] 중 하나를 지정한다. 필수로 입력해야 한다.
            - train: custom dataset을 train 시킨다.
            - val: 모델 성능을 평가한다.
            - predict: 입력 이미지에 대한 추론을 한다.
            - export: 모델을 다른 형식으로 변환한다.
    model: pretrained 모델이나 모델 설정 yaml 파일의 경로를 설정한다. 필수로 입력해야 한다.
            - pretrained 모델 파일경로
                - task에 맞는 pretrained 모델파일의 저장 경로를 지정한다.
                - transfer learnging을 하거나 fine tuning 시 방법
            - 모델 구조 설정 yaml 파일 경로
                - task에 맞는 pretrained 모델 설정파일(yaml파일)의 경로를 지정한다.
                - train mode에서 지정하며 모델을 새로 생성해서 처음부터 학습 시킬 경우 지정한다.
            - Ultralytics에서 제공하는 Pretrained 모델
                - 모델 크기에 따라 5개의 모델을 제공하며 큰 모델은 작은 모델에 비해 추론 성능이 좋은대신 속도는 느리다.
                - 모델은 처음 추론또는 학습할때 local 컴퓨터에 없으면 download 받는다.
                - https://github.com/ultralytics/ultralytics#models                                                                                                        - 확장자가 pt이면 pretrained 된 모델을, yaml이면 모델 구조 설정파일을 download하여 실행한다.
                  - pretrained model은 fine tuning이나 추론할 때, yaml설정파일은 처음부터 학습할 경우 설정하여 받는다.
  • args: task와 mode과 관련한 추가 설정값들을 지정한다.
                - https://docs.ultralytics.com/cfg/

제공 모델

 

 

Object Detection

Predict (추론)

모델로딩

  • Ultralytics에서 제공하는 Pretrained Model이나 직접 학습시킨 모델을 이용해 추론한다.
  • Ultralytics는 Object Detection을 위한 Pretrained 모델을 제공한다.
        - Object Detection 모델은 COCO dataset으로 학습되었다.
        - 모델 명을 지정하면 자동으로 다운로드를 받는다.

 

CLI

yolo task=detect mode=predict model=model_path source=추론할_image_path


- 추가 설정 (configuration)
    - https://docs.ultralytics.com/cfg

    - argument 설정은 name=value 형식으로 한다. (--name value나 name value 는 안된다.)

 

추론 할 Source 타입

 

yolo 형식

yolo task=detect     # 어떤 작업을 할지
     mode=predict    # 그 작업안에서 어떤 일을 할지
     model=models/yolov8s.pt # fine tuning시 사용할 모델
# 옵션
     source=01_test_image/1.jpg # mode=predict에서 추론할 대상경로
     save=True                  # 결과를 표현한 이미지 저장 여부
     save_txt=True              # 결과 라벨파일 저장 여부
     line_width=1               # bounding box(bbox) 선 굵기
     conf=0.7                   # confidence threshold (c_score가 지정한 값 이상인 것만 표현)

 

 

yolo를 통해 사진 detection

- jupyter lab으로 실행

- CLI사용시 코드에서 !빼기

- save=True -> 결과 파일이 runs 디렉토리에 저장된다.

!yolo task=detect mode=predict model=models/yolov8s.pt source=01_test_image/1.jpg save=True save_txt=True line_width=1 conf=0.7

 

 

yolo를 통해 동영상 detection

!yolo task=detect mode=predict model=models/yolov8n.pt source=01_test_image/indo_street.mp4 save=True

 

 

yolo를 통해 webcam detection

!yolo task=detect mode=predict model=models/yolov8n.pt source=0 show=True # 정수-web cam id

python ultralytics version 확인

import ultralytics
from ultralytics import YOLO # 모델 클래스

ultralytics.__version__

 

 

모델 생성하여 임의의 사진 추론하기

- 사전학습된 모델파일의 경로를 지정한다. (없으면 다운로드한다.)

- 추론할 사진의 경로를 지정

# 모델 생성
model = YOLO("models/yolov8n.pt") # 객체 생성시 pretrained 모델파일의 경로를 지정. (없으면 다운로드)
                                  # task => 설정한 모델 파일에 따라서 결정.

# 추론
image_path = "01_test_image/1.jpg"
results = model(image_path) # 추론 -> 필요한 설정들을 파라미터로 지정.

 

 

추론한 사진 결과 확인하기

- plt 활용

import matplotlib.pyplot as plt
import cv2

plt.imshow(results[0].plot()[:,:,::-1]) # 원본이미지에 추론 결과를 표시한 결과 이미지를 반환. (ndarray: bgr모드)

 

 

- cv2 활용

cv2.imshow("f", results[0].plot())
cv2.waitKey()
cv2.destroyAllWindows()

 

 

임의의 web의 이미지 경로를 지정하여 사진 추론

# web상 이미지 추론 -> url 지정
url = "https://cdn.jejusori.net/news/photo/201906/303604_304163_245.jpg"
r = model(url, save=True)

 

 

한번에 여러장 추론하기

  • 이미지들이 있는 디렉토리 경로를 전달.
  • 추론할 파일경로를 리스트로 묶어서 추론한다.
        - 이 경우 추론성능이 좋지 않은 경우가 생긴다. (YOLO 초기버전의 경우, 현재는 상관X)

 

glob 활용

- /* -> 01_test_image 디렉토리 안의 모든 jpg파일을 지정

from glob import glob
img_list = glob("01_test_image/*.jpg")
img_list

 

 

여러장 추론하기

- Results saved to runs\detect\predict2 -> 결과가 디렉토리에 저장된다.

# 리스트로 여러장 추론
r = model(img_list, save=True)

 

 

경로 지정을 통한 여러장 추론

# 경로 지정을 통한 여러장 추론
r2 = model("02_test_image/", save=True)

 

 

동영상

  • source에 동영상 파일 경로를 지정한다.
        - frame 단위로 추론한다.

 

동영상 frame 단위로 추론 및 저장

- save=True -> 디렉토리에 저장한다.

- show=True -> 추론한 동영상 출력

r = model("01_test_image/indo_street.mp4", save=True, show=True)

 

 

len(r) -> frame 수가 출력된다.

len(r) # 350 -> frame

 

 

[:,:,::-1] -> BGR2RGB

plt.imshow(r[-1].plot()[:,:,::-1]);

 

 

추론결과

ultralytics.yolo.engine.results.Results

  • 모델의 추론 결과는 list에 이미지별 예측결과를 Results에 담아 반환한다.
  • Results : 한개 이미지에 대한 추론결과를 담는 객체
  • 추론 종류에 따라 다음 속성을 이용해 결과를 조회한다.
        - Detection: result.boxes - Boxes type
        - Segmentation: result.masks - Masks type
        - Classification: result.probs - torch.Tensor type
        - Pose estimator: result.keypoints - Keypoints  type
  • 추가 정보
        - Results.orig_img: 추론한 원본 이미지
        - Results.orig_shape: 추론한 원본 이미지의 크기 (height, width)
        - Results.path: 추론한 원본이미지의 경로
        - Results.names: class2classname 정의한 딕셔너리 (key: 클래스, name: 클래스 이름)
  • 메소드
        - Results.plot(): 원본 이미지에 추론결과를 표현한 이미지를 ndarray로 반환. (opencv를 이용해서 만들기 때문에 BGR 모드로 반환)

 

from ultralytics import YOLO

model = YOLO("models/yolov8s.pt")
result_list = model("01_test_image/1.jpg", conf=0.7)

 

 

print('총 이미지수:', len(result_list))
result = result_list[0] # 첫번째 이미지에 대한 결과
print(type(result))

 

 

print("원본이미지 경로:", result.path)
print("원본이미지 size:", result.orig_shape) # (height, width)
print("원본이미지:", type(result.orig_img), result.orig_img.shape, result.orig_img.dtype)
import matplotlib.pyplot as plt

plt.imshow(result.orig_img[:,:,::-1]); # [:,:,::-1]: BGR -> RGB

 

 

pprint

# class
from pprint import pprint # 자료구조를 보기좋게 출력하는 함수(정렬).
pprint(result.names) # key: index(class), name: class name ===> 모델이 학습한 데이터의 idx2class를 반환

 

 

Object Detection 결과값 조회

  • 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 (그 물체일 확률)

 

  • 0차원 torch.Tensor 를 상수로 변환
         - tensor.item()
  • N차원 torch.Tensor를 ndarray로 변환
         - tensor.numpy()
         - Tensor객체가 GPU메모리에 있을 경우 메인메모리(CPU)로 먼저 옮겨야 한다.
             - tensor.to('cpu')` or `tensor.cpu()

 

bbox 위치와 object class

# result = result_list[0]
boxes = result.boxes
print(type(boxes)) # Object Detection 결과 -> bbox 위치와 object class

 

 

찾은 object 정보

# 찾은 object 정보
print(boxes.cls.shape) # boxes.cls: object class(index) => [8] => 찾은 object가 8개. 8개 class
print(boxes.cls)

 

 

찾은 object의 class 확률.

print(boxes.conf.shape) # 찾은 object의 class 확률.
boxes.conf

 

 

찾은 object의 class명과 확률

for c, p in zip(boxes.cls, boxes.conf):
    print(f"{int(c)} - {result.names[c.item()]}, {p*100:.3f}%")

 

 

bbox 위치 - xyxy : 좌상단 x,y, 우하단 x,y 좌표

- shape: [8: 찾은 object 개수, 4: 좌표-좌상단xy, 우하단xy]

# bbox 위치 - xyxy : 좌상단 x,y, 우하단 x,y 좌표
print(boxes.xyxy, boxes.xyxy.shape, sep="\n") # shape: [8: 찾은 object 개수, 4: 좌표-좌상단xy, 우하단xy]

 

 

xyxyn

- 0 ~ 1 normalize(정규화) -> 이미지 크기 대비 비율.

print(boxes.xyxyn, boxes.xyxyn.shape, sep="\n") # 0 ~ 1 normalize(정규화) -> 이미지 크기 대비 비율.

 

 

 bbox 위치 - xywh : center x y 좌표, bbox의 너비, 높이

# bbox 위치 - xywh : center x y 좌표, bbox의 너비, 높이
print(boxes.xywh, boxes.xywh.shape, sep="\n")
print(boxes.xywhn, boxes.xywhn.shape, sep="\n") # xywhn => normalize

 

 

bbox를 활용한 이미지 추론

# 원본 이미지에 bbox를 치고 class를 출력
import cv2
from ultralytics import YOLO

# 1. 모델 생성
model = YOLO("models/yolov8s.pt")
# 2, 추론
result_list = model("01_test_image/1.jpg", conf=0.7)
# 3. 추론결과를 이용한 추가 작업 ==> bbox 그리기.

result = result_list[0]

# 원본이미지를 복사
org_img = result.orig_img
img = org_img.copy()

# bbox 추론결과를 조회
boxes = result.boxes
xyxy_list = boxes.xyxy # 좌상단, 우하단 좌표(bbox 위치)
cls_list = boxes.cls   # class index
conf_list = boxes.conf # class 확률

for xyxy, cls, conf in zip(xyxy_list, cls_list, conf_list):
    pt1 = xyxy[:2].to("cpu").numpy().astype("int32") # 좌상단만 가져와서 numpy로 변환 !tensor -> ndarray로 변환시 -> CPU로 이동시킨 후 변환이 가능하다.
    pt2 = xyxy[2:].to("cpu").numpy().astype("int32") # 우하단 좌표
    cls_name = result.names[int(cls.item())] # list의 index는 정수여야 한다.
    txt = f"{cls_name}-{conf.item()*100:.2f}%"

    # image에 bbox
    cv2.rectangle(img, pt1=pt1, pt2=pt2, color=(255, 255, 255), thickness=1)
    # label text
    cv2.putText(img, text=txt, org=pt1-5, fontFace=cv2.FONT_HERSHEY_COMPLEX, fontScale=0.5, color=(255, 255, 255), thickness=1, lineType=cv2.LINE_AA)

# img 출력
cv2.imshow("result", img)
cv2.waitKey()
cv2.destroyAllWindows()

 

 

웹캠 입력 디텍션

import cv2
from ultralytics import YOLO

# 웹캠 연결
cap = cv2.VideoCapture(0)
#### YOLO 모델 생성
model = YOLO("models/yolov8n.pt")

while cap.isOpened():
    # 한 frame(이미지)을 읽기
    succ, frame = cap.read()
    if not succ:
        print("웹캠 연결에 문제가 생겼습니다.")
        break
    # flip(대칭)
    frame = cv2.flip(frame, 1) # 양수: 좌우, 0: 상하, 음수: 상하좌우
    ###############################################
    # YOLO 모델을 이용한 추론 -> 결과 이미지 생성
    ###############################################
    img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # yolo는 rgb 이미지를 학습시킨다.
    
    # 추론. 추론대상이미지타입 - 문자열(경로), Image(ndarray, PIL.Image)
    result = model(img,
                   conf=0.5,  # 확률이 0.5 이상인 것만 결과로 리턴
                   verbose=False)[0] # 추론 결과 로그를 출력하지 않는다.
    
    # 결과에서 위치, 클래스 정보 추출
    ### (찾은 object 개수, shape)
    xyxy_list = result.boxes.xyxy.to("cpu").numpy().astype("int32")
    cls_list = result.boxes.cls.to("cpu").numpy().astype("int32")
    conf_list = result.boxes.conf.to("cpu").numpy()
    
    # for in 문을 이용해 찾은 object 별로 bbox 처리를 한다.
    for xyxy, cls, conf in zip(xyxy_list, cls_list, conf_list):
        pt1, pt2 = xyxy[:2], xyxy[2:]
        txt = f"{result.names[cls]} - {conf*100:.3f}%"
        # box
        cv2.rectangle(frame, pt1, pt2, color=(255, 0, 0), thickness=2)
        cv2.putText(frame, txt, org=pt1, fontFace=cv2.FONT_HERSHEY_COMPLEX, fontScale=1, color=(200,0,0), thickness=1, lineType=cv2.LINE_AA)
    
    # 영상 출력
    cv2.imshow("frame", frame)
    # 중단여부확인
    if cv2.waitKey(1) == 27: # ESC를 입력하면
        break
# 마무리
cap.release() # 웹캠연결 종료
cv2.destroyAllWindows() # 출력 윈도우 종료