OpenCV 강좌, Optical Flow 기초와 실시간 추적 적용

OpenCV는 이미지 및 비디오 처리에 널리 사용되는 오픈 소스 라이브러리로, 실제 세계에서의 다양한 비전 문제를 해결하는 데 도움이 됩니다. 이번 강좌에서는 Optical Flow의 기초를 이해하고 이를 실시간 추적 시스템에 적용하는 방법을 알아보겠습니다. Optical Flow는 비디오 시퀀스에서 물체의 움직임을 추적하는 기술로, 특히 동영상 분석 및 컴퓨터 비전 분야에서 매우 유용합니다.

1. Optical Flow란?

Optical Flow는 연속된 이미지 간의 픽셀 이동을 분석하여 물체의 속도와 이동 방향을 추정하는 방법론입니다. 이는 물체의 경계를 식별하거나 동작을 추적하는 데 사용될 수 있습니다. Optical Flow는 주로 두 가지 주요 가정을 기반으로 합니다:

  • 물체의 밝기(명도)는 시간에 따라 변하지 않는다. 즉, 물체가 움직인다 해도 그 물체의 밝기는 일정하게 유지된다고 가정합니다.
  • 인접한 픽셀들은 동일한 속도로 이동한다. 근처의 픽셀들은 같은 물체의 일부로 간주되며, 이들 픽셀의 이동은 동일하다고 가정합니다.

2. Optical Flow의 수학적 기반

Optical Flow는 스피드 벡터를 계산하기 위해 각 픽셀에 대해 다음과 같은 미분 방정식을 이용합니다:

Optical Flow Equation

여기서:

  • I_x는 이미지의 x-축 방향의 기울기(gradient),
  • I_y는 y-축 방향의 기울기,
  • I_t는 시간에 따른 이미지의 변화입니다.

3. Optical Flow의 종류

Optical Flow는 여러 가지 방법으로 구현될 수 있으며, 그 중 가장 일반적인 두 가지 방법은 Lucas-Kanade 방법과 Farneback 방법입니다.

3.1 Lucas-Kanade 방법

Lucas-Kanade 방법은 작은 영역에서 일관된 움직임을 가정합니다. 주어진 두 이미지 간의 이동을 계산하기 위해 이 방법은 주변 공간의 픽셀을 사용하여 선형 문제를 해결합니다.

3.2 Farneback 방법

Farneback 방법은 각각의 픽셀에 대해 이웃 픽셀들의 값을 사용하여 다항식을 근사하여 이동 벡터를 계산합니다. 이 방법은 보다 부드러운 Optical Flow 장을 생성할 수 있습니다.

4. OpenCV에서 Optical Flow 구현하기

이제 OpenCV를 사용하여 Optical Flow를 실시간으로 구현해보겠습니다. 아래 예제에서는 웹캠으로부터 비디오 스트림을 읽고 Optical Flow를 적용합니다.

4.1 필요한 라이브러리 설치

먼저 OpenCV와 NumPy 라이브러리를 설치해야 합니다. 이는 다음과 같은 명령어로 설치할 수 있습니다:

pip install opencv-python numpy

4.2 예제 코드

다음은 Optical Flow를 실시간으로 추적하는 예제 코드입니다:


import cv2
import numpy as np

# 웹캠 비디오 캡처
cap = cv2.VideoCapture(0)

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

# 이전 프레임의 특성점 찾기
feature_params = dict(maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)

# Lucas-Kanade Optical Flow 파라미터
lk_params = dict(winSize=(15, 15), maxLevel=2,
                  criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

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

while True:
    # 새로운 프레임을 읽기
    ret, frame = cap.read()
    if not ret:
        break
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Optical Flow 계산
    p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)

    # 좋은 포인트 필터링
    good_new = p1[st == 1]
    good_old = p0[st == 1]

    # 포인트를 프레임에 그리기
    for i, (new, old) in enumerate(zip(good_new, good_old)):
        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('Optical Flow', img)

    # 다음 프레임을 위해 준비
    old_gray = frame_gray.copy()
    p0 = good_new.reshape(-1, 1, 2)

    # 'q' 키를 누르면 루프 종료
    if cv2.waitKey(30) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

5. 코드 설명

위 코드에서는 웹캠으로부터 비디오를 읽고 Optical Flow를 적용하여 움직이는 물체를 추적합니다. 코드의 각 부분에 대한 설명은 다음과 같습니다:

  • 비디오 캡처 초기화: cap = cv2.VideoCapture(0)를 사용하여 웹캠에서 비디오를 읽습니다.
  • 첫 프레임 읽기 및 Grayscale 변환: 첫 번째 프레임을 읽고 그레이스케일로 변환하여 Optical Flow 계산에 사용됩니다.
  • 특성점 추출: cv2.goodFeaturesToTrack를 사용하여 추적할 특성점을 추출합니다.
  • 루프를 통한 프레임 처리: 각 프레임에 대해 Optical Flow를 계산하고, 움직이는 특성점에 대한 선과 원을 그립니다.
  • 결과 표시 및 종료: cv2.imshow를 사용하여 결과를 화면에 표시하고, ‘q’키를 눌러 루프를 종료합니다.

6. 결론

이번 강좌에서는 OpenCV를 사용하여 Optical Flow의 기초와 이를 활용한 실시간 물체 추적 방법에 대해 알아보았습니다. Optical Flow는 복잡한 비디오 분석 문제를 해결하는 강력한 도구로, 다양한 응용 프로그램에서 활용될 수 있습니다. 이러한 기법을 사용하여 더 많은 실시간 비전 프로젝트를 개발할 수 있기를 바랍니다.

추가적으로 Optical Flow 기법을 보다 심화하여 다양한 개선 방법이나 다른 알고리즘과의 조합을 통해 성능을 높일 수 있습니다. 예를 들어, 딥러닝 기반의 물체 인식 알고리즘과 함께 Optical Flow를 사용하여 더 정밀한 추적 시스템을 만들 수 있습니다. 다음 강좌에서는 이러한 고급 방법론에 대해서도 다루어보는 시간을 가지겠습니다.

여기까지 읽어주셔서 감사합니다. 질문이나 피드백에 대해서 댓글 남겨주시면 최대한 답변드리도록 하겠습니다!