[260720 15일차] Data, YOLO

2026. 7. 20. 16:40AI 기반 프론트엔드 웹개발자 양성과정

# Data·YOLO 학습일지

[Data, YOLO] 로컬 데이터 수집·증강
YOLO 객체 탐지 기초 + 추적

2026.07.20 · 학습 범위: 데이터(수집·증강·라벨링), YOLO 기초·심화(추적), Teachable Machine, COCO 80클래스, SAM2

📋 오늘 다룬 것들

드디어 AI 객체 탐지에 들어갔다. 먼저 카메라로 직접 데이터를 찍고(로컬 수집), 사진 한 장을 여러 장으로 부풀리는 데이터 증강을 해봤다. 그다음 YOLO로 분류·탐지·자세·분할 4가지 작업을 돌리고, 모델 학습과 과적합 개념, 추론 파라미터 튜닝, 실시간 CCTV 스트림 처리, 마지막으로 심화의 객체 추적(Tracking)까지 훑었다. 코드 한 줄로 물체를 찾아내는 게 신기했다.

데이터
cv2 카메라PIL 증강
YOLO 4대 작업
분류탐지자세분할
학습 개념
train/val과적합트레이드오프
파라미터
confclassessave_txt
실시간
m3u8 스트림putText
심화
추적 trackpersist

📊 데이터 준비

로컬 데이터 수집 (카메라 촬영)

공개 데이터 말고, 컴퓨터에 연결된 웹캠으로 직접 찍어 나만의 데이터셋을 만드는 방법. OpenCV(cv2)로 카메라를 켜고 한 장 찍어 저장한다.

import cv2, os
from datetime import datetime

save_dir = "./captured_images"
os.makedirs(save_dir, exist_ok=True)   # 폴더 없으면 자동 생성

cap = cv2.VideoCapture(0)          # 0 = 첫 번째 카메라
success, frame = cap.read()          # 사진 한 장 읽기
if success:
    ts = datetime.now().strftime('%Y%m%d_%H%M%S')  # 파일명 겹침 방지
    cv2.imwrite(f"{save_dir}/result_{ts}.jpg", frame)
cap.release()                        # 카메라 반드시 해제
VideoCapture(0) 카메라 켜기 → cap.read() 한 장 가져오기 → cv2.imwrite() 파일 저장 → cap.release()로 반드시 끄기(안 끄면 다른 프로그램이 카메라를 못 씀). 파일명에 촬영 시각을 넣으면 여러 장 찍어도 이름이 안 겹친다.

데이터 증강 (이미지 변환)

학습 이미지가 적으면 AI가 특정 각도·밝기에만 익숙해져 틀리기 쉽다. 사진 1장을 회전·밝기·반전으로 변형해 데이터를 늘리는 게 증강이다. PIL로 처리했다.

from PIL import Image, ImageEnhance, ImageOps

img = Image.open("result.jpg")
img_rotated = img.rotate(90)                       # 90도 회전
img_bright  = ImageEnhance.Brightness(img).enhance(0.5) # 밝기 50%
img_flip    = ImageOps.mirror(img)                    # 좌우 반전(거울)

img_rotated.save("./img_rotate.jpg")             # 변환본 저장
회전·밝기·반전 외에도 ImageFilter.BLUR(흐리게), ImageOps.grayscale(흑백), ImageEnhance.Contrast(대비) 등 PIL만으로 10가지 이상 변형이 가능하다. YOLO 학습 땐 증강 이미지를 images/train에, 같은 이름의 라벨(.txt)을 labels/train에 함께 둔다.

데이터 라벨링 (labelImg)

AI 학습용 이미지에 객체 위치를 박스로 표시하고 좌표를 기록하는 작업이 라벨링이다. labelImg는 PC에 설치해 쓰는 무료 오픈소스 도구(웹 기반으로는 Roboflow). 박스를 그리면 YOLO 형식의 .txt 좌표가 저장된다.

# 설치
pip install labelImg

# YOLO 좌표 형식 (.txt) — 한 줄 = 객체 하나, 값은 모두 0~1 정규화
# class  x_center  y_center  width  height
0 0.525 0.376 0.284 0.418   # 클래스번호 x y w h

# classes.txt — 줄 번호 = 클래스 번호
person   # 0번
cat      # 1번
dog      # 2번
정규화(0~1)란? — 픽셀 절대값이 아니라 이미지 크기 대비 비율로 저장한다. x_center = 중심 x ÷ 이미지 너비 식. 그래서 이미지 크기가 달라져도 같은 라벨을 재사용할 수 있다. 클래스 번호는 항상 0부터 시작하고, classes.txt의 줄 순서가 곧 번호다.
🧰 오늘 쓴 도구 라이브러리Pillow(PIL): 이미지 열기·회전·밝기·반전 등 처리(증강에 사용, pip install pillow). schedule: 파이썬 작업을 일정 간격으로 자동 실행(pip install schedule) — 예: schedule.every(10).minutes.do(job)로 10분마다 사진을 자동 촬영해 데이터를 모으는 식으로 활용할 수 있다.

🎯 YOLO 기초

01 — YOLO란?

YOLO(You Only Look Once) = "한 번만 본다". 조셉 레드먼이 만든 오픈소스 객체 탐지 AI로, 이미지·영상 속 사물을 번개처럼 빠르게 찾는다. 자율주행(차·사람·신호 인식), 로봇(물건 집기), 의료(진단 보조) 등에 쓰인다.

02~05 — 네 가지 작업 (분류 · 탐지 · 자세 · 분할)

YOLO는 모델 파일만 바꾸면 같은 4단계 코드로 서로 다른 작업을 한다. 모델 로드 → 추론 → results[0].plot()로 결과 그리기 → cv2.imwrite()로 저장.

from ultralytics import YOLO
import cv2

model = YOLO("yolo11n.pt")             # ① 모델 로드
results = model("input.jpg")          # ② 추론
result_image = results[0].plot()      # ③ 결과 시각화
cv2.imwrite("result.jpg", result_image) # ④ 저장
작업모델 파일무엇을 하나
분류 Classificationyolo11n-cls.pt"이 사진은 강아지" — 사진 1장에 정답 하나
탐지 Detectionyolo11n.pt여러 물체 위치를 네모 박스로 표시
자세 Poseyolo11n-pose.pt사람 관절 17개를 점·선으로 표시
분할 Segmentationyolo11n-seg.pt물체 외곽선을 픽셀 단위로 색칠
모델 크기는 n → s → m → l → x 순 — 작을수록 빠르고, 클수록 정확하다(속도 ↔ 정확도 트레이드오프). 분류는 "전체 사진 하나의 답", 탐지는 "위치까지 박스", 분할은 "박스가 아니라 모양 그대로"가 핵심 차이.

06 — 모델 학습 · 과적합 · 트레이드오프

미리 학습된 yolo11n-cls.pt에 새 클래스를 추가 학습(Fine-tuning)한다. 데이터셋은 train(학습)·val(검증)·test(최종) 3단으로 나눈다.

model = YOLO("yolo11n-cls.pt")
model.train(
    data="dataset",   # train/val 자동 인식
    epochs=2,          # 전체 데이터 반복 횟수
    batch=1,           # 한 번에 처리할 이미지 수
    imgsz=256,         # 입력 이미지 크기
)
val(검증셋)의 역할 — 매 epoch마다 자동 채점하는 모의고사. 가중치를 바꾸진 않고 성능만 측정하며, val 성능이 가장 좋았던 시점을 best.pt로 저장한다. train과 val에 같은 이미지가 섞이면 "시험 문제 유출"이라 점수가 부풀려진다.
과적합(Overfitting) = 모델이 train 이미지를 "외워버린" 상태. 문제집을 통째로 암기한 학생처럼, 본 문제는 100점인데 새 문제는 0점. 증상은 train accuracy ↑인데 val accuracy ↓로 둘의 격차가 벌어지는 것. val loss가 최저점을 찍고 다시 오르기 시작하는 지점이 과적합 시작 신호 → 그 직전의 best.pt를 쓰는 게 정답. 대응책은 epochs 줄이기(EarlyStopping patience), 데이터 증강, 데이터 양 늘리기.
트레이드오프(Trade-off) = 하나를 얻으면 하나를 잃는 관계. 정확도↔속도(큰 모델 vs 작은 모델), imgsz↑↔학습시간↑, batch↑↔메모리↑, epochs↑↔과적합 위험↑. "가장 좋은 설정"은 없고, 하드웨어·시간·목표에 맞춰 균형점을 실험으로 찾는 게 학습의 본질이다.

07~09 — 추론 파라미터 튜닝

model()에 파라미터를 넣어 결과를 세밀하게 제어한다. model.names로 클래스 목록(ID↔이름)을 먼저 확인하고 원하는 것만 탐지할 수 있다.

model(
    "input.jpg",
    save=True,       # 결과 자동 저장
    conf=0.5,        # 신뢰도 50% 이상만 (기본 0.25)
    max_det=3,        # 최대 탐지 개수
    save_crop=True,   # 탐지 영역만 잘라 저장
    save_txt=True,    # 좌표를 txt로 저장
    save_conf=True,   # txt에 신뢰도 점수까지 저장
    classes=[0, 2],  # 0=person, 2=car 만 탐지
)
내가 헷갈렸던 것 — save_conf — 좌표 텍스트를 저장할 때 각 줄 끝에 신뢰도 값을 하나 더 붙이는 옵션이다. 그래서 save_txt=True짝으로 켜야 의미가 있다(저장되는 txt가 없으면 효과도 없음). classes=[60, 75]처럼 번호만 주면 dining table·vase만 골라 탐지된다.

10 — HTTP 실시간 CCTV 스트림 (m3u8)

웹캠 번호 대신 m3u8 주소VideoCapture에 넣으면 인터넷 CCTV를 실시간으로 받는다. m3u8은 영상을 수 초 단위 조각으로 쪼개 순서대로 받는 HLS(HTTP Live Streaming) 재생목록으로, 유튜브 라이브·OTT와 같은 방식이다.

stream_url = "http://210.99.70.120:1935/live/cctv009.stream/playlist.m3u8"
cap = cv2.VideoCapture(stream_url)

while cap.isOpened():
    success, frame = cap.read()
    if not success: break
    results = model(frame)
    cv2.imshow("CCTV", results[0].plot())
    if cv2.waitKey(1) & 0xFF == ord('q'):  # q 누르면 종료
        break
cap.release(); cv2.destroyAllWindows()
cv2.waitKey(1) & 0xFF == ord('q') 풀이 — "1ms 동안 키 눌렸나? 'q'면 종료". waitKey(1)은 1ms 키 입력 대기(없으면 영상이 안 보임), ord('q')는 'q'의 번호(113). & 0xFF는 일부 환경에서 키 번호 앞에 붙는 쓸데없는 비트를 잘라 하위 8비트(0~255)만 남기는 안전장치 — 그래야 어떤 컴퓨터에서든 113 == 113 비교가 성립한다.

11 — 영상에 글자 표시 (putText)

탐지 결과(객체 수·상태)를 프레임 위에 그려 CCTV 알람 UI처럼 만든다. cv2.putText는 매개변수 순서가 고정이다.

count = len(results[0].boxes)          # 탐지 객체 수
status, color = ("Warning", (0,0,255)) if count >= 5 else ("Safe", (255,0,0))
cv2.putText(
    frame,                       # ① 그릴 영상
    f"Detected: {count}, {status}", # ② 문자열
    (10, 30),                    # ③ 좌표 (x, y)
    cv2.FONT_HERSHEY_SIMPLEX,    # ④ 폰트
    1, color, 2,                 # ⑤크기 ⑥색 ⑦두께
    cv2.LINE_AA                  # 안티앨리어싱(글자 매끈)
)
색은 BGR 순서! — OpenCV는 B(파랑)→G(초록)→R(빨강) 순으로 색을 쓴다. 그래서 (255,0,0)은 빨강이 아니라 파랑, (0,0,255)가 빨강이다. 일반 RGB와 순서가 반대라 계속 헷갈렸다.

COCO 80 클래스 (coco.yaml)

YOLO 사전학습(pretrained) 모델은 COCO 데이터셋의 80개 클래스로 학습돼 있다. classes=[0, 2]처럼 걸러낼 때 쓰는 번호가 바로 이 목록이고, 전체는 coco.yaml 또는 model.names로 확인한다.

번호이름번호이름
0person (사람)15cat (고양이)
1bicycle (자전거)16dog (강아지)
2car (자동차)60dining table (식탁)
3motorcycle (오토바이)75vase (꽃병)
......79toothbrush (칫솔)
번호는 0부터 79까지 고정이라, 다른 사람이 짠 코드도 classes=[0]이면 "사람만"이라는 뜻으로 통한다. 내가 만든 커스텀 모델은 이 목록이 아니라 학습 때 지정한 classes.txt 순서를 따른다.

🧪 직접 학습시키기 — Teachable Machine

코드 없이 브라우저에서 바로 모델을 학습시켜 보는 Google Teachable Machine도 써봤다. 이미지·소리·자세 모델을 웹에서 만들 수 있는데, 오늘은 이미지 분류를 해봤다.

1클래스 만들기분류할 종류(예: Happy·Sad·Normal)별로 클래스 생성
2샘플 수집웹캠으로 즉석 촬영하거나 이미지 업로드로 예시 모으기
3학습"Train Model" 클릭 — 브라우저 안에서 바로 학습(코드 X)
4내보내기TensorFlow·TFLite 등으로 export해 실제 앱에 사용
YOLO 학습과 비교 — YOLO의 model.train()이 코드로 하는 학습이라면, Teachable Machine은 같은 원리(예시 → 학습 → 예측)를 클릭만으로 체험하는 도구다. 데이터가 많고 클래스가 균형 잡힐수록 잘 맞힌다는 점, 과적합·일반화 개념이 그대로 적용된다는 점은 동일하다. "학습이 뭔지" 감을 잡기에 좋았다.

🚀 YOLO 심화

01 — 객체 추적 (Tracking)

탐지는 매 프레임 물체를 새로 찾지만, 추적은 물체마다 고유 번호(ID)를 붙여 계속 따라간다. 사람 1번이 화면 밖으로 나갔다 다시 들어와도 같은 1번으로 인식한다. model() 대신 model.track()을 쓰는 게 핵심.

results = model.track(frame, persist=True, conf=0.6)
# persist=True → 이전 프레임 정보 유지(같은 ID로 추적)
# conf=0.6    → 60% 이상 확신할 때만 탐지
annotated_frame = results[0].plot()

cv2.namedWindow("YOLO_TRACKING", cv2.WINDOW_NORMAL) # 창 크기 조절 가능
cv2.imshow("YOLO_TRACKING", annotated_frame)
탐지 vs 추적 — 탐지(detect)는 매 프레임 독립적이라 ID가 없고, 추적(track)은 프레임을 이어 붙여 같은 물체에 같은 ID를 유지한다. persist=True가 "이전 프레임을 기억해라"는 스위치다.

🔗 수업에서 소개된 참고 링크

오늘 강사님이 참고하라고 알려준 사이트·문서들을 모아뒀다. 실습에 직접 쓴 것도, 앞으로 볼 자료도 함께 정리한다.

자료용도링크
Teachable Machine노코드로 직접 모델 학습(이미지·소리·자세)teachablemachine.withgoogle.com
labelImg데이터 라벨링 도구 (pip install labelImg)github.com/HumanSignal/labelImg
COCO 80 클래스YOLO 사전학습 모델의 클래스 번호↔이름 목록ultralytics · coco.yaml
schedule파이썬 작업 주기 실행 (pip install schedule)pypi.org/project/schedule
Pillow (PIL)이미지 처리·증강 (pip install pillow)pypi.org/project/pillow
SAM 2Meta의 영상 세그멘테이션 모델docs.ultralytics · SAM 2 · 데모
SAM 2(Segment Anything Model 2)는 별도 학습 없이 물체를 픽셀 단위로 분할하고, 영상에서는 프레임이 넘어가도 같은 객체를 기억하며 따라가는 Meta의 모델이다.

✍️ 마치며

파이썬 문법을 배운 지 얼마 안 됐는데, 오늘은 그 문법으로 진짜 AI를 돌려봤다는 게 가장 크게 남았다. YOLO("yolo11n.pt") 한 줄에 이미지 경로만 넣으면 물체를 찾아 박스를 그려주는 게 신기하면서도, 뒤에 있는 train/val·과적합·트레이드오프 같은 개념을 알아야 "왜 이 모델을 이렇게 쓰는지" 이해된다는 걸 느꼈다. BGR 색 순서나 & 0xFF처럼 사소하지만 안 알면 계속 틀리는 것들도 오늘 확실히 짚었다. 다음엔 직접 모은 데이터로 나만의 분류 모델을 학습시켜 볼 예정이다.

🏷️ YOLO  |  OpenCV  |  객체탐지  |  데이터  |  AI  |  학습일지