전통적 객체 탐지·추적
템플릿·코너·컨투어·옵티컬 플로우 등 전통 CV 탐지/추적을 언제 쓰고 언제 포기할지 기준 정리
Posted
By okorion
전통적 객체 탐지·추적
TL;DR
- 전통 CV는 강한 가정 위에서만 안정적으로 동작한다.
- 핵심은 “무엇을 쓰느냐”가 아니라 언제 통하고 언제 깨지는가다.
- 탐지는 초기화, 추적은 유지 역할로 분리해야 한다.
- 실패 원인의 대부분은 조명·스케일·가림 변화다.
- 간단한 문제는 전통 CV가 빠르고 설명 가능하다.
- 가정이 깨지면 즉시 딥러닝으로 전환하는 기준을 가져야 한다.
1. 전통적 접근의 전제(가정) 정리
전통적 CV는 데이터가 아니라 환경을 믿는다.
1
2
3
4
5
6
전통 CV의 암묵적 가정
├─ 조명: 큰 변화 없음
├─ 스케일: 객체 크기 일정
├─ 회전: 제한적
├─ 배경: 비교적 단순
└─ 노이즈: 전처리로 제거 가능
이 가정이 깨지는 순간, 성능은 급격히 붕괴한다.
2. 개념 지도: 탐지·추적 알고리즘 스펙트럼
1
2
3
4
5
6
7
8
9
10
11
전통적 탐지 / 추적
├─ 탐지 (Detection)
│ ├─ Template Matching
│ ├─ Corner / Edge
│ ├─ Contour 기반 분할
│ ├─ Feature Matching
│ └─ Watershed
└─ 추적 (Tracking)
├─ Optical Flow
├─ MeanShift / CamShift
└─ Tracking API (OpenCV)
3. 언제 통하고, 언제 깨지는가 (핵심 요약)
Template Matching
- 통함: 크기·회전 고정, 패턴 명확
- 깨짐: 스케일/회전 변화, 조명 변화
Corner / Edge
- 통함: 구조적 형태(문서, 건축물)
- 깨짐: 텍스처 약함, 노이즈 많음
Contour 기반
- 통함: 전경-배경 분리 명확
- 깨짐: 그림자, 반사, 복잡한 배경
Feature Matching
- 통함: 반복 구조, 비교적 큰 객체
- 깨짐: 저해상도, 모션 블러
Watershed
- 통함: 접촉 객체 분리
- 깨짐: seed 설정 실패, 노이즈
Optical Flow / Tracking
- 통함: 프레임 간 변화 작음
- 깨짐: 급격한 움직임, 가림
4. 알고리즘 선택 트리 (텍스트 플로우차트)
1
2
3
4
5
6
7
8
9
10
문제 정의
├─ 객체 위치를 "한 번" 찾고 싶다
│ ├─ 형태 고정 → Template
│ ├─ 경계 명확 → Contour
│ └─ 구조적 특징 → Corner / Edge
└─ 객체를 "계속" 따라가고 싶다
├─ 초기 위치 있음 → Tracking
│ ├─ 색상 기반 → MeanShift
│ └─ 움직임 기반 → Optical Flow
└─ 초기 위치 없음 → Detection → Tracking
5. 최소 실습 ①
Contour 기반 단순 물체 분리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import cv2
import numpy as np
def contour_segmentation():
"""
출력:
- contours 개수
- 입력/이진 이미지 정보
"""
img = np.zeros((120, 200), dtype=np.uint8)
cv2.rectangle(img, (40, 30), (160, 90), 200, -1)
noise = np.random.randint(0, 40, img.shape, dtype=np.uint8)
img = cv2.add(img, noise)
_, th = cv2.threshold(img, 120, 255, cv2.THRESH_BINARY)
kernel = np.ones((3,3), np.uint8)
clean = cv2.morphologyEx(th, cv2.MORPH_OPEN, kernel)
contours, _ = cv2.findContours(clean, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print("contours:", len(contours))
print("img:", img.shape, img.dtype, img.min(), img.max())
contour_segmentation()
해석 포인트
- 전처리가 분리 성능의 90%
- contour는 결과 표현 수단, 해법이 아니다
6. 최소 실습 ②
Synthetic Optical Flow 데모
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import cv2
import numpy as np
def optical_flow_demo():
"""
출력:
- 평균 이동 벡터 크기
"""
prev = np.zeros((100, 200), dtype=np.uint8)
cv2.circle(prev, (60, 50), 10, 255, -1)
next = np.zeros_like(prev)
cv2.circle(next, (70, 50), 10, 255, -1) # 이동
flow = cv2.calcOpticalFlowFarneback(
prev, next, None,
0.5, 3, 15, 3, 5, 1.2, 0
)
mag, _ = cv2.cartToPolar(flow[...,0], flow[...,1])
print("mean flow magnitude:", mag.mean())
optical_flow_demo()
해석 포인트
- Optical Flow는 “객체”가 아니라 픽셀 이동량
- 작은 이동, 연속 프레임에서만 신뢰 가능
7. 실패 케이스 10가지 & 대응
- 회전 변화 → Feature/DL
- 스케일 변화 → Pyramid/DL
- 조명 변화 → Histogram/DL
- 가림 → Re-detection
- 그림자 → 색공간 분리
- 모션 블러 → FPS/셔터
- 배경 복잡 → DL
- 저해상도 → 포기
- 객체 변형 → DL
- 카메라 이동 → 보정 필요
8. 흔한 실수 / 디버깅 체크리스트
- 전처리 없이 탐지
- tracking을 detection으로 해결
- 초기화 없는 추적
- 실패를 파라미터 탓
- 프레임 드롭 무시
- 알고리즘 가정 미확인
- 결과 설명 불가
- DL 전환 기준 없음
- 단일 방법 고집
- synthetic 테스트 생략
9. 딥러닝으로 넘어가야 하는 결정 규칙
1
2
3
4
5
6
아래 중 2개 이상 해당 → DL 전환
- 조명/스케일 변화 큼
- 가림 빈번
- 배경 복잡
- 설명보다 성능 중요
- 라벨 데이터 확보 가능
섹션 요약
- 전통 CV는 “빠르고 명확하지만 조건부”다.
- 탐지와 추적을 역할로 분리해야 안정적이다.
- 실패 패턴을 알면, 딥러닝 전환 시점이 보인다.
다음 글 / 다음 학습
➡️ 다음 글: 딥러닝 기반 컴퓨터 비전: CNN부터 YOLO까지
전통 CV의 한계를 딥러닝이 어떻게 대체하는지를 구조적으로 정리한다.
This post is licensed under CC BY 4.0 by the author.
