성남 프론트엔드

14일차_DATA 수집 ~ YOLO 객체 탐지

sojsoj 2026. 7. 20. 16:43

오늘의 AI 학습 정리: 데이터 수집부터 라벨링, YOLO 활용까지

AI가 이미지 속 사물을 인식하도록 만들기 위해서는 모델만 실행하는 것이 아니라, 데이터를 수집하고 정답을 표시한 뒤 학습과 검증을 거치는 과정이 필요합니다.

전체 과정은 다음과 같습니다.

데이터 수집 → 데이터 증강 → 라벨링 → 모델 학습 → 검증 → 추론 → 실시간 활용


1. AI 학습용 데이터 수집

AI 모델의 성능은 데이터의 양과 품질에 큰 영향을 받습니다. 같은 물체라도 방향, 거리, 크기, 밝기, 배경이 달라질 수 있으므로 다양한 환경에서 촬영한 이미지가 필요합니다.

1-1. 공개 데이터 사이트 이용

직접 모든 이미지를 촬영하기 어렵다면 공개 데이터 사이트를 이용할 수 있습니다.

공개 데이터를 사용할 때는 다음 내용을 확인해야 합니다.

  • 상업적 이용이 가능한가?
  • 데이터를 수정하거나 재배포할 수 있는가?
  • 출처 표시가 필요한가?
  • 얼굴이나 차량 번호판 등 개인정보가 포함되어 있는가?
  • 현재 프로젝트의 학습 목적과 이미지 환경이 비슷한가?

데이터의 양이 많아도 실제 사용할 환경과 너무 다르면 좋은 성능을 얻기 어렵습니다.

1-2. 카메라로 직접 수집

OpenCV를 사용하면 웹캠으로 사진을 촬영하여 저장할 수 있습니다.

import cv2
import os
from datetime import datetime

save_dir = "./captured_images"
os.makedirs(save_dir, exist_ok=True)

cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print("카메라를 열 수 없습니다.")
    raise SystemExit

success, frame = cap.read()

if success:
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    file_path = os.path.join(
        save_dir,
        f"result_{timestamp}.jpg"
    )

    cv2.imwrite(file_path, frame)
    print(f"사진 저장 완료: {file_path}")
else:
    print("카메라에서 사진을 읽지 못했습니다.")

cap.release()

VideoCapture(0)의 0은 기본 카메라를 의미합니다. 외장 카메라를 사용한다면 환경에 따라 1 또는 2로 변경해야 할 수 있습니다.


2. 데이터 증강

데이터 증강(Data Augmentation)은 기존 이미지를 회전하거나 밝기를 변경하는 방식으로 데이터의 다양성을 늘리는 기법입니다.

사진 한 장으로 여러 환경을 간접적으로 만들어 모델이 다양한 상황에 대응하도록 도울 수 있습니다.

from PIL import Image, ImageEnhance, ImageOps

img = Image.open("input.jpg")

# 90도 회전
rotated = img.rotate(90, expand=True)
rotated.save("rotated.jpg")

# 밝기를 50%로 조절
dark = ImageEnhance.Brightness(img).enhance(0.5)
dark.save("dark.jpg")

# 좌우 반전
mirrored = ImageOps.mirror(img)
mirrored.save("mirrored.jpg")

주요 증강 방법은 다음과 같습니다.

  • 회전
  • 밝기 변경
  • 좌우 반전
  • 크기 변경
  • 일부 영역 자르기
  • 노이즈 추가
  • 색상 변경
  • 원근 변환

객체 탐지 데이터 증강 시 주의사항

이미지 분류는 이미지 전체의 종류를 판단하기 때문에 사진만 변형해도 됩니다.

하지만 객체 탐지와 세그멘테이션에서는 이미지가 회전하거나 반전될 때 객체의 박스와 외곽선 좌표도 함께 변환해야 합니다.

이미지만 회전하고 라벨 좌표를 그대로 두면 객체의 실제 위치와 정답 위치가 달라져 잘못된 데이터를 학습하게 됩니다.

또한 원본 이미지를 학습·검증 데이터로 먼저 분리한 뒤 증강하는 것이 좋습니다.

같은 원본에서 만든 이미지가 학습 세트와 검증 세트에 동시에 들어가면 실제보다 성능이 높게 측정될 수 있습니다.

Ultralytics YOLO는 학습 과정에서 회전, 밝기, 좌우 반전, Mosaic 등의 데이터 증강 옵션을 제공합니다.

자세한 설정은 Ultralytics 학습 안내에서 확인할 수 있습니다.


3. 데이터 라벨링이란?

데이터 라벨링은 AI 모델에 정답을 알려주는 작업입니다.

객체 탐지에서는 이미지 속 객체를 사각형 박스로 감싸고 다음 정보를 기록합니다.

  • 객체의 종류
  • 객체 중심의 위치
  • 객체 박스의 너비
  • 객체 박스의 높이

예를 들어 식탁과 꽃병을 학습한다면 다음과 같이 클래스를 정할 수 있습니다.

names:
  0: dining_table
  1: vase

직접 학습하는 모델에서는 클래스 번호를 사용자가 정할 수 있습니다.

반면 주의 ! COCO 데이터로 사전 학습된 YOLO11 모델은 클래스 번호가 이미 정해져 있습니다.

60 = dining table
75 = vase

현재 모델의 전체 클래스 번호는 다음 코드로 확인할 수 있습니다.

from ultralytics import YOLO

model = YOLO("yolo11n.pt")

print(model.names)

 


4. 라벨링 도구

4-1. LabelImg

LabelImg는 컴퓨터에 설치해서 사용하는 라벨링 도구입니다.

장점:

  • 인터넷 없이 사용 가능
  • 사용 방법이 비교적 간단함
  • 이미지가 외부 서버에 업로드되지 않음
  • 바운딩 박스 라벨링에 적합함

단점:

  • 여러 사람이 동시에 작업하기 어려움
  • 데이터 버전 관리 기능이 부족함
  • 주로 객체 탐지용 박스 라벨링에 적합함

4-2. Roboflow

Roboflow는 웹 브라우저에서 데이터를 업로드하고 라벨링할 수 있는 서비스입니다.

장점:

  • 별도의 프로그램 설치 없이 사용 가능
  • 팀 단위 협업 가능
  • 학습·검증·테스트 데이터 분리 지원
  • 데이터 증강 기능 지원
  • YOLO 형식으로 내보내기 가능
  • 모델을 이용한 자동 라벨링 지원

단점:

  • 인터넷 연결 필요
  • 서비스 요금 및 공개 범위 확인 필요
  • 개인정보가 포함된 이미지 업로드 시 주의 필요

5. YOLO를 이용한 자동 라벨링

YOLO를 이용해서도 이미지에 라벨을 만들 수 있습니다.

정확히 말하면 YOLO가 예측한 결과를 정답 후보로 저장하는 것으로, 이를 다음과 같이 부릅니다.

  • 자동 라벨링
  • 사전 라벨링(Pre-labeling)
  • 의사 라벨링(Pseudo-labeling)

5-1. 폴더 속 이미지 자동 라벨링

from ultralytics import YOLO

model = YOLO("yolo11n.pt")

model(
    "images",
    conf=0.5,
    save=True,
    save_txt=True
)

각 옵션의 의미는 다음과 같습니다.

  • save=True: 박스가 그려진 결과 이미지 저장
  • save_txt=True: YOLO 형식의 라벨 파일 저장
  • conf=0.5: 신뢰도가 50% 이상인 결과만 사용

결과는 일반적으로 다음 폴더에 저장됩니다.

runs/
└─ detect/
   └─ predict/
      ├─ image01.jpg
      ├─ image02.jpg
      └─ labels/
         ├─ image01.txt
         └─ image02.txt

객체 탐지 라벨 파일에는 객체 하나당 한 줄씩 다음 값이 저장됩니다.

class_id x_center y_center width height

예:

0 0.512 0.438 0.243 0.572

좌표와 크기는 픽셀이 아니라 이미지 크기를 기준으로 0~1 사이 값으로 정규화됩니다.

5-2. 원하는 객체만 자동 라벨링

식탁과 꽃병만 라벨링하려면 classes 옵션을 사용합니다.

from ultralytics import YOLO

model = YOLO("yolo11n.pt")

model(
    "images",
    classes=[60, 75],
    conf=0.4,
    save=True,
    save_txt=True
)
60 = dining table
75 = vase

번호를 외우지 않고 이름으로 찾을 수도 있습니다.

from ultralytics import YOLO

model = YOLO("yolo11n.pt")

target_names = [
    "dining table",
    "vase"
]

target_ids = [
    class_id
    for class_id, class_name in model.names.items()
    if class_name in target_names
]

print(target_ids)

model(
    "images",
    classes=target_ids,
    conf=0.4,
    save=True,
    save_txt=True
)

5-3. 세그멘테이션 자동 라벨링

사각형 박스가 아니라 객체의 실제 외곽선이 필요하다면 세그멘테이션 모델을 사용합니다.

from ultralytics import YOLO

model = YOLO("yolo11n-seg.pt")

model(
    "images",
    classes=[60, 75],
    conf=0.4,
    save=True,
    save_txt=True
)

자동 라벨링의 한계

YOLO가 만든 라벨은 모델의 예측 결과이므로 완벽한 정답이 아닙니다.

  • 실제 객체를 놓칠 수 있음
  • 다른 물체를 잘못 탐지할 수 있음
  • 객체 박스의 크기와 위치가 부정확할 수 있음
  • 겹치거나 일부만 보이는 객체를 놓칠 수 있음
  • 기본 모델이 배우지 않은 물체는 인식하기 어려움

따라서 다음 방식이 가장 안전합니다.

YOLO 자동 라벨 생성 → LabelImg 또는 Roboflow에서 검수 → 누락된 객체 추가 → 잘못된 박스 수정 → 학습 데이터로 사용

특정 제품이나 부품처럼 기본 YOLO가 모르는 객체는 먼저 일부 이미지를 사람이 직접 라벨링해야 합니다.

이후 1차 모델을 학습하고, 그 모델로 나머지 이미지에 자동 라벨을 생성하면 작업 시간을 줄일 수 있습니다.


6. YOLO란?

YOLO는 “You Only Look Once”의 약자로, 이미지나 영상에서 여러 객체의 종류와 위치를 빠르게 찾아내는 컴퓨터 비전 모델입니다.

사진 한 장뿐만 아니라 다음과 같은 입력을 처리할 수 있습니다.

  • 이미지
  • 이미지 폴더
  • 동영상
  • 웹캠
  • CCTV
  • HTTP 영상 스트림

YOLO11은 객체 탐지뿐 아니라 이미지 분류, 인스턴스 분할, 자세 추정, 회전 객체 탐지 등을 지원합니다. YOLO11 공식 모델 안내

모델기능결과
yolo11n.pt 객체 탐지 객체 이름과 사각형 박스
yolo11n-seg.pt 인스턴스 분할 객체의 실제 영역
yolo11n-pose.pt 자세 추정 사람의 관절 위치
yolo11n-cls.pt 이미지 분류 이미지 전체의 종류
yolo11n-obb.pt 회전 객체 탐지 방향이 포함된 박스

모델명에 사용되는 n, s, m, l, x는 모델의 크기를 의미합니다.

  • n: 가장 작고 빠른 모델
  • s: 작지만 n보다 정확도가 높은 모델
  • m: 속도와 정확도의 중간
  • l, x: 더 크고 많은 연산이 필요한 모델

초보자가 CPU 또는 웹캠 실습을 할 때는 yolo11n.pt부터 시작하는 것이 좋습니다.


7. YOLO 설치와 기본 객체 탐지

터미널에서 Ultralytics 패키지를 설치합니다.

pip install ultralytics

기본 객체 탐지 코드는 다음과 같습니다.

from ultralytics import YOLO

model = YOLO("yolo11n.pt")

results = model(
    "input.jpg",
    conf=0.5,
    save=True
)

save=True를 사용하면 결과가 일반적으로 다음 위치에 저장됩니다.

runs/detect/predict

같은 코드를 반복 실행하면 기존 결과를 덮어쓰지 않고 새 폴더가 만들어집니다.

predict
predict2
predict3

작업별 기본 저장 폴더도 다릅니다.

객체 탐지       → runs/detect
세그멘테이션    → runs/segment
자세 추정       → runs/pose
이미지 분류     → runs/classify
객체 추적       → runs/track 또는 작업별 결과 폴더

8. 원하는 객체만 탐지하기

classes 옵션을 사용하면 특정 클래스만 탐지할 수 있습니다.

from ultralytics import YOLO

model = YOLO("yolo11n-seg.pt")

model(
    "input_seg.jpg",
    classes=[60, 75],
    conf=0.5,
    save=True
)

이 코드는 식탁과 꽃병만 탐지하고 분할합니다.

직접 학습한 모델에서는 클래스 번호가 data.yaml의 순서에 따라 달라집니다.

names:
  0: vase
  1: dining_table

이렇게 정의하고 학습했다면 다음과 같이 사용합니다.

model(
    "input.jpg",
    classes=[0, 1],
    save=True
)

9. 주요 파라미터

results = model(
    "input.jpg",
    conf=0.5,
    imgsz=640,
    max_det=5,
    classes=[0, 2],
    save=True,
    project="results",
    name="my_prediction"
)
파라미터설명
conf=0.5 신뢰도 50% 이상만 탐지
imgsz=640 모델 입력 이미지 크기
max_det=5 한 이미지의 최대 탐지 개수
classes=[0, 2] 지정한 클래스만 탐지
save=True 결과 이미지 저장
save_txt=True 탐지 결과를 라벨 파일로 저장
project="results" 결과를 저장할 상위 폴더
name="test1" 결과 폴더 이름
device=0 첫 번째 GPU 사용
device="cpu" CPU 사용
verbose=False 반복 출력 메시지 줄이기

conf가 너무 높으면 실제 객체를 놓칠 수 있고, 너무 낮으면 잘못 탐지하는 객체가 늘어날 수 있습니다.

처음에는 0.25~0.5 정도에서 비교해보는 것이 좋습니다.


10. 추론 결과 직접 저장하기

YOLO의 plot()을 실행하면 탐지 박스가 그려진 이미지 배열을 얻을 수 있습니다.

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)

print("결과 이미지가 저장되었습니다.")

다음처럼 plot 뒤에 괄호가 없으면 함수가 실행되지 않습니다.

results[0].plot    # 잘못된 사용
results[0].plot()  # 올바른 사용

추론 결과에는 작업에 따라 다음 정보가 들어 있습니다.

results[0].boxes       # 객체 탐지 박스
results[0].masks       # 세그멘테이션 마스크
results[0].keypoints   # 자세 추정 관절 좌표
results[0].probs       # 이미지 분류 확률

자세한 결과 구조는 Ultralytics 추론 안내에서 확인할 수 있습니다.


11. 웹캠 실시간 객체 탐지

from ultralytics import YOLO
import cv2

model = YOLO("yolo11n.pt")
cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print("카메라를 열 수 없습니다.")
    raise SystemExit

while cap.isOpened():
    success, frame = cap.read()

    if not success:
        print("프레임 읽기 실패")
        break

    results = model(
        frame,
        conf=0.5,
        verbose=False
    )

    annotated_frame = results[0].plot()

    cv2.imshow(
        "YOLO Webcam",
        annotated_frame
    )

    if cv2.waitKey(1) & 0xFF == ord("q"):
        print("q키를 눌러 종료합니다.")
        break

cap.release()
cv2.destroyAllWindows()

초보자가 자주 틀리는 코드는 다음과 같습니다.

cap.isOpened()  # isOpend()가 아님
ord("q")        # waitKey 결과와 비교할 때 사용

break는 반드시 while 또는 for 반복문 내부에서 사용해야 합니다.


12. HTTP CCTV 스트림 연결

웹캠 대신 HTTP 영상 스트림 주소를 전달할 수도 있습니다.

from ultralytics import YOLO
import cv2

stream_url = "http://example.com/live/playlist.m3u8"

cap = cv2.VideoCapture(stream_url)
model = YOLO("yolo11n.pt")

if not cap.isOpened():
    print("스트림을 열 수 없습니다.")
    raise SystemExit

while cap.isOpened():
    success, frame = cap.read()

    if not success:
        print("스트림 프레임 읽기 실패")
        break

    results = model(
        frame,
        conf=0.5,
        verbose=False
    )

    annotated_frame = results[0].plot()

    cv2.imshow(
        "CCTV YOLO",
        annotated_frame
    )

    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

HTTP 스트림은 다음 원인으로 열리지 않을 수 있습니다.

  • 스트림 주소 만료
  • 서버 접속 제한
  • 네트워크 연결 문제
  • OpenCV가 지원하지 않는 코덱
  • 동시 접속자 제한
  • 인증이 필요한 스트림

공개 CCTV 영상을 사용할 때는 해당 서비스의 이용 조건과 개인정보 관련 규정도 확인해야 합니다.


13. 영상 속 객체 추적하기

객체 탐지는 각 프레임에서 객체를 새로 찾습니다. 객체 추적은 같은 객체에 ID를 부여해 영상이 진행되어도 계속 구분하는 기능입니다.

from ultralytics import YOLO
import cv2

model = YOLO("yolo11n.pt")
cap = cv2.VideoCapture(0)

while cap.isOpened():
    success, frame = cap.read()

    if not success:
        break

    results = model.track(
        frame,
        persist=True,
        conf=0.5,
        verbose=False
    )

    annotated_frame = results[0].plot()

    cv2.imshow(
        "YOLO Tracking",
        annotated_frame
    )

    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

persist=True는 이전 프레임의 추적 정보를 다음 프레임에서도 이어서 사용하라는 의미입니다.

객체 추적은 다음 분야에 활용할 수 있습니다.

  • 사람 수 계산
  • 차량 이동 분석
  • 위험 구역 진입 감지
  • 물류 제품 이동 추적
  • 특정 객체의 이동 경로 분석

자세한 내용은 Ultralytics 객체 추적 안내에서 확인할 수 있습니다.


14. 나만의 객체 탐지 모델 학습하기

기본 YOLO11 탐지 모델은 COCO 데이터셋의 80개 클래스를 학습한 모델입니다.

기본 목록에 없는 제품, 부품, 불량 유형, 특정 도구 등을 탐지하려면 직접 데이터를 수집하고 학습해야 합니다.

데이터 폴더 구조

dataset/
├─ images/
│  ├─ train/
│  └─ val/
├─ labels/
│  ├─ train/
│  └─ val/
└─ data.yaml

data.yaml 작성

path: ./dataset

train: images/train
val: images/val

names:
  0: dining_table
  1: vase

YOLO 객체 탐지 라벨은 이미지마다 하나의 .txt 파일로 저장합니다.

class_id x_center y_center width height

클래스 번호는 0부터 시작하고 좌표는 0~1 사이의 값으로 정규화합니다. 자세한 구조는 Ultralytics 객체 탐지 데이터 형식에서 확인할 수 있습니다.

모델 학습

from ultralytics import YOLO

model = YOLO("yolo11n.pt")

model.train(
    data="data.yaml",
    epochs=100,
    imgsz=640,
    batch=16
)

학습 결과는 일반적으로 다음 폴더에 저장됩니다.

runs/detect/train

가장 성능이 좋았던 모델은 다음 파일입니다.

runs/detect/train/weights/best.pt

학습한 모델로 추론

from ultralytics import YOLO

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

model(
    "test.jpg",
    conf=0.5,
    save=True
)

15. 효율적인 자동 라벨링 학습 순서

직접 만든 객체를 학습할 때는 다음 순서가 효율적입니다.

  1. 여러 환경에서 이미지를 수집한다.
  2. 일부 이미지에 사람이 직접 라벨링한다.
  3. 직접 만든 라벨로 1차 YOLO 모델을 학습한다.
  4. 1차 모델로 나머지 이미지에 자동 라벨을 생성한다.
  5. LabelImg 또는 Roboflow에서 자동 라벨을 검수한다.
  6. 잘못된 박스를 수정하고 누락된 객체를 추가한다.
  7. 수정된 전체 데이터로 최종 모델을 다시 학습한다.
  8. 학습에 사용하지 않은 테스트 이미지로 성능을 확인한다.

이 과정을 반복하면 사람이 모든 이미지에 처음부터 박스를 그리는 시간을 줄일 수 있습니다.

 


마무리

좋은 데이터 수집 → 정확한 라벨링 → 모델 학습 → 결과 검증 → 실제 환경 적용

오늘 학습의 핵심 :  AI 프로젝트 전체 흐름을 이해

  1. 목적에 맞는 이미지를 수집한다.
  2. 필요한 경우 데이터를 증강한다.
  3. 객체 위치와 종류를 정확히 라벨링한다.
  4. 학습·검증 데이터를 분리한다.
  5. 작업에 맞는 YOLO 모델을 선택한다.
  6. 파라미터를 조절하며 추론 결과를 확인한다.
  7. 이미지, 웹캠, CCTV 및 영상 추적으로 확장한다.

YOLO는 다음과 같은 기능을 제공합니다.

  • 이미지 분류
  • 객체 탐지
  • 인스턴스 분할
  • 자세 추정
  • 객체 추적
  • 이미지·동영상 추론
  • 결과 이미지와 라벨 저장
  • 원하는 클래스만 선택
  • 파라미터 조절
  • 웹캠 및 CCTV 스트림 처리
  • 자동 라벨링
  • 사용자 데이터 학습

 

 

'성남 프론트엔드' 카테고리의 다른 글

16일차_Hugging Face  (0) 2026.07.22
15일차_YOLO 심화  (1) 2026.07.21
13일차_ Anaconda / Python문법  (0) 2026.07.16
12일차_Vercel배포  (0) 2026.07.15
12일차_Node·Express /POST 보내기/  (0) 2026.07.14