OpenCV/OpenCV-Chapter
CH10 OpenCV-Python 추적(Mean Shift, Cam Shift)
kiimy
2021. 12. 25. 16:18
추적(Tracking)
평균이동(Mean Shift) 알고리즘이란?
- 데이터 분석 기법 중 하나
- 데이터가 밀집되있는 분포를 찾는 것 == 모드검출(mode seeking)이라고 불리기도 함
# 특정 색 추적
# 비디오 파일 열기
cap = cv2.VideoCapture('ch10\\videos\\camshift.avi')
if not cap.isOpened():
print('Video open failed!')
sys.exit()
ret, frame = cap.read()
# roi = cv2.selectROI('orange', frame)
(x, y, w, h) = cv2.selectROI('orange', frame)
# print(roi) x, y, w, h
rc = (x, y, w, h)
if not ret:
print('frame read failed!')
sys.exit()
obj_roi = frame[y:y+h, x:x+w]
roi_hsv = cv2.cvtColor(obj_roi, cv2.COLOR_BGR2HSV)
# HS 히스토그램 계산
channels = [0,1]
ranges = [0,180, 0, 256]
hist = cv2.calcHist([roi_hsv], channels, None, [180,256], ranges)
# hist 영상화(y = H, x= S)
hist_norm = cv2.normalize(cv2.log(hist+1), None, 0, 255, cv2.NORM_MINMAX)
cv2.imshow('hist_nrom', hist_norm)
cv2.waitKey()
# Mean Shift 알고리즘 종료 기준
# 최대 10번 반복하며, 정확도가 1이하이면(즉, 이동 크기가 1pixel보다 작으면)종료
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TermCriteria_COUNT, 10, 1)
# 비디오 매 프레임 처리
while True:
ret, frame = cap.read()
if not ret:
break
# HS 히스토그램에 대한 역투영
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 0보다 큰 값으로 되있는 확률과 같은 개념의 이미지를 반환
backproj = cv2.calcBackProject([frame_hsv], channels, hist, ranges, 1)
# Mean Shift(= orange 좌표를 입력과 츌력으로 받는다)
_, rc = cv2.meanShift(backproj, rc, term_crit)
'''
cv2.meanShift(probImage, window, criteria) -> retval, window
probImage: 관심 객체에 대한 히스토그램 역투영 영상(확률 영상)
window: 초기 검색 영역 윈도우 & 결과 영역 반환
retval: 알고리즘 내부 반복횟수
'''
cv2.rectangle(frame, rc, (0, 0, 255), 2)
cv2.imshow('frame', frame)
cv2.imshow('backproj', backproj)
if cv2.waitKey(20) == ord('q'):
break
cap.release()
* Flow
1. 추적할 객체 등록(ROI)
2. HSV색 공간에서 HS Histogram
3. 매 프레임마다 histogram backproj
3. mean shift에 적용하여 객체 추적
추적 ROI window가 객체의 크기가 변함에 따라 바뀌지 않음
- 객체가 멀어지면 작아져야하고 가까워지면 커져야함
==> Cam shift 사용
CamShift(Continuously Adaptive Mean Shift)란?
- 추적하는 객체의 크기가 변하면 검색 window 크기 변경
- MeanShift와 비슷하지만 return값이 다름
((cx, cy), (width, height), angle)
(사각형의 중심), (가로,세로), 사각형이 몇도 회전했는지
* Flow
1. 평균 이동 알고리즘으로 이동 위치 계산
2. window 크기 조정
3. 특정 공간을 가장 잘 표현하는 타원 검출
4. 새로운 크기의 window를 이용하여 다시 평균 이동 수행
cap = cv2.VideoCapture('ch10\\videos\\camshift.avi')
if not cap.isOpened():
print('Video open failed!')
sys.exit()
# 초기 사각형 영역: (x, y, w, h)
# *참고* selectROI로 지정해서 사용할 수 있다.
x, y, w, h = 135, 220, 100, 100
rc = (x, y, w, h)
ret, frame = cap.read()
if not ret:
print('frame read failed!')
sys.exit()
roi = frame[y:y+h, x:x+w]
roi_hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# HS 히스토그램 계산
channels = [0, 1]
ranges = [0, 180, 0, 256]
hist = cv2.calcHist([roi_hsv], channels, None, [90, 128], ranges)
# CamShift 알고리즘 종료 기준
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
# 비디오 매 프레임 처리
while True:
ret, frame = cap.read()
if not ret:
break
# HS 히스토그램에 대한 역투영
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
backproj = cv2.calcBackProject([frame_hsv], channels, hist, ranges, 1)
# Camshift
ret, rc = cv2.CamShift(backproj, rc, term_crit)
''' meanshift <-> camshift
cv2.CamShift(probImage, window, criteria) -> retval, window
window: 회전되지 않은 사각형
retval: 추적하는 객체의 모양을 나타내는 회전된 사각형정보 반환
((cx, cy), (width, height), angle)
(사각형의 중심), (가로,세로), 사각형이 몇도 회전했는지
'''
# 추적 결과 화면 출력(타원)
cv2.rectangle(frame, rc, (0,0,255), 2)
cv2.ellipse(frame, ret, color=(0,255,0), thickness=2)
cv2.imshow('frame', frame)
if cv2.waitKey(30) == ord('q'):
break
cap.release()
결론: Camshift가 더 좋다~~