OpenCV 강좌, Lucas-Kanade vs Farneback 방식 비교

비디오 처리 및 컴퓨터 비전 분야에서 움직임을 추적하는 것은 매우 중요한 작업입니다. 이 과정에서 주로 사용하는 알고리즘 중 두 가지는 Lucas-Kanade 방법과 Farneback 방법입니다. 이 글에서는 각각의 방법에 대해 자세히 설명하고, 각각의 장단점과 실제 사용 예제를 비교해 보겠습니다.

1. Lucas-Kanade 방법

Lucas-Kanade는 Optical Flow의 일종으로, 짧은 시간 간격 동안의 이미지에서의 픽셀 이동을 추정하는 기법입니다. 이 방법은 주로 아주 작은 움직임을 추적하는 데 유용합니다. Lucas-Kanade 방법은 다음과 같은 가정을 기반으로 합니다:

  • 인접한 픽셀에서의 밝기 변화는 크게 변하지 않는다.
  • 작은 움직임에 대해 서로 인접한 픽셀의 속도가 비슷하다.

1.1 이론적 배경

Lucas-Kanade 방법은 이미지에서의 미분을 이용하여 밝기 변화와 픽셀 이동 사이의 관계를 수학적으로 표현합니다. 이 관계는 다음과 같은 형태로 표현될 수 있습니다:

∂I/∂x * u + ∂I/∂y * v + ∂I/∂t = 0

여기서 I는 이미지 밝기, uv는 각 픽셀에서의 x, y 방향 속도를 나타냅니다.

1.2 OpenCV를 이용한 Lucas-Kanade 구현

OpenCV에서는 Lucas-Kanade 방법을 쉽게 구현할 수 있는 함수인 cv2.calcOpticalFlowFarneback을 제공합니다. 다음은 파이썬을 사용하여 Lucas-Kanade Optical Flow를 구현하는 예제입니다:

import cv2
import numpy as np

# 비디오 캡처
cap = cv2.VideoCapture('input_video.mp4')

# 첫 번째 프레임 읽기
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

# 특성 포인트 찾기
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)

# 마스크 생성
mask = np.zeros_like(old_frame)

while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Lucas-Kanade 방법으로 Optical Flow 계산
    p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None)

    # 추적된 포인트를 그리기
    if p1 is not None:
        for i, (new, old) in enumerate(zip(p1, p0)):
            a, b = new.ravel()
            c, d = old.ravel()
            mask = cv2.line(mask, (a, b), (c, d), (0, 255, 0), 2)
            frame = cv2.circle(frame, (a, b), 5, (0, 0, 255), -1)

    img = cv2.add(frame, mask)

    cv2.imshow('Frame', img)
    old_gray = frame_gray.copy()
    p0 = p1[st == 1]

    if cv2.waitKey(30) & 0xFF == 27:
        break

cap.release()
cv2.destroyAllWindows()

2. Farneback 방법

Farneback 방법은 Optical Flow를 계산하는 또 다른 기법으로, 이미지 블록 분석을 통해 밀집한 흐름을 찾습니다. 이 방법은 각 픽셀에 대해 입력 이미지의 다항식을 맞추고, 이를 통해 흐름 벡터를 계산하는 방식입니다.

2.1 이론적 배경

Farneback 방법은 각 이미지 블록의 다항식逼近을 사용하여 흐름 벡터를 계산합니다. 이 방법의 핵심은 이미지 간의 변화를 매우 세밀하게 추적할 수 있다는 점입니다.

2.2 OpenCV를 이용한 Farneback 구현

OpenCV의 cv2.calcOpticalFlowFarneback 함수를 사용하여 Farneback Optical Flow를 쉽게 구현할 수 있습니다. 다음은 Farneback Optical Flow를 계산하는 예제입니다:

import cv2
import numpy as np

# 비디오 캡처
cap = cv2.VideoCapture('input_video.mp4')

# 첫 번째 프레임 읽기
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

# 마스크 생성
h, w = old_gray.shape
mask = np.zeros_like(old_frame)

while True:
    ret, frame = cap.read()
    if not ret:
        break

    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Farneback 방법으로 Optical Flow 계산
    flow = cv2.calcOpticalFlowFarneback(old_gray, frame_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)

    # 벡터화 처리
    for y in range(0, h, 10):
        for x in range(0, w, 10):
            fx, fy = flow[y, x]
            cv2.arrowedLine(mask, (x, y), (int(x + fx), int(y + fy)), (0, 255, 0), 1, tipLength=0.3)

    img = cv2.add(frame, mask)

    cv2.imshow('Frame', img)
    old_gray = frame_gray.copy()

    if cv2.waitKey(30) & 0xFF == 27:
        break

cap.release()
cv2.destroyAllWindows()

3. Lucas-Kanade vs Farneback: 비교

이 두 방법은 각기 다른 상황에서 강점과 약점을 가집니다. 다음은 두 방법의 비교입니다:

특징 Lucas-Kanade Farneback
속도 빠름, 작은 영역에 적합 느림, 전체 영역에 적합
정확도 작은 움직임에 더 정확함 복잡한 움직임, 전체 흐름에서 정확함
사용 용도 특징 점 추적 등 밀도 추적, 전체 흐름 시각화 등

4. 결론

Lucas-Kanade와 Farneback 방법 모두 Optical Flow를 계산하는 데 유용하지만, 각자의 장단점이 있습니다. Lucas-Kanade 방법은 속도와 작은 움직임에 더 적합하고, Farneback 방법은 더 복잡한 움직임을 다루는 데 강점을 가지고 있습니다. 사용자들은 상황에 맞게 각각의 방법을 선택하여 사용할 수 있습니다.

이러한 Optical Flow 기법을 사용하여 비디오 분석, 객체 추적, 움직임 기반 인터페이스 등을 구현할 수 있습니다. OpenCV의 강력한 기능을 활용하여 다양한 프로젝트에 적용해 보며 컴퓨터 비전의 재미를 느껴보시길 바랍니다.