1. MeanShift

MeanShift는 대상 객체의 색상 정보를 평균 이동에 대해 추적하는 알고리즘으로, 연산이 이루어지는 과정은 다음과 같다.

1) 영상에서 추적할 대상을 선정한 후 HSV 컬러 Space의 H(Hue)값 히스토그램 계산
2) 전체 영상을 과정 1의 히스토그램 계산 후 역투영 처리
3) 역투영된 영상에서 MeanShift로 추적

역투영이란 전체 영상의 색상 정보와 대상 객체의 색상 정보의 비율을 0~255 구간 내로 정규화한 것이다. opencv는 히스토그램 역투영 결과에서 평균 이동으로 대상 객체의 위치를 찾아주는 함수 cv2.meanShift()를 지원한다.

 

import cv2
import numpy as np

capture = cv2.VideoCapture("video.avi")

histogram = None
# 검색 중지 요건
terminal = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 15, 0.5)

while capture.isOpened():
    ret, frame = capture.read()
    if not ret:
        break
    draw = frame.copy()
    
    if histogram is not None:
        # HSV space로 변환
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        # 역투영
        dst = cv2.calcBackProject([hsv], [0], histogram, [0,180], 1)
        # 평균 이동 추적
        ret, (x,y,w,h) = cv2.meanShift(dst, (x,y,w,h), terminal)
        cv2.rectangle(draw,(x,y), (x+w, y+h), (0,255,0), 2)
        # 추적 영상 및 역투영 영상 동시 출력
        result = np.hstack((draw, cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)))
    else :
        cv2.putText(draw, "Target", (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 1, cv2.LINE_AA)
        result = draw
    
    cv2.imshow("MeanShift Tracking", result)
    key = cv2.waitKey(10) & 0xff
    if key == 27:
        break
    elif key == ord(' '):
        # space bar를 누른 후 ROI 설정
        x,y,w,h = cv2.selectROI("MeanShift Tracking", frame, False)
        # histogram 계산 및 정규화
        if w and h :
            roi = frame[y:y+h, x:x+w]
            roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
            histogram = cv2.calcHist([roi], [0], None, [180], [0,180])
            cv2.normalize(histogram, histogram, 0, 255, cv2.NORM_MINMAX)
        else:
            histogram = None

capture.release()
cv2.destroyAllWindows()

ROI 설정(좌) / 객체 추적(중) / 역투영(우) - MeanShift

 

cv2.meanShift() 함수는 검색할 히스토그램의 역투영 영상, 검색 시작 위치, 검색 중지 요건을 인자로 사용한다. 위 코드에서의 검색 시작 위치는 ROI를 설정한 좌표로 지정된다. 검색 중지 요건으로 사용된 변수 terminal은 (검색을 중지할 경우, 최대 반복 횟수, 최소 정확도)의 튜플 형태로 전달되어야 한다. terminal에서 사용된 cv2.TERM_CRITERIA_EPS는 정확도가 epsilon보다 작을 경우를, cv2.TERM_CRITERIA_COUNT는 최대 반복 횟수와 동일한 경우를 의미한다. meanshift의 경우 color space를 기반으로 이루어지기 때문에 추적할 객체의 색상이 주변과 유사한 경우에는 큰 효과를 보기 어려운 단점이 있다.

 


2. CamShift

Camshift(Continuously Adaptive MeanShift)는 이름 그대로 연속적인 적응형 MeanShift이며, MeanShift를 개선한 알고리즘이다. cv2.Camshift()를 사용하며, cv2.meanShift()와 사용 방법은 같다.

 

import cv2
import numpy as np

capture = cv2.VideoCapture("video.avi")

histogram = None

terminal = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 15, 0.5)

while capture.isOpened():
    ret, frame = capture.read()
    if not ret:
        break
    draw = frame.copy()
    
    if histogram is not None:
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        dst = cv2.calcBackProject([hsv], [0], histogram, [0,180], 1)
        ret, (x,y,w,h) = cv2.CamShift(dst, (x,y,w,h), terminal)
        cv2.rectangle(draw,(x,y), (x+w, y+h), (0,255,0), 2)
        result = np.hstack((draw, cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)))
    else :
        cv2.putText(draw, "Target", (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 1, cv2.LINE_AA)
        result = draw
    
    cv2.imshow("CamShift Tracking", result)
    key = cv2.waitKey(10) & 0xff
    if key == 27:
        break
    elif key == ord(' '):
        x,y,w,h = cv2.selectROI("CamShift Tracking", frame, False)
        if w and h :
            roi = frame[y:y+h, x:x+w]
            roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
            histogram = cv2.calcHist([roi], [0], None, [180], [0,180])
            cv2.normalize(histogram, histogram, 0, 255, cv2.NORM_MINMAX)
        else:
            histogram = None

capture.release()
cv2.destroyAllWindows()

ROI 설정(좌) / 객체 추적(중) / 역투영(우) - CamShift

 

cv2.Camshift() 함수를 사용하는 부분을 제외하고는 1. MeanShift의 코드와 동일하다. 같은 조건으로 코드를 실행했지만 결과를 보면 meanshift보다 좋지 않은 결과를 나타낼 수 있으니, 검색 중지 요건을 수정하면서 사용할 필요가 있다.

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 라이프코리아트위터 공유하기
  • shared
  • 카카오스토리 공유하기