Object Detection

현서·2025년 8월 19일

컴퓨터 비전

목록 보기
3/16
post-thumbnail

1. Object Detection

Object Detection(객체 탐지)은 이미지나 영상에서 특정 객체의 존재 여부를 확인하고, 해당 객체의 위치를 바운딩 박스(bounding box)로 표시하는 기술이다.

이를 통해 이미지 내에서 여러 개의 객체를 동시에 탐지하고 분류할 수 있다.

Object Detection은 주로 딥러닝 기반의 CNN(합성곱 신경망) 모델을 활용한다.

대표적인 알고리즘 : R-CNN 계열(Faster R-CNN, Mask R-CNN), YOLO(You Only Look Once), SSD(Single Shot MultiBox Detector) 등.

1-1. 전통적인 기법

HOG(Histogram of Oriented Gradients) + SVM(Support Vector Machine), Haar Cascade, Selective Search 등의 방법을 사용하여 특징을 추출하고 객체를 탐지하는 방식이다. 하지만 최근에는 딥러닝 방식이 더 우수하여 잘 사용되지 않는다.

1-2. 딥러닝 기반 기법

2단계 탐지(Two-Stage Detection):

Two-Stage Detection은 두 단계로 객체를 찾는 방식이다.
첫 번째 단계에서는 이미지에서 "어디에 객체가 있을 것 같은지" 후보 영역(Region Proposal)을 찾는다.

ex) Faster R-CNN에서는 Region Proposal Network(RPN)이 다양한 위치에서 객체가 있을 가능성이 높은 영역을 예측한다.
두 번째 단계에서는 이 후보 영역들을 하나씩 분석하여 "이것이 어떤 객체인지" 분류하고, 바운딩 박스를 정밀하게 조정한다.
→ 두 번에 걸쳐 탐지하기 때문에 정확도가 높지만 속도는 상대적으로 느릴 수 있다.

1단계 탐지(One-Stage Detection):

One-Stage Detection은 객체를 찾을 때 한 번의 과정만 거치는 방식이다.
이미지를 입력받으면, 네트워크가 바로 객체의 위치(바운딩 박스)와 종류(클래스)를 동시에 예측한다.

대표적인 알고리즘 : YOLO(You Only Look Once)와 SSD(Single Shot MultiBox Detector)

→ 한 번에 예측하기 때문에 속도가 빠르지만, 정확도는 Two-Stage Detection보다 다소 낮을 수 있다.
→ 실시간 객체 탐지가 중요한 자율주행, 영상 감시, 드론 탐색 등에서 많이 활용된다.


2. YOLO

YOLO(You Only Look Once)는 이미지 전체를 한 번에 처리해 객체의 위치와 종류를 동시에 예측하는 실시간 객체 탐지 알고리즘이다.
빠른 속도와 높은 효율성이 특징이다.
최신 버전인 YOLO8은 이전 모델들보다 개선된 네트워크 구조와 최적화된 학습 기법을 적용해 정확도와 속도를 크게 향상시켰으며, 특히 작은 객체나 복잡한 배경에서도 강력한 탐지 성능을 보인다.

2-1. YOLOv8 모델 크기별 분류

  • n (nano): 초경량 모델, 모바일 및 임베디드 장치에서 사용하기 적합하다.
  • s (small): 속도가 빠르면서도 정확도가 준수하여 실시간 추론이 필요한 경우 사용한다.
  • m (medium): 균형 잡힌 모델로 중간 정도의 성능과 속도를 제공한다.
  • l (large): 높은 정확도를 요구하는 애플리케이션에서 사용한다.
  • x (extra-large): 최대 성능을 발휘하지만, 속도가 상대적으로 느리다.

2-2. YOLOv8 모델 유형별 분류

  • YOLOv8 Detect

    • 가장 일반적인 객체 탐지 모델, 특정 객체의 위치와 크기를 바운딩 박스로 반환한다.
    • yolov8n.pt, yolov8s.pt, yolov8m.pt, yolov8l.pt, yolov8x.pt 형태로 제공된다.
  • YOLOv8 Segment

    • 객체 탐지뿐만 아니라 픽셀 단위의 분할(Segmentation)까지 수행하는 모델이다.
    • 바운딩 박스뿐만 아니라 객체 마스크까지 제공한다.
    • yolov8n-seg.pt, yolov8s-seg.pt 등의 형태로 제공된다.
  • YOLOv8 Pose

    • 사람의 관절 위치를 탐지하여 포즈를 예측하는 모델이다.
    • ex) 사람의 팔, 다리, 머리 등의 관절을 찾아낼 수 있다.
    • yolov8n-pose.pt, yolov8s-pose.pt 등의 형태로 제공된다.
  • YOLOv8 Classify

    • 이미지에서 객체를 분류하는 모델이다.
    • 기존의 CNN 기반 분류 모델(ResNet, EfficientNet 등)과 유사한 역할을 합니다.
    • yolov8n-cls.pt, yolov8s-cls.pt 등의 형태로 제공됩니다.

2-3. 역사

  • YOLO는 2015년 Joseph Redmon가 처음 출시한 이후 컴퓨터 비전 커뮤니티에 의해 성장
  • 초기버전(1~4)에서의 YOLO는 딥러닝 프레임워크인 Darknet에서 유지
  • YOLOv3 레포를 파이토치로 작성하여 Ultralytics에서 YOLOv5를 출시
  • YOLOv5 SOTA(State Of The Art, 최신 기술 수준 / 최고 성능을 달성함) 레포가 되었음
  • Ultralytics는 2023년 1월에 YOLOv8을 출시
  • Ultralytics 공식 사이트
  • YOLOv8 아키텍처

3. PascalVOC 2007

PascalVOC 2007은 객체 탐지(Object Detection), 분할(Segmentation), 동작 인식(Action Recognition) 등의 다양한 컴퓨터 비전 과제를 위한 벤치마크 데이터셋이다.

총 20개의 객체 클래스(예: 사람, 자동차, 개, 고양이 등)를 포함하며,
훈련(train), 검증(val), 테스트(test) 세트로 구성되어 있다.

각 이미지에는 객체의 경계 상자(Bounding Box) 및 해당 클래스 레이블이 주어지며, Mean Average Precision(mAP) 평가 기준을 적용하여 성능을 측정한다.


4. YAML 파일

YAML 파일은 모델 구성, 데이터 경로, 하이퍼파라미터 등을 정의하는 설정 파일이다.
모델 학습과 추론을 자동화하는 데 중요한 역할을 한다.

주로 data.yaml과 model.yaml 같은 파일이 있다.

  • data.yaml은 학습 및 검증 데이터셋의 경로, 클래스 개수, 클래스 이름 등을 정의한다.
  • model.yaml은 네트워크 구조(레이어, 채널 수, 활성화 함수 등)를 설정한다.

YAML 형식은 가독성이 뛰어나고 계층적 구조를 쉽게 표현할 수 있어 YOLO의 설정을 직관적으로 관리할 수 있으며, 이를 통해 사용자 맞춤형 모델을 효율적으로 구축할 수 있다.

path: /content/pascal_datasets/VOC
train:
  - images/train2007
val:
  - images/val2007
test:
  - images/test2007

nc: 20
names: ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog',
        'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']

5. 객체 탐지 모델의 성능 평가 지표

5-1. 정밀도(Precision)

객체 탐지 모델이 예측한 객체 중 실제로 정답인 객체의 비율을 의미한다.

Precision = (TP) / (TP + FP)
TP(True Positive) : 모델이 올바르게 탐지한 객체 수
FP(False Positive) : 잘못 탐지한 객체 수
→ 정밀도가 높을수록 모델이 잘못된 탐지를 덜 한다는 의미이다.

5-2. 재현율(Recall)

실제 존재하는 객체 중에서 모델이 올바르게 탐지한 객체의 비율을 의미한다.
놓치지 않고 얼마나 많은 객체를 찾았는지를 평가하는 것이다.

Recall = (TP) / (TP + FN)
FN(False Negative) : 모델이 놓친 실제 객체 수
→ 재현율이 높을수록 모델이 더 많은 객체를 탐지하지만, 종종 잘못된 탐지(FP)도 많아질 수 있다.

5-3. AP(Average Precision)

특정 클래스에 대해 Precision-Recall 곡선을 기반으로 평균 정밀도를 계산한 값이다.
AP는 Recall을 0에서 1까지 변화시키면서 Precision을 계산한 후 평균을 내는 방식으로 구한다.
객체 탐지 모델의 성능을 측정하는 대표적인 방법이며, 보통 특정 IoU 기준에서 계산된다.(예: AP@IoU=0.5는 IoU가 0.5 이상인 경우에 대해 AP를 구함)

5-4. IoU(Intersection over Union)

예측된 바운딩 박스와 실제 객체의 바운딩 박스가 얼마나 겹치는지를 나타내는 값이다.
IoU는 두 박스가 겹치는 영역의 면적을 두 박스의 총 합집합 면적으로 나누어 계산한다.
값이 1에 가까울수록 예측 박스와 실제 박스가 거의 일치한다는 뜻이며,
보통 객체 탐지 성능 평가에서 특정 임계값(예: IoU ≥ 0.5)을 기준으로 모델의 정확도를 평가한다.

5-5. mAP(mean Average Precision)

여러 클래스에 대한 AP 값을 평균 낸 값으로, 전체 모델의 객체 탐지 성능을 평가하는 종합적인 지표이다.
전체 데이터셋에 포함된 모든 클래스의 성능을 반영하며,
다양한 IoU 임곗값(예: 0.5~0.95)에 대해 평균을 내기도 한다.
→ 높은 mAP 값은 모델이 다양한 클래스의 객체를 정확하게 탐지한다는 것을 의미한다.

5-6. mAP@50

IoU(Intersection over Union)가 0.5(50%) 이상이면 정답으로 인정하고 계산한 평균 정밀도이다.
→ 모델이 대략적인 위치라도 맞추면 성능이 좋게 나온다.

5-7. mAP@50-95

IoU를 0.5부터 0.95까지 0.05 간격으로 변화시키면서 성능을 평가한 평균 정밀도아다.
→ 객체의 위치를 더욱 정확하게 맞춰야 높은 점수를 받기 때문에 더 엄격한 기준이다.


# PascalVOC 2007 Train/Val 다운로드
# train: 2501장, val: 2510장
!wget http://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar
# test: 4952장
!wget http://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar
# 파일 및 디렉토리 경로를 객체 지향적으로 다룰 수 있는 모듈
from pathlib import Path
root = Path('./pascal_datasets')
# train/val, test 디렉토리 생성
Path('./pascal_datasets/trainval').mkdir(parents=True, exist_ok=True)
Path('./pascal_datasets/test').mkdir(parents=True, exist_ok=True)
# VOC/images, VOC/labels 하위에 train2007, val2007, test2007 디렉토리 생성
for path1 in ('images', 'labels'):
    for path2 in ('train2007', 'val2007', 'test2007'):
        # ./pascal_datasets/VOC/images/train2007
        new_path = root / 'VOC' / path1 / path2
        new_path.mkdir(parents=True, exist_ok=True)
# tar 압축 해제
!tar -xvf VOCtrainval_06-Nov-2007.tar -C ./pascal_datasets/trainval/
!tar -xvf VOCtest_06-Nov-2007.tar -C ./pascal_datasets/test/
# 압축 내부에 zip 파일이 있으므로 추가로 해제
%cd /content/pascal_datasets/trainval
!unzip -q VOCtrainval_06-Nov-2007.zip
%cd /content/pascal_datasets/test
!unzip -q VOCtest_06-Nov-2007.zip
%cd /content/pascal_datasets

VOC → YOLO 형식 변환

# 어노테이션을 YOLO 형식으로 변환
!git clone https://github.com/ssaru/convert2Yolo.git
%cd /content/pascal_datasets/convert2Yolo
%pip install -qr requirements.txt

example.py 실행: VOC XML 어노테이션 → YOLO txt 라벨 변환

# datasets: 데이터셋이 VOC 형식임을 지정
# img_path: 이미지 파일 경로
# label: 어노테이션(xml) 경로
# convert_output_path: YOLO 형식으로 변환된 라벨 저장 경로
# img_type: 사용할 이미지 파일 확장자
# manifest_path: 변환 과정에서 사용할 추가적인 정보 파일 저장 경로
# cls_list_file: VOC에서 사용할 클래스 목록이 정의된 파일

!python example.py \
    --datasets VOC \
    --img_path /content/pascal_datasets/trainval/VOCdevkit/VOC2007/JPEGImages \
    --label /content/pascal_datasets/trainval/VOCdevkit/VOC2007/Annotations \
    --convert_output_path /content/pascal_datasets/VOC/labels/train2007 \
    --img_type '.jpg' \
    --manifest_path /content \
    --cls_list_file ./voc.names
!python example.py \
    --datasets VOC \
    --img_path /content/pascal_datasets/test/VOCdevkit/VOC2007/JPEGImages \
    --label /content/pascal_datasets/test/VOCdevkit/VOC2007/Annotations \
    --convert_output_path /content/pascal_datasets/VOC/labels/test2007 \
    --img_type '.jpg' \
    --manifest_path /content \
    --cls_list_file ./voc.names

val.txt에 해당하는 라벨을 val2007 폴더로 이동

# /content/pascal_datasets/trainval/ImageSets/Main/val.txt 파일을 읽어서
# /content/pascal_datasets/VOC/labels/train2007 파일 중 txt 문서에 있는 파일을
# /content/pascal_datasets/VOC/labels/val2007 으로 옮기기

import shutil

path = '/content/pascal_datasets/trainval/VOCdevkit/VOC2007/ImageSets/Main/val.txt'

with open(path) as f:
    image_ids = f.read().strip().split()
    for id in image_ids:
        ori_path = '/content/pascal_datasets/VOC/labels/train2007'
        mv_path = '/content/pascal_datasets/VOC/labels/val2007'
        shutil.move(f'{ori_path}/{id}.txt', f'{mv_path}/{id}.txt')

이미지도 YOLO 구조(images/labels)에 맞게 이동

# /content/pascal_datasets/trainval/VOCdevkit/VOC2007/JPEGImages 와
# /content/pascal_datasets/test/VOCdevkit/VOC2007/JPEGImages 에서
# 이미지를 가져와 디렉토리에 맞게 저장

import os

path = '/content/pascal_datasets'

for folder, subset in ('trainval', 'train2007'), ('trainval', 'val2007'), ('test', 'test2007'):
    ex_imgs_path = f'{path}/{folder}/VOCdevkit/VOC2007/JPEGImages'
    label_path = f'{path}/VOC/labels/{subset}'
    img_path = f'{path}/VOC/images/{subset}'
    print(subset, ": ", len(os.listdir(label_path)))
    for lbs_list in os.listdir(label_path):
        shutil.move(os.path.join(ex_imgs_path, lbs_list.split('.')[0]+'.jpg'),
                    os.path.join(img_path, lbs_list.split('.')[0]+'.jpg'))
train2007 :  2501
val2007 :  2510
test2007 :  4952

YOLO 학습

%cd /content
!pip install ultralytics
from ultralytics import YOLO
# data: 데이터셋 설정 파일
# epochs: 학습 에포크 수
# batch: 배치 크기
# imgsz: 입력 이미지 크기
# device: GPU(0), CPU(-1)
# workers: 데이터 로딩에 사용할 CPU 스레드 수
# name: 학습 결과 저장 폴더명

model = YOLO('yolov8s.pt') # YOLOv8 small 모델 불러오기
# 학습 시작
results = model.train(
    data='custom_voc.yaml',   # 데이터셋 정의(yaml 파일 필요)
    epochs=10,                # 학습 epoch
    batch=32,                 # 배치 크기
    imgsz=640,                # 입력 이미지 크기
    device=-1,                # -1: CPU, 0: GPU
    workers=2,                # 데이터 로딩 쓰레드 수
    name='custom_s'           # 결과 저장 폴더명
)
# 검증 수행
results = model.val(
    data="custom_voc.yaml",  # 데이터셋 설정
    imgsz=640,               # 이미지 크기
    iou=0.5,                 # IoU 임계값
    batch=32,                # 배치 크기
    device=0,                # GPU 사용
    workers=2,               # 데이터 로드 시 병렬 처리할 워커 수
    half=True,               # FP16 연산 활성화 (속도 향상)
    split="test"             # 테스트 데이터셋을 사용
)

print(results)

학습된 모델로 예측

model = YOLO("/content/runs/detect/custom_s3/weights/best.pt")

# 객체 탐지 수행
results = model.predict(
    source="/content/pascal_datasets/VOC/images/custom2007",  # 테스트 이미지 폴더
    imgsz=640,           # 입력 이미지 크기
    conf=0.25,           # 신뢰도(Confidence) 임계값
    device=0,            # GPU 사용 (CPU 사용 시 "cpu")
    save=True,           # 탐지 결과 저장
    save_txt=True,       # 탐지 결과를 txt 형식으로 저장 (YOLO 포맷)
    save_conf=True       # 탐지된 객체의 신뢰도 점수도 저장
)

print(results)

profile
The light shines in the darkness.

0개의 댓글