본문 바로가기
OpenCV/OpenCV-Chapter

CH10 OpenCV-Python 추적(Mean Shift, Cam Shift)

by kiimy 2021. 12. 25.
728x90

추적(Tracking)

평균이동(Mean Shift) 알고리즘이란?

- 데이터 분석 기법 중 하나

- 데이터가 밀집되있는 분포를 찾는 것 == 모드검출(mode seeking)이라고 불리기도 함

ROI 중심이동(Mean shift) --> 주황색 중심으로 이동(더 밀집되 있는 곳으로)

# 특정 색 추적

# 비디오 파일 열기
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()

selectROI / histogram / backproj

* 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가 더 좋다~~

728x90

댓글