OpenCV 기반 영상 추적 알고리즘 실습(3)

Yk Lee·2022년 6월 8일
0

AI영상인식실습

목록 보기
16/16

영상배경제거와 영상물체 추적(1)

동영상의 배경 이미지를 획득하고, 제거하는 다양한 방법을 설명할 수 있다.

영상 배경 제거
배경 인식
평균에 의한 배경 영상 : 가장 간단한 배경 인식 방법으로 카메러가 고정된 상화, 조명이 일정한 상황에서 잘 동작함(CCTV 등)

실습

import cv2 as cv

## [capture]
capture = cv.VideoCapture('vtest.avi')
# capture = cv.VideoCapture('AD_street_parking_santafe_set1_no1_20200818.mp4')
# capture = cv.VideoCapture('43653691_20200211-14h19m22s_R_P.mp4')

frame_index = 1
_, frame_prev = capture.read()
while True:
    frame_index = frame_index + 1
    _, frame = capture.read()
    if frame is None:
        break

    beta = 98
    frame_prev = cv.addWeighted(frame_prev, float(beta)/100, frame, float(100-beta)/100, 0)
    #배경영상이미지 계산으로 동영상이 재생이 되면서 프레임 개수가 늘어가는데 과거 1번부터 마지막 프레임까지 전부다 평균을 내린다.
    #frame_prev = cv.addWeighted(frame_prev, (frame_index-1)/frame_index, frame, 1/frame_index, 0)

    ## [display_frame_number]
    #get the frame number and write it on the current frame
    cv.rectangle(frame, (10, 2), (100,20), (255,255,255), -1)
    cv.putText(frame, str(capture.get(cv.CAP_PROP_POS_FRAMES)), (15, 15),
                cv.FONT_HERSHEY_SIMPLEX, 0.5 , (0,0,0))
 
    ## [show]
    cv.imshow('Frame', frame)
    cv.imshow('Background', frame_prev)

    keyboard = cv.waitKey(1) & 0xFF
    if keyboard == 27:
        break
    
capture.release()
cv.destroyAllWindows()

결과

beta의 값이 낮아질수록 잔상이 진해진다.

영상배경제거와 영상물체 추적(2)

OpenCV 활용한 배경 제거
연속 frame 혹은 동영상의 배경 제거 알고리즘 지원
Opening/Closing 기법과 같이 활용하면 노이즈 개선 가능

종류
createBackgroundSubtractorMOG()
가우시안 Mixture을 기반으로 한 전경/배경 분할 알고리즘으로 가우시안 분산값(k=3~5) 지정
createBackgroundSubtractorGMG()
통계적 배경 이미지 제거와 픽셀 단위의 베이지안 분할을 결합
처음 몇 프레임을 배경 모델링으로 사용하여 초반에는 검정 창을 출력한다.
createBackgroundSubtractorMOG2()
기존 대비 조도 변화에 강인하여 각 픽셀별로 가우시안 분산값의 개수를 적절히 선택해 줌
createBackgroundSubtractorKNN()
KNN 기반으로 배경 여부를 판단하기 위한 threshold를 활용함
(그림자 인식 기능 활용할 경우 속도가 늦어짐 - >detectShadow = True/False)

실습

import cv2 as cv
import numpy as np

#### create Background Subtractor objects
backSub = cv.createBackgroundSubtractorMOG2()
# backSub = cv.bgsegm.createBackgroundSubtractorMOG()
# backSub = cv.bgsegm.createBackgroundSubtractorGMG()
# backSub = cv.createBackgroundSubtractorKNN()

## [capture]
capture = cv.VideoCapture('vtest.avi')
# capture = cv.VideoCapture('AD_street_parking_santafe_set1_no1_20200818.mp4')
# capture = cv.VideoCapture('43653691_20200211-14h19m22s_R_P.mp4')

kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5,5))
# kernel = np.ones((3,3), np.uint8)
while True:
    ret, frame = capture.read()
    if frame is None:
        break

    ## [apply]
    #update the background model
    #배경이 추출된 영상
    fgMask = backSub.apply(frame)
    # fgMask_filter = cv.fastNlMeansDenoising(fgMask,3,21,7)
    # fgMask_blur = cv.GaussianBlur(fgMask, (5,5),0)
    #배경에서 추출된 영상을 오프닝한 영상
    fgMask_morph = cv.morphologyEx(fgMask, cv.MORPH_OPEN, kernel)
    # fgMask_morph = cv.morphologyEx(fgMask_morph, cv.MORPH_CLOSE, kernel)
    ## [apply]

    ## [display_frame_number]
    #get the frame number and write it on the current frame
    cv.rectangle(frame, (10, 2), (100,20), (255,255,255), -1)
    cv.putText(frame, str(capture.get(cv.CAP_PROP_POS_FRAMES)), (15, 15),
               cv.FONT_HERSHEY_SIMPLEX, 0.5 , (0,0,0))
    ## [display_frame_number]

    ## [show]
    #show the current frame and the fg masks
    cv.imshow('Frame', frame)
    cv.imshow('FG Mask', fgMask)
    # cv.imshow('FG Mask Filtered', fgMask_filter)
    # cv.imshow('FG Mask Blur', fgMask_blur)
    cv.imshow('FG Mask Blur', fgMask_morph)
    ## [show]

    keyboard = cv.waitKey(1) & 0xFF
    if keyboard == 27:
        break
capture.release()
cv.destroyAllWindows()

결과

영상물체 추적

Cam Shift 함수
카메라에서 사람이 지정한 물체를 추적하는 기능
MeanShift : 데이터 집합의 밀도분포(특징점, 코너, 색상)를 기반으로 객체 추적
Cam Shift : 탐색창의 크기를 스스로 조정하여 Mean-Shift의 단점 보강.

실습

import cv2
import numpy as np

capture = cv2.VideoCapture("vtest.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()

meanShift(추적하고자하는 물체의 이미지,초기위치, 추적종료조건)

결과

성능이 조금 구리다. 추적반응이 상당히 느리다. 참고로 스페이스바로 정지한후 마우스로 원하는 추적 영상을 드래그 한 후 스페이스바를 누르면 된다.

실습 2

import cv2
import numpy as np

cap = cv2.VideoCapture("vtest.avi")

# 옵션 설명 http://layer0.authentise.com/segment-background-using-computer-vision.html
fgbg = cv2.createBackgroundSubtractorMOG2(varThreshold=100)

while True:
    ret, frame = cap.read()
    if frame is None:
        break
    
    fgmask = fgbg.apply(frame)

    nlabels, labels, stats, centroids = cv2.connectedComponentsWithStats(fgmask)

    for index, centroid in enumerate(centroids):
        if stats[index][0] == 0 and stats[index][1] == 0:
            continue
        if np.any(np.isnan(centroid)):
            continue

        x, y, width, height, area = stats[index]
        centerX, centerY = int(centroid[0]), int(centroid[1])

        if area > 100:
            cv2.circle(frame, (centerX, centerY), 1, (0, 255, 0), 2)
            cv2.rectangle(frame, (x, y), (x + width, y + height), (0, 0, 255))

    cv2.imshow('mask',fgmask)
    cv2.imshow('frame',frame)

    keyboard = cv2.waitKey(1) & 0xFF
    if keyboard == 27:
        break

cap.release()
cv2.destroyAllWindows()

결과

2명씩 붙어서 가는 경우 하나의 객체로 인식해준다.

profile
AR개발자지망생

0개의 댓글