
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) 등.
HOG(Histogram of Oriented Gradients) + SVM(Support Vector Machine), Haar Cascade, Selective Search 등의 방법을 사용하여 특징을 추출하고 객체를 탐지하는 방식이다. 하지만 최근에는 딥러닝 방식이 더 우수하여 잘 사용되지 않는다.
Two-Stage Detection은 두 단계로 객체를 찾는 방식이다.
첫 번째 단계에서는 이미지에서 "어디에 객체가 있을 것 같은지" 후보 영역(Region Proposal)을 찾는다.
ex) Faster R-CNN에서는 Region Proposal Network(RPN)이 다양한 위치에서 객체가 있을 가능성이 높은 영역을 예측한다.
두 번째 단계에서는 이 후보 영역들을 하나씩 분석하여 "이것이 어떤 객체인지" 분류하고, 바운딩 박스를 정밀하게 조정한다.
→ 두 번에 걸쳐 탐지하기 때문에 정확도가 높지만 속도는 상대적으로 느릴 수 있다.

One-Stage Detection은 객체를 찾을 때 한 번의 과정만 거치는 방식이다.
이미지를 입력받으면, 네트워크가 바로 객체의 위치(바운딩 박스)와 종류(클래스)를 동시에 예측한다.
대표적인 알고리즘 : YOLO(You Only Look Once)와 SSD(Single Shot MultiBox Detector)
→ 한 번에 예측하기 때문에 속도가 빠르지만, 정확도는 Two-Stage Detection보다 다소 낮을 수 있다.
→ 실시간 객체 탐지가 중요한 자율주행, 영상 감시, 드론 탐색 등에서 많이 활용된다.

YOLO(You Only Look Once)는 이미지 전체를 한 번에 처리해 객체의 위치와 종류를 동시에 예측하는 실시간 객체 탐지 알고리즘이다.
빠른 속도와 높은 효율성이 특징이다.
최신 버전인 YOLO8은 이전 모델들보다 개선된 네트워크 구조와 최적화된 학습 기법을 적용해 정확도와 속도를 크게 향상시켰으며, 특히 작은 객체나 복잡한 배경에서도 강력한 탐지 성능을 보인다.
YOLOv8 Detect
YOLOv8 Segment
YOLOv8 Pose
YOLOv8 Classify
PascalVOC 2007은 객체 탐지(Object Detection), 분할(Segmentation), 동작 인식(Action Recognition) 등의 다양한 컴퓨터 비전 과제를 위한 벤치마크 데이터셋이다.
총 20개의 객체 클래스(예: 사람, 자동차, 개, 고양이 등)를 포함하며,
훈련(train), 검증(val), 테스트(test) 세트로 구성되어 있다.
각 이미지에는 객체의 경계 상자(Bounding Box) 및 해당 클래스 레이블이 주어지며, Mean Average Precision(mAP) 평가 기준을 적용하여 성능을 측정한다.
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']
객체 탐지 모델이 예측한 객체 중 실제로 정답인 객체의 비율을 의미한다.
Precision = (TP) / (TP + FP)
TP(True Positive) : 모델이 올바르게 탐지한 객체 수
FP(False Positive) : 잘못 탐지한 객체 수
→ 정밀도가 높을수록 모델이 잘못된 탐지를 덜 한다는 의미이다.
실제 존재하는 객체 중에서 모델이 올바르게 탐지한 객체의 비율을 의미한다.
놓치지 않고 얼마나 많은 객체를 찾았는지를 평가하는 것이다.
Recall = (TP) / (TP + FN)
FN(False Negative) : 모델이 놓친 실제 객체 수
→ 재현율이 높을수록 모델이 더 많은 객체를 탐지하지만, 종종 잘못된 탐지(FP)도 많아질 수 있다.
특정 클래스에 대해 Precision-Recall 곡선을 기반으로 평균 정밀도를 계산한 값이다.
AP는 Recall을 0에서 1까지 변화시키면서 Precision을 계산한 후 평균을 내는 방식으로 구한다.
객체 탐지 모델의 성능을 측정하는 대표적인 방법이며, 보통 특정 IoU 기준에서 계산된다.(예: AP@IoU=0.5는 IoU가 0.5 이상인 경우에 대해 AP를 구함)
예측된 바운딩 박스와 실제 객체의 바운딩 박스가 얼마나 겹치는지를 나타내는 값이다.
IoU는 두 박스가 겹치는 영역의 면적을 두 박스의 총 합집합 면적으로 나누어 계산한다.
값이 1에 가까울수록 예측 박스와 실제 박스가 거의 일치한다는 뜻이며,
보통 객체 탐지 성능 평가에서 특정 임계값(예: IoU ≥ 0.5)을 기준으로 모델의 정확도를 평가한다.
여러 클래스에 대한 AP 값을 평균 낸 값으로, 전체 모델의 객체 탐지 성능을 평가하는 종합적인 지표이다.
전체 데이터셋에 포함된 모든 클래스의 성능을 반영하며,
다양한 IoU 임곗값(예: 0.5~0.95)에 대해 평균을 내기도 한다.
→ 높은 mAP 값은 모델이 다양한 클래스의 객체를 정확하게 탐지한다는 것을 의미한다.
IoU(Intersection over Union)가 0.5(50%) 이상이면 정답으로 인정하고 계산한 평균 정밀도이다.
→ 모델이 대략적인 위치라도 맞추면 성능이 좋게 나온다.
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)


