AIDON
System Overview

AIDON AI CCTV — 건설현장 안전 감지 시스템

CCTV 영상을 AI가 실시간으로 분석해 안전모 미착용·낙상·화재·연기·위험구역 침입을 자동 감지하고 운영자에게 알람을 전달합니다. 모든 이벤트는 영상·스냅샷과 함께 보관되어 사후 점검 및 리포트에 활용됩니다.

5종 위험 감지다채널 동시 모니터링2단계 처리 (1차 필터 → 2차 AI)위험구역 (ROI) 지정10초 영상 자동 보관주간 · 월간 PDF 리포트
01

이 웹이 무엇을 하나요?

기능 개요
  • • CCTV 영상에서 위험 상황 자동 감지
  • • 5초 이상 지속되면 알람 발생
  • • 영상·스냅샷·이벤트 자동 보관
이용 대상
  • 운영자(Manager) — 모니터링·확인 처리
  • 관리자(Admin) — 카메라·계정·ROI 관리
  • • 인증: 이메일 + 비밀번호 (JWT)
기술 구성
  • • 백엔드: Python · FastAPI · Ultralytics YOLOv8
  • • 프론트엔드: Next.js · React · TypeScript
  • • 데이터베이스: PostgreSQL (Docker)
02

어떤 위험을 감지하나요?

안전모 미착용
경고 (Warning)
구현됨
언제
작업자가 안전모를 쓰지 않고 작업하는 상황
어떻게
사람을 탐지한 뒤, PPE 모델로 머리 영역에 안전모가 있는지 확인
임계치
5초 이상 지속 시
알람
노란색 경고 + 알림 팝업 + 소리
위험구역 침입
경고 (Warning)
구현됨
언제
관리자가 지정한 위험구역에 비인가 작업자가 머무는 상황
어떻게
사람의 발 좌표가 폴리곤 안에 들어왔는지 매 프레임 확인
임계치
기본 5초 이상 체류 (카메라별 조절)
알람
노란색 경고 + 알림 팝업
낙상 감지
긴급 (Critical)
구현됨
언제
추락 또는 의식 잃은 채로 쓰러진 상황
어떻게
사람 박스의 y좌표 속도가 빠르거나, 종횡비가 누운 모양인데 정지
임계치
10초 이상 자세 미변화
알람
빨간색 긴급 + 알림 팝업 + 강한 소리
화재 감지
긴급 (Critical)
구현됨
언제
불꽃이 보이는 상황
어떻게
먼저 HSV 색공간에서 빨강/주황 픽셀을 검사하고, 통과하면 Fire 모델로 확정
임계치
5초 이상 지속 (찰나의 용접 불꽃 제거)
알람
빨간색 긴급 + 알림 팝업
연기 감지
긴급 (Critical)
부분 구현
언제
연기가 보이는 상황
어떻게
Fire 모델이 연기까지 함께 분류
임계치
5초 이상 지속
알람
빨간색 긴급 + 알림 팝업
03

사용된 AI 모델

1차 (사람 탐지)
yolov8n.pt
Ultralytics 공식 (자동 다운로드)
용도
사람 박스를 매 프레임 탐지 + ByteTrack으로 추적. 사람이 없는 채널은 PPE/Fire 호출 자체를 건너뜀.
크기
≈ 6 MB
속도
~50ms/frame (CPU 기준)
env
YOLO_PRIMARY_WEIGHTS
기본 클래스
personbicyclecar...
2차 (PPE)
ppe.pt
snehilsanyal — 건설현장 안전장비
용도
사람이 있을 때만 호출. 같은 사람(track id)은 30초마다 한 번만 재검증.
크기
≈ 22 MB
속도
~120ms/frame (CPU 기준)
env
YOLO_PPE_WEIGHTS
기본 클래스
HardhatNO-HardhatNO-MaskNO-Safety VestSafety Vest...
2차 (화재/연기)
fire.pt
Abonia1 — 화재·연기
용도
HSV 빨강/주황 픽셀이 2% 이상일 때만 호출. 평상시엔 거의 호출되지 않음.
크기
≈ 18 MB
속도
~80ms/frame (CPU 기준)
env
YOLO_FIRE_WEIGHTS
기본 클래스
Firesmokedefault
모델 교체 가이드
  1. 1새 가중치 파일(.pt)을 backend/weights/ 폴더에 저장.
  2. 2backend/.env 의 해당 변수 값을 새 파일 이름으로 변경. 예: YOLO_PPE_WEIGHTS=my-ppe-v2.pt
  3. 3백엔드 재시작: python -m uvicorn main:app --port 8000
  4. 4이 페이지를 새로고침해 모델 카드의 "현재 로드된 클래스"가 갱신됐는지 확인.
참고 · 모델이 출력하는 클래스 이름과 시스템이 이해하는 위험 유형이 다르면 backend/models/yolov8_model.py DANGER_CLASS_ALIASES 에 매핑을 추가하세요. (예: "no-hardhat" → "no_helmet")
04

기획서 대비 — 무엇이 맞고 무엇이 어긋났나

요약

기획서가 제안한 8개 항목 중 3개는 정확히 일치(1차 필터·HSV·ByteTrack), 2개는 외부 모델로 대체(PPE·화재 — 자체 파인튜닝 안 됨), 3개는 미적용(낙상 포즈 추정·TensorRT·DeepStream). 또한 PPE는 5종 위반 유형 중 안전모 1종만 실제 알람으로 활성화되어 있음.

기획서 명시현재 구현매칭
YOLOv8n 사람 탐지 (1차)
yolov8n.pt (Ultralytics 자동 다운로드)
정확히 일치
ByteTrack 객체 추적
Ultralytics 내장 ByteTrack + lap
정확히 일치
HSV 빨강/주황 사전 필터
OpenCV HSV + 2% 임계치 (FIRE_HSV_THRESHOLD)
정확히 일치
YOLOv8s PPE 분류 (안전모/안전벨트/안전화/조끼 5클래스)
ppe.pt (snehilsanyal, 10클래스)
안전벨트·안전화는 모델 자체에 클래스 없음. 안전조끼는 감지되지만 알람 매핑 안 됨.
부분/대체
Custom Fire-CNN (자체 파인튜닝)
fire.pt (Abonia1 — 외부 공개 모델)
YOLO 기반 화재/연기 모델이지만 우리 현장 데이터로 파인튜닝하지 않은 상태.
부분/대체
RTMPose 포즈 추정 (낙상 2차)
없음 — 룰 기반(y속도/종횡비/정지)만
쪼그려 앉기·점심시간 휴식과 진짜 의식 잃은 상태 구분이 어려움 → 오탐 위험.
미적용
TensorRT FP16 가속
PyTorch CPU (자동 CUDA fallback)
GPU 서버 도입 후 적용 예정. CPU 환경에서는 사람 탐지 ~50ms/frame.
미적용
DeepStream 7 / Triton Inference Server
OpenCV + FFmpeg (소프트웨어 디코딩)
32~64채널 운영 시 필요. 현재는 1~4채널만 가능.
미적용
PPE — 1종만 알람

현재 ppe.pt는 10클래스를 감지하지만, 알람으로 가는 건 안전모(no_helmet) 1종뿐입니다.

  • 안전모 미착용 — 활성화됨
  • 안전조끼 미착용 — 모델은 감지, 알람 매핑 안 됨
  • 안전벨트·안전화 — 모델 클래스 자체 없음
안전조끼는 backend/models/yolov8_model.py DANGER_CLASSES"no_safety_vest"를 추가하면 즉시 활성화됨.
낙상 — 포즈 추정 빠짐

기획서는 RTMPose 17개 키포인트 + 5초 시퀀스 분석을 명시했지만, 현재는 박스 모양·속도 룰만 사용합니다.

  • 급강하 (y속도) — 추락 직후 잡힘
  • 종횡비 + 정지 — 누운 자세 잡힘
  • 포즈 검증 없음 — 쪼그려 앉기·점심 휴식 오탐 가능
yolov8n-pose.pt (자동 다운로드)를 후보 영역에만 호출하면 정확도 ↑.
화재 — 외부 모델 그대로

기획서의 "Custom Fire-CNN(자체 파인튜닝)"이 아니라, 외부 공개 모델인 fire.pt (Abonia1)를 그대로 사용 중입니다.

  • HSV 사전 필터로 호출 빈도 절감
  • 연기(smoke) 클래스 정확도 낮음 — 모델 한계
  • 현장 영상으로 파인튜닝 안 됨
현장 영상으로 파인튜닝하거나, 더 좋은 화재 전용 모델로 교체 필요.
성능 격차 — CPU 데모 (현재) vs GPU 운영 (기획서 목표)
지표현재기획서 목표비고
1차 사람 탐지 속도~50ms/frame (CPU)~1~2ms/frame (GPU TensorRT FP16)25~50배 격차 — GPU 필수
PPE 추론 평균 지연~120ms/frame (CPU)~10ms (GPU)약 10배
동시 처리 채널1~4채널 안정32~64채널 (설계서 §5)GPU + DeepStream 도입 시 가능
화재 탐지 정확도외부 모델 그대로현장 영상으로 파인튜닝용접·노을 반사 오탐 가능성. 현장 데이터 수집 필요
낙상 탐지 정확도룰 기반만 (포즈 없음)포즈 추정 + 5초 시퀀스yolov8-pose 또는 RTMPose 추가 시 개선
PPE 위반 종류 수안전모(no_helmet) 1종만 알람안전모·안전벨트·안전화·조끼 4종 + 마스크안전조끼는 코드 한 줄 추가로 즉시 활성. 나머지는 별도 모델 필요.
CPU 환경에서 즉시 개선 가능
  • 안전조끼 미착용 알람 활성화
    코드 1줄 — DANGER_CLASSES 매핑 추가. 약 5분 작업.
  • 낙상 2차 검증에 yolov8-pose 추가
    후보 시점에만 호출 — CPU 부담 최소. 약 30~60분 작업.
  • 현장 영상 수집 시작
    클립이 자동 저장되므로, 라벨링만 시작하면 추후 파인튜닝 데이터로 활용 가능.
GPU 서버 도입 후
  • TensorRT FP16 변환
    기존 .pt를 .engine으로 변환 — CPU 대비 5~10배 속도.
  • DeepStream 7 또는 Triton 도입
    32~64채널 동시 처리.
  • 자체 데이터로 PPE·Fire 파인튜닝
    한국 건설현장 특화로 정확도 향상.
  • NVDEC 하드웨어 디코딩
    4K 다채널 처리 시 GPU 디코더 활용.
05

이렇게 동작합니다 (2단계 처리 흐름)

1차 필터 (모든 채널 · 항상)
  • ① 카메라 영상 받기 + 디코딩
  • ② 4 fps로 추론용 프레임 추출
  • yolov8n 으로 사람 탐지 + 추적(ByteTrack)
  • ④ 룰 엔진: ROI 폴리곤 · 낙상 자세 · HSV 색
가벼움 · 빠름 · 항상 돈다
트리거 큐
in-process
(운영 시 Redis)
2차 AI (트리거 시에만)
  • PPE 분류 (비동기 큐, 사람 있을 때만)
  • Fire 분류 (HSV 통과 시)
  • ③ 5초 지속 검증 (SustainTracker)
  • ④ 확정 시 → DB 저장 + 클립 녹화 + 알람
무거움 · 가끔 돈다
알람 정책 — 어떻게 알람 폭주를 막나
① 5초 지속 검증
한 프레임만 잡힌 가짜 트리거(용접 불꽃, 화면 가장자리 스침)는 알람으로 안 뜸.짧게 끝난 트리거는 triggers 테이블에 'expired'로만 기록.
② ACK 기반 차단
같은 (카메라, 유형)의 미확인 알람이 1건이라도 있으면 같은 종류 새 알람은 차단.운영자가 ACK 하기 전까지는 같은 인시던트로 묶임.
③ ACK 시 즉시 해제
확인 처리 누르면 그 (카메라, 유형)의 dedup 상태가 리셋되어 즉시 다음 인시던트가 알람.
06

각 페이지 안내

07

튜닝 가능한 설정 (.env 환경변수)

환경변수기본값의미
DATABASE_URLpostgresql+psycopg2://ai_cctv:ai_cctv_dev@127.0.0.1:5433/ai_cctvDB 접속 정보. Docker Postgres 사용.
FRONTEND_ORIGINhttp://localhost:3000CORS 허용 출처.
JWT_SECRET(dev 기본값 — 운영 시 반드시 교체)JWT 토큰 서명 키.
JWT_ACCESS_MINUTES60access 토큰 유효시간(분).
JWT_REFRESH_DAYS7refresh 토큰 유효시간(일).
ADMIN_EMAIL / ADMIN_PASSWORDadmin@local / admin1234users 테이블이 비어 있을 때 첫 부팅 시드 관리자.
YOLO_PRIMARY_WEIGHTSyolov8n.pt1차 사람 탐지 가중치.
YOLO_PPE_WEIGHTSppe.pt2차 PPE 분류 가중치.
YOLO_FIRE_WEIGHTSfire.pt2차 화재/연기 가중치.
YOLO_PRIMARY_CONF / YOLO_PPE_CONF / YOLO_FIRE_CONF0.30 / 0.35 / 0.35각 모델의 confidence 임계치. 낮을수록 민감.
FIRE_HSV_THRESHOLD0.02 (=2%)1차 화재 게이트. 프레임의 빨강/주황 픽셀 비율이 이 값을 넘을 때만 fire.pt 호출.
FALL_Y_VELOCITY_NORM0.30낙상 1차 — y좌표가 1초에 화면 높이의 이만큼 떨어지면 후보.
FALL_ASPECT_RATIO1.5낙상 1차 — 가로/세로 비율이 이 값 이상이면 누운 자세 후보.
FALL_STILL_SECONDS / FALL_STILL_MOVE_FRAC3.0 / 0.05낙상 — 누운 자세가 N초 정지(이동 < 화면 너비의 X%)면 후보.
SUSTAIN_NO_HELMET / SUSTAIN_FIRE / SUSTAIN_SMOKE / SUSTAIN_FALL5 / 5 / 5 / 10유형별 알람 발생을 위한 지속 시간(초). 이 시간 미만이면 무시.
RTSP_URL_TESTrtsp://…RTSP 연결 테스트용 기본 URL.
WEBCAM_DEVICE_NAME / WEBCAM_RTSP_URL노트북 웹캠을 RTSP로 송출하는 ffmpeg 설정.
파일 위치: backend/.env · 변경 후 백엔드 재시작 필요.
08

기술 스택

계층현재 사용 중상태비고
추론 프레임워크Ultralytics YOLOv8 + PyTorch구현됨운영 시 NVIDIA DeepStream / Triton + TensorRT 검토
객체 탐지 / 추적yolov8n + ByteTrack구현됨ByteTrack은 Ultralytics 내장 사용
안전장비 분류ppe.pt (10클래스)구현됨교체 가능 — snehilsanyal 기반
화재/연기 분류fire.pt (3클래스)구현됨Abonia1 기반 — 연기 정확도 향상 필요
포즈 추정룰 기반 (y속도/종횡비)부분 구현GPU 도입 시 RTMPose 또는 yolov8-pose 추가
스트리밍/디코딩OpenCV + FFmpeg (소프트웨어)부분 구현운영 GPU에서 NVDEC 하드웨어 디코딩으로
비동기 큐in-process queue.Queue부분 구현운영 시 Redis로 교체 (멀티 프로세스 워커)
백엔드 APIFastAPI + Uvicorn구현됨JWT 인증 (PyJWT + bcrypt)
데이터베이스PostgreSQL 17 (Docker)구현됨로컬은 :5433 컨테이너
프론트엔드Next.js 16 + React 19 + Tailwind구현됨Recharts로 차트 시각화
PDF 리포트ReportLab + 맑은고딕구현됨한글 폰트 임베드
영상 클립 인코딩ffmpeg + H.264 (libx264)구현됨10초 ±5s 클립을 브라우저 호환 mp4로
09

운영 환경 시나리오

현재: 개인 PC(CPU) + Docker Postgres + 1~4채널 데모 영상. 본인 PC만으로도 모든 기능이 동작하고 있습니다.
적용 위치① 엣지② 하이브리드③ 중앙
1차 필터현장 미니PC + GPU현장 미니PC + GPU본사 서버
2차 AI현장 미니PC + GPU본사 (트리거 시 영상 전송)본사 서버
회선 트래픽이벤트 메타데이터만메타데이터 + 트리거 클립전체 영상 (1.5Gbps+)
본사 GPU 부하거의 0이벤트 시에만상시 40~70%
10

앞으로 할 일 (로드맵)

최근 완료 (2026-05-18 검증 라운드)
  • 구현됨
    1차/2차 트리거 분리 — 실제 워커 루프 동작 확인
    rtsp_worker._inference_loop에서 1차 사람 탐지 매 프레임 / 2차 PPE는 사람 있을 때만 + 30초 재검증 / 2차 Fire는 HSV 통과 시만 / ROI·낙상 룰 동시 적용 — 카운터(primary_calls/ppe_calls/ppe_gated/fire_gated)가 stats에 누적되어 대시보드에 노출됨.
  • 구현됨
    ROI 폴리곤 편집 → DB → 워커 실시간 적용 흐름
    에디터 저장 시 PATCH /cameras/{id}/rois → WorkerManager.refresh_rois → StreamWorker.set_rois 즉시 반영. 다음 추론 틱부터 발 좌표 기반 체류 시간 누적.
  • 구현됨
    대시보드 — 2단계 트리거 변환율 + 추론 큐 카드
    Row 5에 트리거 유형별 총/확정/만료/변환율 표 + PPE 비동기 큐 사용량·처리량·평균 지연 카드.
  • 구현됨
    메뉴/페이지 권한 가드 (admin / manager 분리)
    Sidebar는 /users만 admin 전용. /cameras 페이지에 isAdmin 가드 추가 — 등록 폼·활성 토글·ROI·삭제 버튼이 관리자에게만 보임 (운영자는 403 받지 않고 UI 단계에서 차단).
  • 구현됨
    PDF 안전 리포트 — 트리거 변환율 섹션 렌더 검증
    데이터 있는 기간에서 "트리거"·"변환율"·"확정"·"1차"·"2차" 모두 정상 출력. 평가 §4 위험도 점수와 §5 권고문에 변환율 임계치(<5%) 자동 인용.
AI 모델 개선
  • 계획됨
    현장 데이터로 PPE 모델 파인튜닝
    지금 PPE 모델은 외부 데이터로 학습 — 실제 현장 영상으로 학습하면 정확도 ↑
  • 계획됨
    연기 감지 모델 교체/추가
    현재 fire.pt의 smoke 클래스 정확도가 낮음
  • 계획됨
    RTMPose 또는 YOLOv8-pose로 낙상 2차 검증
    지금은 룰 기반만. 포즈 추정 추가하면 오탐 감소
  • 계획됨
    허가 작업자 식별 (헬멧 색상 또는 ID 카드)
    ROI 침입을 비인가/인가로 분류
인프라 (GPU 서버 도입 시)
  • 계획됨
    TensorRT FP16 변환 (CPU → GPU 5~10배 가속)
  • 계획됨
    DeepStream / Triton 도입 (32~64채널 대응)
  • 계획됨
    NVDEC 하드웨어 디코딩
  • 계획됨
    Redis 큐 + 멀티 프로세스 워커
운영 기능
  • 계획됨
    외부 알람 발송 (SMS/이메일/카카오톡/Slack)
  • 계획됨
    카메라 다운/오류 시 운영자 통보
  • 계획됨
    라이브 그리드에 ROI 폴리곤 오버레이 표시
    지금은 ROI 편집 페이지에서만 다각형이 보임
  • 계획됨
    리포트 자동 발송 스케줄링
  • 계획됨
    다중 현장(파트너사) 지원
프로덕션 준비
  • 계획됨
    HTTPS + TLS 인증서
  • 계획됨
    HttpOnly 쿠키 + CSRF (현재 localStorage 토큰)
  • 계획됨
    Alembic DB 마이그레이션 (현재 ad-hoc ALTER)
  • 계획됨
    Sentry 에러 추적
  • 계획됨
    Prometheus + Grafana 모니터링
  • 계획됨
    Postgres 자동 백업
  • 계획됨
    GitHub Actions CI/CD
  • 계획됨
    단위·통합 테스트 추가 (현재 0%)
11

디렉토리 구조

AI_CCTV/
├── backend/                          # FastAPI 서버
│   ├── main.py                       # 앱 진입점 (lifespan, 라우터 등록)
│   ├── .env                          # ★ 환경변수 (모델·DB·인증 등 모든 설정)
│   ├── docker-compose.yml            # Postgres 컨테이너
│   ├── weights/                      # ★ AI 모델 가중치 (.pt 파일)
│   │   ├── yolov8n.pt                # 1차 사람 탐지 (자동 다운로드)
│   │   ├── ppe.pt                    # 2차 PPE 분류
│   │   └── fire.pt                   # 2차 화재/연기
│   ├── models/yolov8_model.py        # 모델 로더 + 클래스 매핑
│   ├── triggers/                     # 1차 트리거 룰
│   │   ├── ppe_trigger.py            # 30초 재검증 + 위반 캐시
│   │   ├── fire_trigger.py           # HSV 사전 필터
│   │   ├── roi_trigger.py            # 폴리곤 + 체류 시간
│   │   ├── fall_trigger.py           # y속도 + 종횡비
│   │   └── sustain.py                # 5초 지속 검증 + triggers 테이블
│   ├── rtsp_worker.py                # 카메라당 캡처+추론 스레드
│   ├── worker_manager.py             # 카메라별 워커 등록·라이프사이클
│   ├── inference_service.py          # 2차 PPE 비동기 큐
│   ├── clip_recorder.py              # 링버퍼 → H.264 mp4
│   ├── api/                          # FastAPI 라우터
│   │   ├── auth.py / users.py        # 로그인 / 사용자 CRUD
│   │   ├── cameras.py                # 카메라 + ROI + 스냅샷
│   │   ├── events.py / triggers.py   # 이벤트 / 트리거 조회
│   │   ├── stats.py / reports.py     # 통계 / PDF 리포트
│   │   ├── stream.py                 # WebSocket 멀티구독자
│   │   ├── detect.py                 # 정지 이미지 검출
│   │   └── webcam.py                 # 노트북 캠 ffmpeg 제어
│   ├── db/                           # DB
│   │   ├── database.py / models.py   # 엔진 + ORM 모델
│   │   └── repository.py             # 쿼리 + dedup + 통계
│   ├── auth/                         # bcrypt + JWT
│   ├── reports/pdf_builder.py        # 한글 PDF 생성
│   └── captures/clips/               # 자동 녹화된 mp4 (이벤트별)
│
└── frontend/                         # Next.js 16
    ├── app/
    │   ├── page.tsx                  # 대시보드
    │   ├── live/                     # 실시간 그리드
    │   ├── cameras/                  # 카메라 관리 + [id]/roi 편집
    │   ├── events/                   # 위험 감지 기록
    │   ├── reports/                  # PDF 리포트
    │   ├── users/                    # 사용자 관리
    │   ├── architecture/             # ★ 이 페이지
    │   └── login/                    # 로그인
    ├── components/                   # 재사용 컴포넌트
    └── lib/                          # 타입 + API 클라이언트 + 인증