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()
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()
cv2.Camshift() 함수를 사용하는 부분을 제외하고는 1. MeanShift의 코드와 동일하다. 같은 조건으로 코드를 실행했지만 결과를 보면 meanshift보다 좋지 않은 결과를 나타낼 수 있으니, 검색 중지 요건을 수정하면서 사용할 필요가 있다.
'데이터 분석 & 시각화 > OpenCV' 카테고리의 다른 글
[OpenCV Practice 09 - 1] 이미지 변형 (Scaling, Translation) (0) | 2020.08.29 |
---|---|
[OpenCV Programming] 디스크립터 2 (0) | 2020.08.28 |
[OpenCV Practice 08] 이미지 임계값 처리 Image Thresholding (0) | 2020.08.21 |
[OpenCV Programming] 객체 추적 1 (0) | 2020.08.20 |
[OpenCV Practice 07] 색공간 추적하기 (0) | 2020.08.19 |
최근댓글