Python/파이썬 OpenCV 공부

[파이썬 OpenCV] 영상의 객체 추적 - 배경 차분 - 이동 평균 배경 - cv2.accumulateWeighted

AI 꿈나무 2020. 10. 19. 19:55
반응형

영상의 객체 추적 - 배경 차분 - 이동 평균 배경

 이전 포스팅에서 공부하였던 정적 배경 모델 사용시 문제점은 새로 나타난 객체가 고정되었을 때 이것을 지속적으로 객체로 인식한다는 것입니다.

 

 

[파이썬 OpenCV] 영상의 객체 추적 - 정적 배경 차분 방법 - cv2.absdiff 함수

영상의 객체 추적 - 정적 배경 차분 방법  배경 차분(Background Subtraction : BS)은 등록된 배경 모델과 현재 입력 프레임과의 차영상을 이용하여 전경 객체를 검출하는 방법입니다.  동영상에서 움직

deep-learning-study.tistory.com

 

 

 고정된 객체가 일정 시간 지나면 배경으로 등록되는 방법에 대해 알아보겠습니다.

 

1. 이동 평균 배경 - Moving average

 이동 평균 배경 방법은 현재 프레임과 이전 프레임까지의 배경 영상에 가중치를 곱하여 영상을 갱신합니다.

 수백장의 영상을 저장하는 대신 매 프레임이 들어올 때마다 평균 영상을 갱신하는 방법입니다.

 

$$B(x, y, t) = \alpha \cdot I(x,y,t) + (1-\alpha)\cdot B(x, y, t-1)$$

 

 B(x,y,t) : 갱신된 배경 영상

 $\alpha$ : 현재 프레임에 대한 가중치

 I(x,y,t) : 현재 프레임

 B(x,y,t-1) : 이전 프레임까지의 배경 영상

 

 현재 프래임과 배경 영상의 가중치 합을 이용해서 배경 영상을 업데이트 합니다.

 이 방법을 이용하면 배경 영상을 조금조금씩 업데이트 할 수 있습니다.

 

 주의할 점은 현재 프래임은 컬러영상 unit8 데이터 타입인데 가중치 합 과정에서 소수점 미세한 정보를 보존해야 하므로 입력 영상은 실수형 자료를 이용해줘야 합니다.

 

 영상을 갱신하는 방법이므로 대용량 버퍼 메모리가 필요하지 않습니다.

 

2. 이동 평균 계산을 위한 가중치 누적 함수 - cv2.accumulateWeighted

 OpenCV에서는 이동 평균 함수를 따로 제공해주지 않고 cv2.accumulateWeighted 함수를 이용하여 이동 평균 배경을 구현할 수 있습니다.

 

cv2.accumulateWeighted(src, dst, alpha, mask=None) -> dst

• src: 입력 영상. 1 또는 3채널. 8비트 또는 32비트 실수형

• dst: 축적 영상. 입력 영상과 동일 채널 개수. 32비트 또는 64비트 실수형

• alpha: (입력 영상에 대한) 가중치

• mask: 마스크 영상

 alpha 값은 보통 0.01을 줍니다.

 0.01은 작은 값이 아닙니다.

 초당 30프레임으로 영상이 동작하기 때문에 0.01은 3~4초만에 100개의 프레임이 입력되어 1이 됩니다.

 

 dst가 입력인자, 반환값 두 가지가 있습니다.

 accumulate 내부 구현 식은 dst가 입력, 출력 두 곳에 있으므로 입력 인자에도 dst를 입력해야 합니다.

  

3. 이동 평균에 의한 배경 차분 예제 코드

 예제 코드 출처 :  황선규 박사님 github홈페이지 sunkyoo.github.io/opencv4cvml/

 

# 비디오 파일 열기
cap = cv2.VideoCapture('PETS2000.avi')

if not cap.isOpened():
    print('Video open failed!')
    sys.exit()

# 배경 영상 등록
ret, back = cap.read()

if not ret:
    print('Background image registration failed!')
    sys.exit()

# back: uint8 배경, fback: float32 배경
# 흑백으로 변환
back = cv2.cvtColor(back, cv2.COLOR_BGR2GRAY)
# 노이즈 제거
back = cv2.GaussianBlur(back, (0, 0), 1.0)
# float32로 변경
fback = back.astype(np.float32)

# 비디오 매 프레임 처리
while True:
    ret, frame = cap.read()

    if not ret:
        break

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (0, 0), 1.0)

    # fback: float32, back: uint8 배경
    # gray는 현재 프레임의 영상
    cv2.accumulateWeighted(gray, fback, 0.01)
    # absdiff 함수를 이용하기 위해 unit8로 변경
    back = fback.astype(np.uint8)

    # 인자의 타입이 같아야 한다.
    diff = cv2.absdiff(gray, back)
    _, diff = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)

    # 레이블링을 이용하여 바운딩 박스 표시
    cnt, _, stats, _ = cv2.connectedComponentsWithStats(diff)

    for i in range(1, cnt):
        x, y, w, h, s = stats[i]

        if s < 100:
            continue

        cv2.rectangle(frame, (x, y, w, h), (0, 0, 255), 2)

    cv2.imshow('frame', frame)
    cv2.imshow('diff', diff)
    cv2.imshow('back', back)

    if cv2.waitKey(30) == 27:
        break

cap.release()
cv2.destroyAllWindows()

 

 

 이처럼 고정 객체가 발생하였을 때 배경 영상을 업데이트하여 고정 객체를 배경 객체로 인식합니다.

 


OpenCV 튜토리얼과 황선규 박사님의 'OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝' 을 공부하면서 정리해 보았습니다.

  

반응형