TRENDSHIFT 딥다이브 · 영상 시맨틱 검색 분석

SentrySearch 딥다이브
— "빨간 트럭이 정지신호 무시한 장면" 한 문장으로 영상을 찾는다

영상을 자막·캡션으로 옮기는 중간 단계 없이, 영상 픽셀과 한국어 문장을 같은 768차원 벡터 공간에 놓고 비교하는 시맨틱 영상 검색 CLI. ⭐4.3k · 401 forks · Tesla 센트리 모드 영상에서 출발해 모든 영상으로 확장. (저장소: ssrajadh/sentrysearch · Apache-2.0 · Python 100%)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

SentrySearch가 정확히 무엇을 하는 도구인가

SentrySearch"찾고 싶은 장면을 자연어로 입력하면 영상에서 해당 구간만 잘라 클립으로 돌려주는" 시맨틱 영상 검색 CLI다. README 한 줄 설명 그대로 — "Type what you're looking for, get a trimmed clip back." 영상을 텍스트로 받아쓰는 STT나 프레임 캡셔닝 같은 중간 단계 없이, 영상 픽셀을 직접 벡터로 만들어 검색어 벡터와 비교한다.

한 컷 비유

"영상에 자막을 다는 중간 단계 없이, 영상 그 자체를 검색한다"

일반 영상 검색은 "프레임을 캡션으로 옮기거나 음성을 받아쓴 뒤" 그 텍스트를 검색한다. 음성 없는 대시캠은 검색 불가능하고, 캡션이 부정확하면 검색도 부정확하다.

SentrySearch는 그 중간 단계를 빼버린다. 영상 픽셀을 직접 768차원 벡터로 만들고, 검색어도 같은 공간의 벡터로 만들어 바로 비교한다. "중간 사람(middleman)을 없앤다"는 이 발상이 HN(해커뉴스)·GIGAZINE에서 반향을 일으켰다.

2왜 주목받는가

트렌딩 이유와 기존 방식 대비 강점
기존 방식의 불편함
"AI가 일단 글로 옮기게 하자"라는 우회로

영상 → 캡션/자막 → 텍스트 검색이라는 우회로는 두 가지 위험이 있다. 첫째, 캡션 단계에서 정보가 손실된다. 한 프레임에서 "빨간 트럭, 신호등 빨강, 횡단보도, 행인 2명"을 다 잡으려면 캡션이 길어지는데 짧으면 손실, 길면 비용 폭발.

둘째, 단어 불일치. 사람이 "트럭"이라 검색하는데 AI가 "화물차"로 캡션을 달았다면 영영 못 찾는다. STT는 음성 없는 영상에 아예 무용지물이다.

SentrySearch의 해법
픽셀과 단어를 처음부터 같은 공간에 놓기

영상 픽셀과 텍스트를 처음부터 같은 768차원 공간에 넣는다. "빨간 트럭"이라는 문장과 진짜 빨간 트럭이 찍힌 영상 30초가 비슷한 벡터가 되도록 임베딩 모델이 미리 학습돼 있다. 중간 단계가 없으니 정보 손실도, 단어 불일치도 없다. 수 시간 영상에서 sub-second 검색이 가능해진다.

기존 영상 검색 방식 비교

방식SentrySearch 대비 한계
STT(음성 인식)오디오를 받아써 검색 — 음성 없는 대시캠/CCTV에는 무용지물
프레임 캡셔닝AI가 캡션을 잘못 달면 검색 실패. 영상당 캡션 수천 개면 비용 폭발
키워드 태깅사람이 수동 태깅 — 시간 소모, 미리 정한 태그 밖은 검색 불가
SentrySearch영상 픽셀 직접 임베딩 → 텍스트와 같은 벡터 공간에서 즉시 비교 (중간 단계 0)

여기에 README가 강조하는 차별점이 더 있다. sentrysearch highlights이상 장면(anomaly)을 자동 추출하고, 정지 프레임을 감지해 건너뛰며, 거의 같은 결과를 자동 중복 제거(dedupe)한다. Tesla 메타데이터(속도·위치·시간) 오버레이, 멀티카메라 합성(SentryMerge)·얼굴 가림(SentryBlur) 연계까지 묶여 있다.

3기술 스택 전체 지도

언어 구성 · 임베딩 백엔드 · 벡터 DB · 영상 처리

언어 구성

Python ████████████████████████████████ 100% ← CLI, 청킹, 임베딩, 검색 전 영역 (Python 3.11+ · uv 패키지 매니저 · pyproject.toml 단일 설정)

임베딩 백엔드 (3종 선택)

백엔드역할상세
Gemini Embedding 2기본(클라우드)Google API. 영상 픽셀을 네이티브로 임베딩. 빠르고 정확하나 영상이 구글로 전송됨
DashScope Qwen3-VL클라우드 대안Alibaba DashScope API. 멀티모달 임베딩. 지역별 요금 상이. 설치: uv tool install ".[qwen-cloud]" 필요
로컬 Qwen3-VL프라이버시/무료qwen8b / qwen2b 모델을 내 GPU에서 실행. 영상이 외부로 나가지 않음

벡터 DB · 검색

기술역할상세
ChromaDB벡터 저장/검색로컬 임베디드 벡터 DB. MRL 차원 절단으로 768차원에 통일
코사인 유사도유사도 측정검색어 벡터와 영상 청크 벡터의 방향 비교. 기본 임계값 0.41
중복 제거(dedupe)결과 정제유사도 상한 0.9 권장 — 거의 같은 클립을 한 개로 합침

영상 처리 / 로컬 추론

기술역할상세
FFmpeg / imageio-ffmpeg영상 디코딩·트리밍청킹, 해상도/FPS 축소, 매칭 구간 클립 추출
PyTorch · torchvision로컬 모델 실행로컬 Qwen3-VL 추론 런타임
bitsandbytes4-bit 양자화NVIDIA 8~16GB VRAM에서 8B 모델 구동 (.[local-quantized])
geopy (선택)역지오코딩Tesla 좌표 → 지명 변환 (오버레이용)

4아키텍처 심화 분석

인덱싱 파이프라인 · 청킹 · 임베딩 추상화 · 검색 흐름

전체 파이프라인 구조도

┌──────────────────────────────────────────────────────────────┐ │ 입력: /path/to/footage (대시캠/CCTV/유튜브 영상 파일들) │ └───────────────────────────┬──────────────────────────────────┘ │ sentrysearch index ┌───────────────▼────────────────┐ │ ① 전처리 (FFmpeg) │ │ 480p · 5fps 다운스케일 │ │ 정지 프레임 감지 → 스킵 │ └───────────────┬────────────────┘ ▼ ┌────────────────────────────────┐ │ ② 청킹 (chunk + overlap) │ │ 30초 단위, 5초 겹침 │ │ 0~30 / 25~55 / 50~80 ... │ └───────────────┬────────────────┘ ▼ ┌────────────────────────────────┐ │ ③ 임베딩 (백엔드 교체 가능) │ │ Gemini2 | DashScope | 로컬 Qwen│ │ → 청크마다 768차원 벡터 │ └───────────────┬────────────────┘ ▼ ┌────────────────────────────────┐ │ ④ 저장 (ChromaDB) │ │ 벡터 + 메타(파일/타임스탬프) │ └───────────────┬────────────────┘ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ sentrysearch search "빨간 트럭" ┌───────────────▼────────────────┐ │ 검색어 → 같은 백엔드로 임베딩 │ │ → 768차원 벡터 │ └───────────────┬────────────────┘ ▼ ┌────────────────────────────────┐ │ ChromaDB 코사인 유사도 Top-K │ │ threshold 0.41 미만 → 경고 │ │ dedupe → FFmpeg 트리밍 → 클립 │ └────────────────────────────────┘

핵심 설계 패턴 ①: 멀티모달 공동 임베딩 공간

패턴
Joint Embedding Space (공동 임베딩 공간)
텍스트와 영상이라는 서로 다른 모달리티를 같은 768차원 공간에 투영한다. "빨간 트럭" 문장 벡터와 빨간 트럭 영상 벡터가 가까워지도록 사전 학습된 멀티모달 모델 덕에, 둘을 같은 자로 잴 수 있다.
텍스트 "red truck at a stop sign" ─┐ ├─→ 같은 768차원 공간 → 코사인 유사도 비교 영상 30초 (픽셀) ─┘ (중간에 '글로 옮기는' 단계 없음)

핵심 설계 패턴 ②: 청킹 + 오버랩

한 시간짜리 영상을 통째로 임베딩할 수 없다. 모델 입력 한계도 있고 비용도 길이에 비례한다. 그래서 30초 단위로 자르되 5초씩 겹치게 자른다. 이벤트가 청크 경계에 걸쳐 어느 쪽에도 안 잡히는 일을 막는다.

책 발췌 비유

백과사전에서 특정 사건을 찾을 때, 1·2·3챕터로 정확히 잘라 검색하면 사건이 1챕터 끝과 2챕터 시작에 걸쳐 있을 때 둘 다에서 빠질 수 있다.

그래서 발췌를 만들 때 일부러 페이지를 겹치게 자른다. 같은 사건이 두 발췌에 동시에 들어가도 손해는 없고, 빠지는 일은 막는다. LLM에 긴 문서를 넣을 때 쓰는 청킹+오버랩과 똑같은 전략이다.

핵심 설계 패턴 ③: 백엔드 추상화 (Strategy 패턴)

임베딩 생성을 하나의 인터페이스 뒤로 숨겨, --backend 플래그만 바꾸면 Gemini / DashScope / 로컬 Qwen이 갈아끼워진다. 인덱싱 코드와 검색 코드는 백엔드가 무엇인지 몰라도 된다. 민감 영상은 로컬, 공개 영상은 클라우드를 인덱스 단위로 선택할 수 있는 유연성이 여기서 나온다.

핵심 설계 패턴 ④: 정지 프레임 스킵 (비용 최적화)

대시캠·주차 영상은 차가 멈춰 화면이 거의 안 변하는 구간이 많다. SentrySearch는 JPEG 파일 크기 비교로 "이 구간은 정적"이라 판단하고 그 청크를 통째로 건너뛴다. 임베딩 호출 수 자체가 줄어 비용이 내려간다.

비용 모델 (Gemini Embedding 2 기준)
프레임 단위 과금 — 1시간 ≈ ~$2.84

README 계산: 1시간 = 3,600초 = 3,600 프레임 × $0.00079~$2.84/시간 (기본 30초 청크·5초 오버랩). 정지 프레임이 많은 영상일수록 스킵으로 실제 비용은 더 내려간다. 100시간이면 단순 환산 ~$284이므로, 대량 인덱싱 전엔 비용을 가늠해야 한다.

5디렉토리 구조 해부

작고 단정한 단일 패키지 — 읽기 좋은 레포
ssrajadh/sentrysearch/ ├── sentrysearch/ # ⭐ 메인 파이썬 패키지 (CLI 진입점 + 핵심 로직) │ # 인덱싱·청킹·임베딩 백엔드·ChromaDB·검색 모듈 ├── tests/ # 테스트 코드 ├── docs/ # 문서 (사용법·백엔드별 가이드) ├── .github/ # CI/이슈 템플릿 등 GitHub 설정 ├── .env.example # API 키 등 환경변수 예시 (GEMINI/DashScope) ├── pyproject.toml # ⭐ 빌드·의존성·CLI 엔트리포인트·extras 단일 설정 ├── uv.lock # uv 잠금 파일 (재현 가능한 의존성) ├── README.md # 영문 설명 (한 줄 요약 + 비용/하드웨어 표) ├── README.zh.md # 중문 README ├── CONTRIBUTING.md # 기여 가이드 ├── LICENSE # Apache-2.0 └── .gitignore

핵심은 pyproject.tomlextras로 설치 변형을 정의한다는 점이다. .[local](로컬 Qwen), .[local-quantized](4-bit NVIDIA), .[tesla](메타데이터 오버레이) — 무거운 의존성(PyTorch, bitsandbytes, geopy)을 필요한 사람만 선택 설치하게 분리했다. 초보자가 "왜 설치가 무거운가"를 배우기에 좋은 실전 예시다.

용어
optional dependencies (extras)
파이썬 패키지가 "기본 설치"와 "추가 기능 설치"를 나누는 방법. pip install pkg[local]처럼 대괄호 안 이름이 extra다. 모두에게 PyTorch를 강제하지 않고, 로컬 추론이 필요한 사람만 받게 한다.

6학습 포인트 (기술별)

이 레포에서 무엇을 배울 수 있는가

A. 멀티모달 임베딩과 벡터 검색

배울 것: 텍스트·영상을 같은 공간에 넣는 임베딩의 원리, 코사인 유사도로 의미 거리를 재는 법, 임계값(0.41)으로 "확신 없음"을 거르는 설계. 이 레포는 RAG·시맨틱 검색의 핵심 개념을 영상이라는 직관적 대상으로 보여준다.

B. 벡터 DB 다루기 (ChromaDB)

배울 것: 임베딩을 저장하고 "가장 비슷한 것"을 빠르게 찾는 벡터 DB의 사용법. MRL 차원 절단으로 768차원 통일 — 백엔드마다 다른 출력 차원을 한 공간에 맞추는 실전 트릭.

C. 청킹 + 오버랩 전략

배울 것: 긴 데이터를 조각내되 경계 손실을 막는 표준 패턴. 영상의 30초/5초 오버랩은 LLM에 긴 문서를 넣을 때의 청킹과 동일한 발상이다. 한 번 이해하면 모든 검색·RAG 파이프라인에 재활용된다.

D. 백엔드 추상화 (클라우드 vs 로컬)

배울 것: 같은 인터페이스 뒤에 Gemini/DashScope/로컬 Qwen을 갈아끼우는 Strategy 패턴. 프라이버시·비용·정확도의 트레이드오프를 코드 구조로 푸는 법을 배운다.

E. 현대적 파이썬 패키징 (uv + pyproject.toml)

배울 것: setup.py 없이 pyproject.toml 하나로 빌드·의존성·CLI 엔트리포인트·extras를 모두 선언하는 법. uv tool install로 CLI를 격리 환경에 까는 pipx 대안 워크플로.

F. 비용·성능 엔지니어링

배울 것: 480p/5fps 다운스케일, 정지 프레임 스킵(JPEG 크기 비교), 결과 dedupe 등 "같은 결과, 더 적은 비용"을 위한 실전 최적화. 프레임 단위 과금 모델을 직접 계산해보며 클라우드 AI 비용 감각을 기른다.

7하드웨어 / 시스템 요구사항

클라우드는 가볍고, 로컬은 GPU 메모리가 좌우한다
항목클라우드 모드(Gemini/DashScope)로컬 모드(Qwen3-VL)
Python3.11 또는 3.12 (3.13 이상 미지원)3.11 또는 3.12 (3.13 이상 미지원)
GPU불필요필수 (Apple Silicon 또는 NVIDIA)
네트워크API 호출 필수모델 다운로드 후 오프라인 가능
비용~$2.84/시간 (Gemini)무료 (전기·하드웨어만)
프라이버시영상이 외부 전송됨영상이 로컬에만 머묾
공통FFmpeg(자동 동봉 imageio-ffmpeg) · ChromaDB 로컬 저장 공간

로컬 모드 — GPU 메모리별 자동 선택

하드웨어설치 명령자동 선택 모델
Apple Silicon 24GB+uv tool install ".[local]"qwen8b
Apple Silicon 16GBuv tool install ".[local]"qwen2b
NVIDIA 18GB+ VRAMuv tool install ".[local]"qwen8b
NVIDIA 8~16GB VRAMuv tool install ".[local-quantized]"qwen8b (4-bit)
Apple Silicon 8GBuv tool install ".[local]"qwen2b (메모리 부족 가능, Gemini API 권장)
동작 안 함
Intel Mac · 전용 GPU 없는 머신

README가 명시: 로컬 모드는 "Intel Macs and machines without a dedicated GPU"에서는 잘 동작하지 않는다. 이런 환경은 Gemini/DashScope 클라우드 백엔드를 써야 한다.

8직접 해볼 수 있는 실습 과제

난이도별 5가지 과제
과제 1

이미지 검색 미니 실험 ★ 초급 1시간

Gemini API 키만 발급받아, 사진 10장을 임베딩해서 ChromaDB에 넣고 텍스트로 검색해본다. 영상 인덱싱은 비싸지만 이미지로 같은 원리(임베딩→벡터DB→코사인 유사도)를 저비용으로 체험할 수 있다.

확인 포인트: "강아지"로 검색했을 때 개 사진이 상위에 오는가? 임계값(0.41)을 바꾸면 결과가 어떻게 달라지는가?
과제 2

SentrySearch 설치 & 첫 검색 ★ 초급 1시간

# 1. 클론 후 설치 (uv 필요) — Gemini 백엔드 기본
#    DashScope 백엔드 사용 시: uv tool install ".[qwen-cloud]"
git clone https://github.com/ssrajadh/sentrysearch
cd sentrysearch && uv tool install .

# 2. 환경 초기화 (.env에 API 키 입력)
sentrysearch init

# 3. 짧은 드라이빙 영상 인덱싱 + 검색
sentrysearch index ./clips --verbose
sentrysearch search "빨간 트럭" --results 3
sentrysearch stats
--verbose로 청킹·전처리·임베딩이 내부에서 어떻게 도는지 관찰한다.
과제 3

두 백엔드 벤치마크 ★★ 중급 2시간

같은 영상을 --backend 플래그로 Gemini API와 로컬 Qwen3-VL 둘 다 인덱싱하고, 동일 검색어 10개로 결과를 비교한다. 정확도·처리 시간·비용을 표로 정리하면 본인 환경에 맞는 선택 기준이 생긴다.

측정: 같은 검색어에 두 백엔드의 Top-1 클립이 일치하는가? 유사도 점수 분포는? 1시간 영상 처리 시간 차이는?
과제 4

highlights로 이상 장면 자동 추출 ★★ 중급 2시간

sentrysearch highlights -n 3으로 영상에서 "평소와 다른" 장면을 자동 추출하고, 그 결과를 검색 기반 추출과 비교한다. 청킹 파라미터(--chunk-duration, --overlap)를 바꿔가며 추출 품질이 어떻게 달라지는지 실험한다.

생각해볼 점: anomaly는 "검색어 없이" 무엇을 기준으로 뽑힐까? (벡터 공간에서 다른 청크들과 거리가 먼 청크)
과제 5

웹 UI로 감싸기 ★★★ 고급 4시간

FastAPI 백엔드 + 간단한 프론트엔드로 SentrySearch를 감싼 웹 도구를 만든다. 영상 업로드 → 자동 인덱싱 → 검색창 → 결과 클립 미리보기. 멀티모달 임베딩의 위력을 동료에게 시연하기 좋은 데모가 된다.

# app.py — SentrySearch를 서브프로세스/모듈로 호출
from fastapi import FastAPI
app = FastAPI()

@app.get("/search")
def search(q: str):
    # sentrysearch search "{q}" 결과를 JSON으로 반환
    return {"query": q, "clips": run_search(q)}

9관련 기술 심화 학습 로드맵

4주 학습 플랜

1주차: 임베딩과 벡터 검색의 기초

요일학습 내용실습
임베딩이란 무엇인가단어 임베딩으로 "강아지↔댕댕이" 유사도 계산
코사인 유사도 직접 구현numpy로 두 벡터의 코사인 값 계산
ChromaDB 입문문장 10개 임베딩 → 저장 → 검색
멀티모달 임베딩 개념이미지+텍스트를 한 공간에 넣어 검색
임계값과 정밀도/재현율threshold를 바꾸며 결과 품질 관찰

2주차: SentrySearch 분해

요일학습 내용실습
설치 & CLI 전체 명령init/index/search/img/stats 순회
청킹·오버랩 파라미터chunk-duration/overlap 바꿔 비교
전처리(480p·5fps·정지 스킵)--verbose 로그에서 스킵 동작 확인
img 검색 & highlights이미지 쿼리·이상 장면 추출 실험
dedupe & save-top중복 제거 임계값 조정

3주차: 백엔드와 프라이버시

요일학습 내용실습
Gemini Embedding 2 API키 발급·요금 구조 이해
DashScope Qwen3-VL클라우드 대안 백엔드 연결
로컬 Qwen3-VL 구동GPU 메모리별 모델 선택·양자화
비용 계산 실습프레임 단가 × 시간으로 견적
프라이버시 트레이드오프민감 영상 로컬/공개 영상 클라우드 분리

4주차: 확장과 응용

요일학습 내용실습
FastAPI로 감싸기검색 API 엔드포인트 작성
프론트엔드 결과 미리보기클립 썸네일·재생 UI
RTSP 실시간 스트림1분 단위 청킹+임베딩 파이프라인
임계값 기반 알림유사도 0.7↑ 시 슬랙 알림
종합 프로젝트CCTV 시맨틱 모니터링 프로토타입

10핵심 키워드 사전

이 레포를 이해하는 데 꼭 필요한 용어들
키워드설명
임베딩데이터를 고정 길이 숫자 리스트(벡터)로 바꾸는 기법. 비슷한 의미 → 비슷한 숫자. SentrySearch는 768차원 사용
벡터 공간임베딩 숫자들이 만드는 가상의 공간. 가까울수록 의미가 비슷함
멀티모달텍스트·이미지·영상 등 여러 종류(모달리티) 데이터를 한 모델이 같은 공간에서 다룸
시맨틱 검색글자 일치가 아니라 의미 유사도로 찾는 검색. "트럭"으로 "화물차" 영상도 찾음
코사인 유사도두 벡터가 같은 방향을 향하는 정도. -1~1, 1에 가까울수록 유사. 기본 임계값 0.41
벡터 DB임베딩을 저장하고 "가장 비슷한 것"을 빠르게 찾는 DB. 여기선 ChromaDB
ChromaDB로컬에서 가볍게 도는 임베디드 벡터 DB. 대안: Pinecone, Qdrant, Weaviate
청크긴 영상을 자른 조각. 기본 30초 단위
오버랩청크 경계를 일부러 겹치게 자르는 것. 기본 5초. 경계 이벤트 누락 방지
정지 프레임 스킵화면이 거의 안 변하는 구간을 JPEG 크기 비교로 감지해 건너뛰는 비용 최적화
MRLMatryoshka Representation Learning. 큰 임베딩을 앞부분만 잘라 작은 차원으로 쓰는 기법. 여기선 768차원 통일에 사용
Gemini Embedding 2구글의 멀티모달 임베딩 모델. SentrySearch 기본 백엔드
Qwen3-VL알리바바의 비전-언어 모델. DashScope(클라우드)·로컬 두 경로로 사용
highlights검색어 없이 영상에서 이상/주목 장면을 자동 추출하는 명령
dedupe거의 같은 결과 클립을 한 개로 합치는 중복 제거 (유사도 상한 0.9 권장)
uvRust로 만든 초고속 파이썬 패키지 매니저. uv tool install로 CLI를 격리 설치 (pipx 대안)
extraspyproject.toml의 선택 의존성 묶음. .[local] .[tesla]처럼 필요한 기능만 설치
SentryMerge / SentryBlur같은 저자의 자매 도구. 멀티카메라 합성 / 얼굴·번호판 가림(redaction)

11참고 링크

더 깊이 파고들 때 유용한 자료들