본문 바로가기
Data & AI Intelligence/▶AI & Agent

YOLO11 실습: 이미지 예측, 시각화, Streamlit 웹앱 구축

by 류딩이2025. 12. 10.

YOLO11 실습 총정리: 이미지 예측 · 시각화 · Streamlit 웹UI

이 글은 YOLO11 모델을 활용하여 객체 탐지를 수행하는 전체 흐름을 정리한 튜토리얼입니다.
YOLO 기본 예측, 이미지 저장/시각화 스크립트, Streamlit 웹 인터페이스, Docker 실행까지 모든 내용을 포함하며
특히 요청하신 “전체 코드에 대한 상세 설명”을 접기 형태로 제공합니다.


1. YOLO11 모델 성능 비교표

Model size mAP 50–95 CPU Speed(ms) T4 Speed(ms) Params(M) FLOPs(B)
YOLO11n 640 39.5 56.1 1.5 2.6 6.5
YOLO11s 640 47.0 90.0 2.5 9.4 21.5
YOLO11m 640 51.5 183.2 4.7 20.1 68.0
YOLO11l 640 53.4 238.6 6.2 25.3 86.9
YOLO11x 640 54.7 462.8 11.3 56.9 194.9

 

각 항목이 의미하는 것

항목 의미 영향
mAP 탐지 정확도 높을수록 좋은 모델
CPU Speed CPU 추론 속도 서버/노트북에서 중요
TensorRT Speed NVIDIA GPU 최적화 속도 실시간 서비스 적합성 판단
Params 모델 크기 메모리/배포환경에 영향
FLOPs 연산량 속도와 직접적 관련

2. YOLO 기본 추론 코드

단일 이미지를 읽어 객체 정보(좌표·클래스·confidence)를 추출하는 기본 예제입니다.

[코드 보기] YOLO 기본 추론
from ultralytics import YOLO

model = YOLO("yolo11n.pt")
results = model("cow.jpg")

for result in results:
    xywh = result.boxes.xywh
    xyxy = result.boxes.xyxy
    names = [model.names[int(cls)] for cls in result.boxes.cls.tolist()]
    confs = result.boxes.conf

3. predict_yolo.py — 탐지 이미지 저장

[코드 보기]
from ultralytics import YOLO
from PIL import Image

model = YOLO("yolo11n.pt")
results = model(["cow.jpg"])

for i, r in enumerate(results):
    im_bgr = r.plot()
    im_rgb = Image.fromarray(im_bgr[..., ::-1])
    r.show()
    r.save(filename=f"result{i}.jpg")
[설명 보기 — predict_yolo.py 상세 설명]
  • YOLO("yolo11n.pt") 모델 가중치를 로드합니다.
  • results = model(["cow.jpg"]) 이미지를 입력으로 추론을 실행하고 결과 리스트를 반환합니다.
  • r.plot() YOLO가 bounding box를 그려 넣은 BGR 이미지를 반환합니다.
  • Image.fromarray(...) BGR → RGB로 변환해 사람이 보기 좋은 컬러로 변경합니다.
  • r.show() 윈도우/노트북 환경에서 이미지 표시.
  • r.save() bounding box가 포함된 이미지를 파일로 저장합니다.

4. visualize_yolo.py — 화면 시각화

[코드 보기]
from ultralytics import YOLO
from PIL import Image

model = YOLO("yolo11n.pt")
results = model(["cow.jpg"])

for i, r in enumerate(results):
    im_bgr = r.plot()
    im_rgb = Image.fromarray(im_bgr[..., ::-1])
    r.show()
[설명 보기 — visualize_yolo.py 상세 설명]
  • r.plot(): YOLO가 그린 bounding box 포함 이미지 생성
  • RGB 변환: 색상이 뒤집히지 않도록 BGR → RGB 변환
  • r.show(): 결과를 즉시 화면에 표시
  • 저장은 선택이며 시각화가 목적

5. Streamlit을 활용한 YOLO 웹 데모

이미지 업로드 → 객체 탐지 → 결과 표시 → JSON/PNG 다운로드까지 가능한 웹 UI입니다.

1) Docker 실행

docker run -it --name yolo_streamlit -p 8000:8000 -v $(pwd):/workspace python:3.10-slim /bin/bash

2) 의존성 설치

apt update
apt install -y libgl1 libglib2.0-0

3) Streamlit 실행

streamlit run ui/app.py --server.port=8000

6. Streamlit 전체 코드 + 상세 설명

[코드 보기 — Streamlit YOLO 웹 앱 전체]
import io
from typing import List, Dict, Any

import numpy as np
import streamlit as st
from PIL import Image
from ultralytics import YOLO

# 페이지 설정
st.set_page_config(page_title="YOLO 객체 검출 데모", layout="wide")
st.title("YOLO 객체 검출 데모")

# 사이드바 설정
with st.sidebar:
    st.header("설정")

    weights = st.text_input(
        "가중치(.pt) 경로 또는 모델 이름",
        value="model/yolo11n.pt",
        help="예: yolo11n.pt 또는 커스텀 모델 경로"
    )

    conf = st.slider("Confidence Threshold", 0.0, 1.0, 0.25, 0.01)
    iou = st.slider("NMS IoU Threshold", 0.0, 1.0, 0.45, 0.01)
    max_det = st.number_input("최대 검출 수 (max_det)", min_value=1, max_value=3000, value=300)

    device = st.selectbox(
        "Device",
        options=["auto", "cpu", "cuda:0"],
        index=0,
        help="'auto'는 가능한 경우 GPU를 사용합니다."
    )

    imgsz = st.number_input("이미지 입력 크기 (imgsz)", min_value=32, max_value=2048, value=640, step=32)
    line_thickness = st.slider("박스 두께", 1, 8, 2)
    hide_labels = st.checkbox("라벨 숨기기", value=False)
    hide_conf = st.checkbox("Conf 숨기기", value=False)


# 모델 로드 함수
@st.cache_resource(show_spinner=False)
def load_model(weights_path: str) -> YOLO:
    return YOLO(weights_path)


# 검출 결과 포맷팅 함수
def format_detections(result) -> List[Dict[str, Any]]:
    names = result.names
    dets = []

    if result.boxes is None or len(result.boxes) == 0:
        return dets

    xyxy = result.boxes.xyxy.cpu().numpy()
    confs = result.boxes.conf.cpu().numpy()
    clss = result.boxes.cls.cpu().numpy().astype(int)

    for i, (x1, y1, x2, y2) in enumerate(xyxy):
        dets.append({
            "class_id": int(clss[i]),
            "class_name": names[int(clss[i])],
            "confidence": float(confs[i]),
            "bbox_xyxy": [float(x1), float(y1), float(x2), float(y2)],
        })

    return dets


# 메인 UI
uploaded = st.file_uploader("이미지 업로드", type=["jpg", "jpeg", "png", "bmp", "webp"])
col1, col2 = st.columns(2)

if uploaded is not None:
    image = Image.open(uploaded).convert("RGB")
    col1.subheader("입력 이미지")
    col1.image(image, use_column_width=True)

    run = st.button("추론 실행")

    if run:
        model = load_model(weights)

        with st.spinner("모델 추론 중..."):
            results = model.predict(
                source=np.array(image),
                conf=conf,
                iou=iou,
                max_det=max_det,
                device=None if device == "auto" else device,
                imgsz=imgsz,
                verbose=False,
                line_width=line_thickness,
                hide_labels=hide_labels,
                hide_conf=hide_conf
            )

        result = results[0]

        # 결과 이미지 생성
        annotated = result.plot()  # numpy array (BGR → RGB 자동 변환됨)
        col2.subheader("검출 결과")
        col2.image(annotated, use_column_width=True)

        # 상세 정보
        with st.expander("추론 상세"):
            speeds = getattr(result, "speed", {})
            st.json({
                "model": weights,
                "image_shape": list(np.array(image).shape),
                "num_detections": int(len(result.boxes) if result.boxes is not None else 0),
                "speed_ms": speeds
            })

        # 검출 결과 리스트
        dets = format_detections(result)
        if len(dets) > 0:
            st.subheader("검출 목록")
            st.dataframe(dets, use_container_width=True)
        else:
            st.info("검출된 객체가 없습니다. Threshold를 낮추거나 다른 이미지를 시도하세요.")

        # 결과 다운로드
        buf = io.BytesIO()
        Image.fromarray(annotated).save(buf, format="PNG")

        st.download_button(
            "시각화 이미지 다운로드(PNG)",
            data=buf.getvalue(),
            file_name="detections.png",
            mime="image/png"
        )

        st.download_button(
            "검출 결과(JSON) 다운로드",
            data=str(dets).encode("utf-8"),
            file_name="detections.json",
            mime="application/json"
        )

 

[설명 보기 — Streamlit 전체 코드 설명]
  • st.sidebar: 모델 옵션 설정 UI
  • load_model(): YOLO 모델을 캐싱하여 재사용 → 성능 향상
  • format_detections(): YOLO 탐지 결과를 JSON 형태로 변환
  • file_uploader: 사용자가 이미지를 업로드
  • model.predict(): YOLO 실제 추론 실행
  • result.plot(): bounding box가 포함된 시각화 이미지 생성
  • st.expander(): 추론 속도(ms) 등 상세 정보 제공
  • download_button(): 시각화 이미지/JSON 다운로드 기능 제공

 

[설명 보기 — Streamlit 전체 코드 자세한 설명]

더보기

YOLO Streamlit 전체 코드 상세 설명

아래는 YOLO11 객체 검출 Streamlit 앱 전체 코드에 대한 상세 해설입니다.
각 코드 블록이 어떤 역할을 하는지 단계별로 정리했습니다.


1. 기본 라이브러리 및 설정

import io
from typing import List, Dict, Any

import numpy as np
import streamlit as st
from PIL import Image
from ultralytics import YOLO
  • numpy: 이미지 배열 처리
  • streamlit: 웹 UI 구성
  • PIL: 이미지 로드 및 RGB 변환
  • YOLO: 객체 탐지 모델

2. Streamlit 페이지 설정

st.set_page_config(page_title="YOLO 객체 검출 데모", layout="wide")
st.title("YOLO 객체 검출 데모")

- 제목과 화면 레이아웃 설정


3. 사이드바 구성 (모델 옵션 설정)

with st.sidebar:
    st.header("설정")

    weights = st.text_input(
        "가중치(.pt) 경로 또는 모델 이름",
        value="model/yolo11n.pt",
        help="예: yolo11n.pt 또는 커스텀 모델 경로"
    )

    conf = st.slider("Confidence Threshold", 0.0, 1.0, 0.25, 0.01)
    iou = st.slider("NMS IoU Threshold", 0.0, 1.0, 0.45, 0.01)
    max_det = st.number_input("최대 검출 수 (max_det)", 1, 3000, 300)

    device = st.selectbox("Device", ["auto", "cpu", "cuda:0"])
    imgsz = st.number_input("이미지 입력 크기", 32, 2048, 640, 32)
    line_thickness = st.slider("박스 두께", 1, 8, 2)
    hide_labels = st.checkbox("라벨 숨기기", False)
    hide_conf = st.checkbox("Conf 숨기기", False)
  • Confidence: 신뢰도 기준(낮으면 더 많이 탐지)
  • IoU Threshold: 박스 중복 제거 기준
  • imgsz: 모델 입력 이미지 크기
  • hide_labels / hide_conf: 출력에서 텍스트 표시 여부

4. YOLO 모델 캐싱 로드

@st.cache_resource(show_spinner=False)
def load_model(weights_path: str) -> YOLO:
    return YOLO(weights_path)

- Streamlit 캐시 기능으로 모델 재로드를 방지 → 속도 최적화


5. 탐지 결과 포맷 함수

def format_detections(result) -> List[Dict[str, Any]]:
    names = result.names
    dets = []

    if result.boxes is None or len(result.boxes) == 0:
        return dets

    xyxy = result.boxes.xyxy.cpu().numpy()
    confs = result.boxes.conf.cpu().numpy()
    clss = result.boxes.cls.cpu().numpy().astype(int)

    for i, (x1, y1, x2, y2) in enumerate(xyxy):
        dets.append({
            "class_id": int(clss[i]),
            "class_name": names[int(clss[i])],
            "confidence": float(confs[i]),
            "bbox_xyxy": [float(x1), float(y1), float(x2), float(y2)],
        })

    return dets

- YOLO 결과에서 필요한 부분만 정리해 JSON 스타일로 출력


6. 사용자 이미지 업로드 UI

uploaded = st.file_uploader("이미지 업로드", type=["jpg","jpeg","png","bmp","webp"])
col1, col2 = st.columns(2)

- 좌측: 입력 이미지 표시
- 우측: YOLO 분석 결과 표시


7. 업로드된 이미지 출력

if uploaded is not None:
    image = Image.open(uploaded).convert("RGB")
    col1.subheader("입력 이미지")
    col1.image(image, use_column_width=True)

8. 추론 실행 및 모델 예측

run = st.button("추론 실행")

if run:
    model = load_model(weights)

    with st.spinner("모델 추론 중..."):
        results = model.predict(
            source=np.array(image),
            conf=conf,
            iou=iou,
            max_det=max_det,
            device=None if device == "auto" else device,
            imgsz=imgsz,
            verbose=False,
            line_width=line_thickness,
            hide_labels=hide_labels,
            hide_conf=hide_conf
        )
  • YOLO 모델로 이미지 분석
  • confidence, IoU, max_det 등 적용
  • 박스 두께, 라벨 숨김 옵션도 반영

9. 박스가 그려진 이미지 출력

result = results[0]
annotated = result.plot()
col2.subheader("검출 결과")
col2.image(annotat

 


마무리

이 글에서는 YOLO11의 기본 사용법부터 Streamlit 웹 애플리케이션 배포까지 모두 정리했습니다.
각 코드마다 상세 설명을 추가하여 초보자도 쉽게 이해할 수 있도록 구성했습니다.
필요하면 웹캠 실시간 YOLO / Fine-tuning / 데이터셋 제작 등도 계속 확장해 드릴 수 있습니다.