본문 바로가기
OpenCV/OpenCV-Chapter

CH10 OpenCV-Python 객체 추적(배경차분)

by kiimy 2021. 12. 25.
728x90

배경차분(Background Subtraction: BS)

== 정적배경(Static Background)

등록된 배경 모델과 현재 입력 프레임과의 차영상을 이용하여 전경 객체를 검출

움직이는 전경 객체 검출을 위한 기본적인 방법

Back Image(정적배경)을 등록하고 새로 들어온 Frame과 차영상을 통해서 새로운 객체 검출

Threshold를 사용해서 이진화
=> 흰색 객체를 레이블링 기법(connect..stats)을 사용해서 크기와 위치를 판단
그리고 그 위치에서 boundingRect그려주면 간단한 침입자 감지 프로그램 만들 수 있다.
But 
이와같은 방법은 좋지 않다
why?
영상에서 새로운 객체를 계속 따라가지만 멈추었을 때도 계속 추적
1. 조명의 변화에 민감
2. 차가 새로 들어오고 멈췄는데도 계속 검출
==> 시간이 어느정도 지나면 배경으로 보는 것이 맞음
So, 점진적으로 Back Image(정적배경)을 업데이트해서 적응하는 형태로 동작할 수 있도록 해야함
== 평균연산(Mean shift, Cam shift) 사용
cap = cv2.VideoCapture('ch10\\videos\\PETS2000.avi')

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

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

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

# color로 진행해도 되지만 연산 속도나 굳이 color가 필요가 없어서
back = cv2.cvtColor(back, cv2.COLOR_BGR2GRAY)

# noise 제거(가우시안 없을시 도로 라인 같은 곳에 noise 발생)
# why? 빛의 반사?로 인해 튀는 값이 나타날 수 있다.(도로 라인..등)
# 정적영상 or 현재 영상 둘 중에 하나만 gaussian == noise가 뚜렷해짐
back = cv2.GaussianBlur(back, (0,0), 1.)

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)

    # 차영상 구하기 & 이진화(실시간 영상 - 정적배경)
    # 덧셈 함수나 뺄셈 함수에서는 두 배열의 요소를 서로 뺄셈했을 때 음수가 발생하면 0을 반환했지만 
    # 절댓값 차이 함수는 이 값을 절댓값으로 변경해서 양수 형태로 반환
    diff = cv2.absdiff(gray, back)
    # 차이값이 30 이하면 0, 이상이면 255(30정도의 차이값은 노이즈일 가능성이 높다라고 보면됨)
    _, diff = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)

    # + 레이블링을 이용한 boundingbox 표시
    cnt, _, stats, _ = cv2.connectedComponentsWithStats(diff)

    # 0은 배경이기 때문에 배경은 제외(grayscale)
    for i in range(1, cnt):
        (x, y, w, h, area) = stats[i]

        # 작은 객체를 포함시킬려면 area를 지정해주는 것이 좋음
        if area < 100:
            continue

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


    cv2.imshow('frame', frame)
    cv2.imshow('diff', diff)
    cv2.imshow('back', back) # 업데이트가 되지 않음

    if cv2.waitKey(20) == ord('q'):
        break

cap.release()

728x90

댓글