영상 행동인식 AI 개발자가 처음 알아야 할 것
with. Detection(객체 감지), Tracking(객체 추적), Clip Sampling(클립 샘플링), Action Recognition(행동인식)
영상에서 사람의 행동을 인식한다고 하면 처음에는 한 장면을 보고 정답을 고르는 이미지 분류 문제처럼 생각하기 쉽다. 사람이 바닥 가까이에 있으면 falling(낙상), 손에 컵을 들고 있으면 medication(복약)처럼 분류하면 될 것 같기 때문이다.
실제 영상에서는 그렇게 단순하지 않다. 바닥에 이미 누워 있는 상태와 넘어지는 과정은 다르고, 물을 마시는 행동은 식사와 복약 모두에서 나타날 수 있다. 여러 사람이 동시에 등장하면 어떤 프레임의 사람이 다음 프레임의 누구와 같은 사람인지도 구분해야 한다.
따라서 영상 행동인식은 하나의 모델만으로 끝나는 문제가 아니다. 먼저 프레임에서 사람을 찾고, 같은 사람을 시간에 따라 추적하고, 사람별 프레임을 일정한 길이로 모은 다음, 그 시퀀스를 행동으로 분류해야 한다. 짧게 흔들리는 예측을 시간 구간으로 정리하는 작업도 필요하다.
이 과정에서 자주 등장하는 개념이 **Detection(객체 감지), Tracking(객체 추적), Crop(영역 추출), Clip Sampling(클립 샘플링), Action Recognition(행동인식), Temporal Post-processing(시간축 후처리)**이다. 이 용어들은 서로 분리된 기능이 아니라 실제 영상 처리 순서에서 앞뒤로 연결된다.
영상 프레임
↓
사람 감지(Detection)
↓
사람별 ID 유지(Tracking)
↓
사람 영역 추출(Crop)
↓
사람별 프레임 시퀀스 구성(Clip Sampling)
↓
영상-텍스트 행동 분류(X-CLIP)
↓
문맥 보정과 시간 구간화(Post-processing)
↓
행동 이벤트(Action Window Event)
그림 1. 영상 프레임이 사람별 행동 이벤트로 바뀌는 기본 흐름.
이 글에서는 녹화 영상 기반 행동인식에 필요한 사람 감지, 추적, 클립 구성, X-CLIP 분류와 시간 구간 생성까지 다룹니다. RTSP 실시간 연결, 영상 저장 정책, API 배포와 공인시험 평가 방법은 후속 글에서 이어갑니다. 현재 프로젝트에서 검증이 완료된 입력은 MP4 녹화 영상이며, RTSP 입력은 운영 단계의 별도 검증 대상입니다.
1. 영상 행동인식은 왜 이미지 분류와 다를까
이미지 분류는 한 장의 이미지에서 보이는 특징을 이용한다. 고양이와 자동차처럼 모양이 분명한 객체를 구분할 때는 한 장만으로도 충분한 경우가 많다.
행동은 시간의 변화까지 포함한다. 예를 들어 다음 세 장면은 한 프레임만 보면 비슷할 수 있다.
- 침대에 누워 쉬는 중
- 잠을 자는 중
- 서 있다가 넘어져 바닥에 도달한 직후
현재 자세만 보면 모두 lying(누워 있음)에 가깝지만, 행동의 의미는 서로 다르다. 특히 falling(낙상)은 자세 하나보다 서 있는 상태에서 중심이 낮아지고 바닥 방향으로 빠르게 이동하는 과정이 중요하다.
반대로 sleeping(수면)과 resting(휴식)은 큰 움직임이 없다는 공통점이 있다. 이 둘을 구분하려면 침대나 의자 같은 주변 문맥, 자세가 유지된 시간, 행동을 설명하는 텍스트 프롬프트를 함께 고려해야 한다.
즉, 영상 행동인식의 입력은 한 장의 프레임이 아니라 다음과 같은 시간 시퀀스에 가깝다.
사람 A: frame 101 → frame 102 → frame 103 → ... → frame 132
사람 B: frame 101 → frame 102 → frame 103 → ... → frame 132
여기서 중요한 점은 사람 A와 사람 B의 프레임이 섞이지 않아야 한다는 것이다. 이를 위해 객체 감지 다음에 객체 추적이 필요하다.
2. Detection은 행동을 맞히는 모델이 아니라 사람을 찾는 모델이다
Object Detection(객체 감지)은 프레임 안에서 객체가 있는 위치와 객체 종류를 찾는다. 일반적인 출력은 다음 세 요소로 구성된다.
| 출력 | 의미 |
|---|---|
bbox |
객체의 위치를 나타내는 사각형 좌표 |
class |
person(사람), chair(의자) 같은 객체 종류 |
confidence |
해당 감지 결과에 대한 모델 점수 |
Bounding Box(바운딩 박스)는 보통 다음과 같은 좌표로 표현한다.
bbox = (x1, y1, x2, y2)
(x1, y1) ┌──────────────┐
│ │
│ person │
│ │
└──────────────┘ (x2, y2)
그림 2. 사람 Bounding Box(바운딩 박스)의 기본 좌표 표현.
현재 프로젝트에서는 YOLO 계열 검출기로 person(사람) 클래스만 감지한다. 이 단계의 목적은 walking(걷기)이나 eating(식사)을 직접 결정하는 것이 아니라, 행동 분류기가 볼 사람 영역을 안정적으로 제공하는 것이다.
이 구분은 중요하다. 사람 감지 정확도가 높아졌다고 행동 분류 정확도가 반드시 같은 비율로 높아지는 것은 아니다. 검출기가 바뀌면 다음 요소도 함께 변할 수 있기 때문이다.
- Bounding Box(바운딩 박스)의 크기와 중심
- 사람 주변 배경이 Crop(영역 추출)에 포함되는 비율
- 가려진 사람을 유지하는 시간
- 작은 사람이나 바닥에 있는 사람의 감지 여부
예를 들어 낙상한 사람의 바운딩 박스가 자주 사라지면 행동 분류기는 낙상 과정의 마지막 프레임을 받지 못한다. 반대로 박스를 지나치게 크게 잡으면 소파, 침대, 식탁 같은 배경이 사람보다 더 큰 비중을 차지할 수 있다.
따라서 검출기는 독립적인 전처리 단계가 아니라 행동인식 모델의 입력을 만드는 첫 번째 구성요소다.
3. Tracking은 프레임 사이에서 같은 사람을 연결한다
객체 감지는 각 프레임을 독립적으로 처리한다. 첫 번째 프레임에서 발견한 사람이 두 번째 프레임의 누구와 같은 사람인지는 감지 결과만으로 알 수 없다.
Multi-Object Tracking(다중 객체 추적)은 프레임 사이의 감지 결과를 연결해 객체별 track_id(추적 ID)를 부여한다.
frame 1: [track_id=7] [track_id=12]
frame 2: [track_id=7] [track_id=12]
frame 3: [track_id=7] [track_id=12]
그림 3. Tracking(객체 추적)은 프레임이 바뀌어도 동일 인물의 ID를 유지한다.
현재 프로젝트에서는 YOLO의 사람 감지 결과를 ByteTrack에 전달한다. ByteTrack은 높은 점수의 감지 상자만 사용하는 대신 낮은 점수의 감지 상자도 기존 tracklet(짧은 추적 궤적)과 연관시켜, 가림이나 일시적인 감지 점수 저하로 추적이 끊기는 문제를 줄이는 방식이다.[1]
추적이 필요한 이유는 행동 분류 입력을 사람별로 분리하기 위해서다.
buffers = {
7: [crop_101, crop_102, crop_103, ...],
12: [crop_101, crop_102, crop_103, ...],
}
만약 track_id가 없다면 서로 다른 사람의 프레임이 하나의 시퀀스에 섞일 수 있다. 첫 프레임은 걷는 사람, 다음 프레임은 소파에 앉은 사람인 시퀀스를 행동 분류기에 넣는 셈이다.
Tracking(추적)이 완벽한 것은 아니다. 다음 상황에서는 ID가 바뀌거나 서로 바뀌는 ID Switch(ID 전환)가 발생할 수 있다.
- 사람이 다른 사람 뒤로 가려지는 경우
- 화면 밖으로 나갔다가 다시 들어오는 경우
- 카메라가 흔들리거나 장면이 급격하게 바뀌는 경우
- 여러 사람의 외형과 위치가 비슷한 경우
- 낮은 조도나 압축 손상으로 감지가 불안정한 경우
행동인식 시스템에서는 분류기 정확도뿐 아니라 track_id가 얼마나 안정적으로 유지되는지도 함께 확인해야 한다.
4. Crop은 사람을 중심으로 보되 문맥을 완전히 버리지 않는 과정이다
전체 프레임을 그대로 행동 분류기에 넣으면 여러 사람과 가구, 벽, 화면 자막이 함께 들어간다. 어떤 사람의 행동을 분류한 결과인지도 불명확해진다.
그래서 추적된 바운딩 박스를 기준으로 사람 영역을 Crop(영역 추출)한다. 현재 프로젝트에서는 다음 순서로 입력을 만든다.
- 사람 바운딩 박스를 일정 비율 확장한다.
- 확장된 영역을 정사각형으로 맞춘다.
- 모델 입력 크기인
224 × 224로 조정한다. - 같은
track_id의 Crop을 시간 순서대로 저장한다.
def make_person_crop(frame, bbox, margin_percent=10, output_size=224):
x1, y1, x2, y2 = bbox
# 실제 구현에서는 프레임 경계 확인, margin 확장,
# 정사각형 변환 후 resize를 수행한다.
crop = frame[y1:y2, x1:x2]
return resize(crop, (output_size, output_size))
사람만 정확하게 잘라내면 항상 좋은 것은 아니다. 행동에 따라 주변 객체가 중요한 단서가 되기 때문이다.
| 행동 | 도움이 될 수 있는 주변 문맥 |
|---|---|
| medication(복약) | 약 포장, 약병, 컵, 물병 |
| eating(식사) | 식기, 음식, 식탁 |
| sleeping(수면) | 침대, 이불 |
| resting(휴식) | 의자, 책, TV 리모컨 |
| falling(낙상) | 바닥과 사람 자세의 관계 |
Crop이 너무 작으면 손에 든 물체나 주변 가구가 사라진다. 너무 크면 배경이 행동 분류를 지배할 수 있다. 이 때문에 Crop Margin(Crop 여백)은 단순한 화면 설정이 아니라 모델 입력 계약의 일부다.
5. Clip Sampling은 어느 프레임을 얼마나 모을지 정하는 일이다
행동 분류기는 무한히 긴 영상을 한 번에 처리하지 않는다. 추적된 사람의 Crop 중 일정한 수의 프레임을 모아 하나의 Clip(클립)을 만든다.
현재 프로젝트의 기본 예시는 사람별 최근 32개 Crop을 Sliding Buffer(슬라이딩 버퍼)에 보관하는 방식이다.
from collections import deque
track_buffers: dict[int, deque] = {}
def add_crop(track_id: int, crop, sequence_length: int = 32):
if track_id not in track_buffers:
track_buffers[track_id] = deque(maxlen=sequence_length)
track_buffers[track_id].append(crop)
여기서 서로 다른 두 종류의 간격을 구분해야 한다.
Crop Sample Stride(프레임 수집 간격)
몇 프레임마다 Crop을 버퍼에 넣을지 정한다.
1: 모든 프레임을 수집2: 두 프레임마다 한 번 수집4: 네 프레임마다 한 번 수집
영상 FPS를 F, 시퀀스 길이를 N, 수집 간격을 S라고 하면 시퀀스가 포함하는 시간 범위는 대략 다음과 같다.
temporal coverage ≈ N × S / F seconds
예를 들어 30 FPS 영상에서 32개 프레임을 매 프레임 수집하면 약 1.07초를 본다. 같은 32개를 네 프레임마다 수집하면 약 4.27초를 보지만, 짧은 동작의 세부 변화는 더 많이 건너뛴다.
Classification Stride(분류 실행 간격)
완성된 버퍼를 몇 프레임마다 다시 분류할지 정한다. 이 값은 입력 시퀀스의 시간 범위가 아니라 예측을 새로 계산하는 빈도를 제어한다.
Crop Sample Stride = 시퀀스를 어떻게 구성하는가
Classification Stride = 시퀀스를 얼마나 자주 분류하는가
두 값을 하나로 생각하면 안 된다. 수집 간격을 키우면 모델이 보는 시간 범위가 달라지고, 분류 간격을 키우면 이벤트 갱신 속도와 연산량이 달라진다.
| 설정 변화 | 기대 효과 | 주의할 점 |
|---|---|---|
| 수집 간격 증가 | 더 긴 행동 문맥 확보 | 짧은 동작을 놓칠 수 있음 |
| 수집 간격 감소 | 세밀한 움직임 보존 | 비슷한 프레임이 많아짐 |
| 분류 간격 증가 | 추론량 감소 | 알림과 화면 갱신이 늦어짐 |
| 분류 간격 감소 | 빠른 예측 갱신 | GPU 사용량과 중복 예측 증가 |
따라서 Sequence Length(시퀀스 길이), Sample Stride(수집 간격), Classification Stride(분류 간격)는 모델 가중치와 함께 버전으로 관리해야 한다.
6. X-CLIP은 영상을 자연어 행동 설명과 비교한다
현재 프로젝트의 기본 행동 분류기는 microsoft/xclip-base-patch16-zero-shot이다. 여기서 사용하는 X-CLIP은 언어-이미지 사전학습 모델을 영상 인식으로 확장한 모델이다. Cross-frame Attention(프레임 간 어텐션), Multi-frame Integration Transformer(다중 프레임 통합 트랜스포머), Video-specific Prompt Generator(영상 특화 프롬프트 생성기)를 통해 여러 프레임과 텍스트의 관계를 계산한다.[2][3]
전통적인 고정 분류기는 마지막 출력층이 walking, sleeping 같은 정해진 클래스 수에 맞춰져 있다. X-CLIP의 Zero-shot(제로샷) 경로에서는 영상과 자연어 후보 문장의 유사도를 비교할 수 있다.
영상 시퀀스
├─ "person walking across a room"
├─ "person taking medicine with water"
├─ "person sleeping in bed"
└─ "person falling from standing position"
→ 각 문장과 영상의 유사도 점수 계산
현재 프로젝트는 여러 자연어 프롬프트를 다음 8개 행동으로 매핑한다.
| 구분 | Action Class(행동 클래스) |
|---|---|
| 일상행동 | walking(걷기) |
| 일상행동 | medication(복약) |
| 일상행동 | sleeping(수면) |
| 일상행동 | eating(식사) |
| 일상행동 | exercising(운동) |
| 일상행동 | resting(휴식) |
| 위험행동 | falling(낙상) |
| 위험행동 | fighting(싸움) |
예를 들어 person taking medicine from a packet과 person swallowing medicine with water는 서로 다른 프롬프트지만 최종적으로 medication(복약) 클래스에 속한다.
이 방식은 프롬프트를 통해 행동의 시각적 의미를 구체적으로 설명할 수 있다는 장점이 있다. 반면 문장의 표현이 실제 영상과 맞지 않거나 서로 비슷한 행동을 충분히 구분하지 못하면 결과가 흔들릴 수 있다.
medication(복약)과 eating(식사)은 모두 손을 입으로 가져갈 수 있다. sleeping(수면)과 resting(휴식)은 움직임이 적다. 프롬프트 개수만 늘린다고 문제가 자동으로 해결되는 것도 아니다. 특정 클래스에 프롬프트가 지나치게 많으면 점수 집계 방식에 따라 그 클래스가 유리해질 수 있다.
따라서 프롬프트는 다음 항목과 함께 하나의 계약으로 관리하는 편이 안전하다.
- 전체 프롬프트 목록
- 프롬프트에서 8개 클래스로의 매핑
- 프롬프트별 점수 또는 클래스별 점수 집계 방식
- Top-k(상위 k개) 개수
- 프롬프트 버전
- 검증에 사용한 데이터 분리 기준
7. BGR과 RGB도 모델 입력 계약이다
OpenCV로 읽은 영상 프레임은 일반적으로 BGR 채널 순서를 사용한다. 많은 사전학습 비전 모델과 이미지 처리 문서는 RGB를 기준으로 설명한다.
OpenCV frame: B, G, R
일반적인 모델 입력: R, G, B
채널 순서를 잘못 처리해도 배열 크기는 정상이다. 프로그램도 오류 없이 실행된다. 하지만 모델이 학습 때 보던 색 분포와 다른 입력을 받기 때문에 출력 점수가 달라질 수 있다.
현재 프로젝트는 이 차이를 숨기지 않고 BGR Branch(BGR 분기)와 RGB Branch(RGB 분기)를 각각 계산할 수 있게 구성했다. 두 분기의 확률을 평균하거나, 검증된 보정 모델이 각 분기의 점수와 영상 특징을 함께 사용하도록 설계할 수 있다.
중요한 것은 BGR과 RGB 중 하나가 항상 정답이라는 주장이 아니다. 학습, 검증, 배포에서 같은 채널 정책을 사용하고 그 정책을 기록하는 것이 핵심이다.
input_color_order: bgr_rgb_mean
crop_size: [224, 224]
sequence_length: 32
crop_sample_stride: 1
classification_stride: 16
prompt_profile: observable_v2
모델 가중치가 같더라도 색상 순서, Crop 크기, 시퀀스 구성과 프롬프트가 달라지면 실제 시스템은 다른 입력을 처리한다. 영상 행동인식에서 ‘같은 모델’이라고 말하려면 가중치뿐 아니라 이 전처리 계약까지 같아야 한다.
8. 모델 점수는 바로 최종 행동 이벤트가 아니다
X-CLIP이 반환하는 값은 후보 프롬프트에 대한 상대적인 점수다. 한 번의 추론에서 가장 높은 점수가 나왔다고 해서 해당 행동이 확정됐다는 뜻은 아니다.
실제 시스템은 다음 정보를 추가로 사용할 수 있다.
- Top-k 행동과 각 점수
- Bounding Box의 폭, 높이와 종횡비
- 사람 중심점의 이동량
- 최근 수 초 동안의 자세 변화
- 화면에 동시에 존재하는 사람 수
- 컵, 식기, 약 관련 물체 같은 Context Object(문맥 객체)
- 이전 행동 구간과 현재 행동 구간의 연속성
예를 들어 낙상은 단순히 가로로 긴 바운딩 박스만으로 결정하면 안 된다. 소파에 누운 사람도 비슷한 박스 모양을 가질 수 있다. 낙상 판단에는 모델 점수와 함께 중심점의 하강, 자세 변화, 낮은 자세의 지속 같은 시간 정보가 필요하다.
복약과 식사도 컵 하나만 보고 구분하기 어렵다. 컵은 두 행동 모두에 나타날 수 있다. 따라서 문맥 객체는 행동을 강제로 바꾸는 정답이 아니라, 모델 점수의 불확실성을 해석하는 보조 근거로 사용해야 한다.
이러한 후처리는 두 종류로 구분하는 것이 좋다.
| 구분 | 예시 | 주의점 |
|---|---|---|
| 관측 기반 규칙 | 이동량, 박스 비율, 물체 거리 | 실제 추론 시 얻을 수 있는 정보만 사용 |
| 학습된 보정 | 분류 점수와 motion feature를 이용한 calibration | 평가 대상 영상의 정답이 학습에 들어가면 안 됨 |
파일명, 영상 번호, 공인시험 행동 순서나 특정 정답 시간대를 조건으로 사용하는 방식은 운영 환경에서 재현되지 않는다. 이는 일반적인 후처리가 아니라 평가 데이터에 대한 하드코딩이 된다.
9. Frame Event(프레임 이벤트)와 Action Window Event(행동 구간 이벤트)는 서로 다른 질문에 답한다
영상 분석 결과는 프레임 단위와 시간 구간 단위로 나눌 수 있다.
Frame Event(프레임 이벤트)
특정 시점에 화면에 누가 있고 어디에 있는지를 표현한다.
{
"frame_index": 420,
"timestamp_sec": 14.0,
"tracks": [
{
"track_id": 7,
"bbox": [320, 110, 510, 690],
"detection_conf": 0.94
}
]
}
Action Window Event(행동 구간 이벤트)
한 명의 추적 객체가 일정 시간 동안 무엇을 했는지를 표현한다.
{
"track_id": 7,
"start_timestamp_sec": 12.9,
"end_timestamp_sec": 14.0,
"actions": [
{
"mapped_label": "walking",
"confidence": 0.81
}
]
}
두 이벤트는 상속 관계가 아니라 같은 분석 결과를 서로 다른 축으로 표현한 것이다.
시간 →
t=10 t=11 t=12 t=13
track_id=7 ● ● ● ● ← Action Window Event
track_id=12 ● ● ● ●
↑
└ Frame Event
그림 4. 같은 분석 결과를 시점 기준과 추적 객체 기준으로 나눈 이벤트 구조.
Frame Event는 실시간 화면에 Bounding Box를 그리거나 현재 인원을 확인할 때 유용하다. Action Window Event는 행동 알림, 통계, API 전송과 평가에 적합하다.
10. 영상에서 행동 이벤트까지, 처리 순서를 고정한다
앞에서 설명한 개념을 하나의 파이프라인으로 정리하면 다음과 같다.
1. MP4 영상에서 프레임과 타임스탬프 읽기
2. YOLO로 사람 Bounding Box 감지
3. ByteTrack으로 사람별 track_id 유지
4. track_id별 사람 Crop 생성
5. 최근 N개 Crop을 Sliding Buffer에 저장
6. Classification Stride마다 준비된 시퀀스 선택
7. X-CLIP으로 영상과 행동 프롬프트 유사도 계산
8. 프롬프트 점수를 8개 행동 클래스로 매핑
9. BBox, motion, context 정보를 이용해 결과 보정
10. Frame Event와 Action Window Event 생성
11. 영상 클립과 이벤트의 clip_id 연결
12. API 전송 또는 오프라인 평가
아래 코드는 구조를 보여 주기 위한 최소 예제다. 실제 프로젝트에서는 추적 종료 처리, 프레임 경계, GPU 배치, 오류 처리와 이벤트 직렬화가 추가된다.
for frame_index, timestamp_sec, frame in source.frames():
detections = tracker.track(frame)
for detection in detections:
crop = crop_and_pad(
frame,
detection.bbox,
margin_percent=10,
output_size=224,
)
crop_buffer.add(detection.track_id, crop)
if frame_index % classification_stride != 0:
continue
for track_id in crop_buffer.ready_tracks():
sequence = crop_buffer.get_sequence(track_id)
model_input = classifier.preprocess(sequence)
result = classifier.classify(model_input, top_k=5)
yield make_action_window_event(
track_id=track_id,
result=result,
timestamp_sec=timestamp_sec,
)
이 코드를 실제 운영 코드로 만들 때 가장 먼저 고정해야 하는 항목은 다음과 같다.
- 어떤 사람 감지 모델과 가중치를 사용하는가
- 추적기는 어떤 설정으로 ID를 연결하는가
- Crop 여백과 입력 해상도는 얼마인가
- 시퀀스 길이와 프레임 수집 간격은 얼마인가
- 행동을 몇 프레임마다 다시 분류하는가
- 입력 채널은 BGR, RGB 또는 두 분기 결합인가
- 어떤 프롬프트와 클래스 매핑을 사용하는가
- 후처리는 어떤 관측 정보만 사용하는가
- 이벤트의 시작과 종료 시각은 어떻게 계산하는가
- 학습과 평가, 운영 코드가 같은 입력 계약을 사용하는가
이 설정을 코드 여러 곳에 흩어 놓기보다 설정 파일과 실행 manifest(실행 명세)에 기록하는 편이 재현하기 쉽다.
11. 좋은 오프라인 점수가 곧 CCTV 운영 성능은 아니다
녹화 영상 평가에서는 모든 프레임이 파일 안에 있고 영상 시작과 종료도 명확하다. CCTV RTSP 스트림에서는 상황이 달라진다.
- 네트워크 지연과 연결 끊김이 발생한다.
- 디코더가 프레임을 늦게 전달할 수 있다.
- 추론이 입력 속도를 따라가지 못하면 프레임이 쌓인다.
- 카메라 각도, 조도와 압축률이 평가 영상과 다르다.
- 사람이 화면 밖으로 나가거나 장시간 가려질 수 있다.
따라서 운영 검증에서는 분류 정확도 외에 다음 지표가 필요하다.
| 운영 지표 | 확인할 내용 |
|---|---|
| Effective FPS(유효 처리 FPS) | 초당 실제로 처리한 프레임 수 |
| End-to-End Latency(종단 지연) | 촬영 시점부터 이벤트 생성까지 걸린 시간 |
| Dropped Frames(유실 프레임) | 처리하지 못하고 버린 프레임 수 |
| ID Switch(ID 전환) | 동일 인물의 추적 ID가 바뀐 횟수 |
| False Alarms per Hour(시간당 오탐) | 운영 시간 기준 잘못 발생한 위험 알림 |
| Event Persistence(이벤트 지속성) | 행동 라벨이 짧게 흔들리지 않고 유지되는지 |
특히 falling(낙상)과 fighting(싸움) 같은 위험행동은 전체 평균 정확도만으로 평가하기 어렵다. 위험행동 Recall(재현율), 오탐 빈도와 알림 지연시간을 별도로 확인해야 한다.
마무리
영상 행동인식은 프레임 한 장을 분류하는 작업이 아니다. Detection(객체 감지)은 사람의 위치를 찾고, Tracking(객체 추적)은 프레임 사이에서 같은 사람을 연결한다. Crop과 Clip Sampling은 사람별 시간 시퀀스를 만들고, X-CLIP은 그 시퀀스를 자연어 행동 설명과 비교한다. 마지막으로 문맥과 시간 정보를 이용해 짧은 모델 출력을 실제 행동 구간으로 바꾼다.
이제 “영상 전체를 X-CLIP에 넣으면 행동이 바로 나오지 않을까?”라는 질문에 답할 수 있다. 한 사람이 짧게 등장하는 단순 영상에서는 가능할 수 있다. 그러나 여러 사람이 있는 CCTV 환경에서 사람별 행동과 정확한 시간 구간을 얻으려면 감지, 추적, 샘플링과 이벤트 설계가 함께 필요하다.
영상 행동인식에서 먼저 설계해야 하는 것은 가장 큰 모델 하나가 아니다. 같은 사람의 프레임을 같은 규칙으로 모아, 같은 의미의 행동 이벤트로 바꾸는 재현 가능한 파이프라인이다.
참고 자료
- Yifu Zhang et al., ByteTrack: Multi-Object Tracking by Associating Every Detection Box, ECCV 2022.
- Bolin Ni et al., Expanding Language-Image Pretrained Models for General Video Recognition, ECCV 2022.
- Hugging Face Transformers, X-CLIP Model Documentation.
- Microsoft, microsoft/xclip-base-patch16-zero-shot.
- Ultralytics, ByteTrack API Reference.
이 글의 설정값과 코드 예시는 영상 행동인식 파이프라인을 설명하기 위한 예시입니다. 카메라 환경, 영상 FPS, 대상 행동과 데이터셋에 따라 별도의 검증이 필요합니다. 본 시스템의 행동 분석 결과는 안전관리 보조 정보이며, 의료적 진단이나 응급상황에 대한 단독 판단 근거로 사용해서는 안 됩니다.