파이썬 시각화 공부 10일(모션 감지 카메라 만들기)
안녕하세요 공대아저씨 입니다.
2023년 정말 더운 여름이 지나가고, 벌써 가을이 오고 있습니다.
여러분은 가을이 되면 어떤 생각이 가장 많이 드나요?
저는 가을이 되면 대다수의 학회들이 추계학술대회를 주최해서, 자주 참가하곤 했는데
학회에 가게되면 평소에 보지못했던 교수님들이나 은사님들 같이 공부했던 동료들을 만나게 되는 등
좋은 시간을 보낼 수 있는 기회가 많아지는 계절인 것 같습니다.
학회 참석 자체가 대학원생들에게는 1년동안 뿌린 씨앗을 거두는 순간들이기도 하고,
자신이 앞으로 나아가고자 하는 방향에 대한 소위 말하는 스펙 혹은 포트폴리오를 만들기 정말 좋은 기간입니다.
많은 분들이 이 기간 동안 좋은 기회를 잡으셨으면 합니다.
오늘 우리가 할 것은 바로 '모션 감지 카메라' 만들기 입니다.
우리가 지금까지 공부한 것을 정리해보면,
컬러이미지 변환 - 이미지의 픽셀 연산 - 도형 그리기 - 영상에 도형 집어넣기 - 이미지 조작하기 - 이미지 스케일 변환 -
영상 이진화 이러한 순서대로 공부를 했습니다.
우리가 computer vision을 활용한 딥러닝 모델에 들어가기에 앞서,
가장 기초적인 영상(이미지)을 갖고 주무르는 실습을 해본 것입니다.
오늘은 그 주무르기의 거의 마지막 단계인 모션 인식 카메라를 만들어 볼 것입니다.
먼저, 코드를 실습하기 전에 필요한 것은
pc 혹은 노트북이 카메라와 연결이 되어 사용이 가능한 상태(노트북은 내장 카메라) 여야 합니다.
오늘은 코드가 제법 평소보다 길어질 거 같으니
코드를 작성하기 전에 모션 감지카메라를 어떻게 만들지 부터 구조를 먼저 짜보겠습니다.
1. 카메라에 찍히는 영상도 결국 연속된 사진들의 나열이기 때문에, 이전 시점과 현시점의 픽셀 값 차이가 발생하면,
움직임이 있는 거라고 할 수 있습니다.
2. 따라서, 코딩을 할때는 움직임을 식별하기 위한 기준 값을 설정해주고
3. 각 시점의 카메라로 찍힌 순간들의 픽셀 정보를 저장해야합니다.
4. 과거시점을 a라고하면, 현재 시점을 b, 그 다음 시점을 c 라고 해보겠습니다.
5. 여기서, 초기에 a, b 프레임을 먼저 읽는데 이 2가지를 먼저 읽는 이유는 a, b의 차이를 계산하기 위해서 입니다.
일반적인 모션 감지의 로직은 다음과 같습니다.
ㆍ초기 상태에서 a와 b 프레임을 읽어옵니다.
ㆍ루프를 시작하면서 새로운 프레임(c)을 읽어옵니다.
ㆍa와 b 프레임을 비교하여 움직임을 감지합니다.
ㆍa와 b를 각각 b와 c로 업데이트합니다. 이렇게 하면 다음 루프에서 새로운 c와 그 전의 b를 비교할 수 있습니다.
6. a, b, c에 대해 값이 저장 되면, a, b, c를 모두 grayscale로 변환 하고
7. a-b, b-c의 절대값 차이를 계산합니다.
이러한 형태로 해서 한번 코드를 작성해보겠습니다.
## 변화감지 카메라
import cv2
import numpy as np
thresh, max_diff = 64, 12 # 달라진 픽셀값 기준치 설정
a, b, c = None, None, None # 카메라에 받아오는 정보 처리
cap = cv2.VideoCapture(0) # 내장카메라 사용
if cap.isOpened() :
ret, a = cap.read() # a 프레임 읽기
ret, b = cap.read() # b 프레임 읽기
while ret :
ret, c = cap.read() # 앞에 ab 2장이 제대로 읽혔다면 3번째 장을 읽어라 c 프레임 읽기
draw = c.copy() # 출력영상에 사용할 복제본
if not ret:
break
# 영상을 grayscale로 변경
a_gray = cv2.cvtColor(a, cv2.COLOR_BGR2GRAY)
b_gray = cv2.cvtColor(b, cv2.COLOR_BGR2GRAY)
c_gray = cv2.cvtColor(c, cv2.COLOR_BGR2GRAY)
# a-b, b-c 절대 값 차이 계산
diff_1 = cv2.absdiff(a_gray, b_gray)
diff_2 = cv2.absdiff(b_gray, c_gray)
# threshold로 정한 값 미만의 차이는 무시
ret, diff_1_thr = cv2.threshold(diff_1, thresh, 255, cv2.THRESH_BINARY)
ret, diff_2_thr = cv2.threshold(diff_2, thresh, 255, cv2.THRESH_BINARY)
# 차이점에 변동이 있는지를 그림을 통해서 확인
diff = cv2.bitwise_and(diff_1_thr, diff_2_thr) # 2개의 차이값을 and 로 합치는 것임
diff_cnt = cv2.countNonZero(diff) # diff 에서 제로가 아닌 값을 세라
if diff_cnt > max_diff :
non_zeros = np.nonzero(diff) # 0이 아닌 픽셀값의 좌표 얻기
print(non_zeros)
cv2. rectangle(draw, (min(non_zeros[1]), min(non_zeros[0])),
(max(non_zeros[1]), max(non_zeros[0])), (255, 0, 255),2)
cv2.putText(draw, 'Motion detected', (30,30), cv2.FONT_HERSHEY_PLAIN,
2, (0, 0, 255))
#컬러 영상과 threshold 영상을 같이 출력
stacked = np.hstack((draw, cv2.cvtColor(diff, cv2.COLOR_GRAY2BGR)))
cv2.imshow('img', stacked)
#다음 비교를 위해 영상 순서정리
a, b = b, c # abc 사진을 한장씩 받는데 그 차이를 계싼해서 디텍션을 판단하는 건데 판단했으면 a가 필요없고
# b와 c가 필요로 한데 결국, c는 새로 받고 a b를 한단계 앞으로 미는 작업
if cv2.waitKey(10) == 27:
break
cap.release()
cv2.destroyAllWindows()
이렇게 모션이 감지되면 그 부분에 박스가 생기면서 감지된 부분을 표시해주고,
흑백이미지로도 움직인 부분을 흰색으로 표시해주고 있습니다.
물론, 좌측 상단에 motion detected라는 정보도 같이 띄워주고 있구요.
자, 오늘은 CV에서 가장 기초단계를 모두 활용한 모션감지 카메라를 만들어 보았습니다.
관련 연구를 하거나, 기초 코드를 짜는데 굉장히 많은 분들에게 좋은 정보가 될거라고 생각합니다.
긴글을 읽어 주셔서 감사합니다 :)
다음시간에도 재미있는 코딩 주제를 갖고 돌아오도록 하겠습니다.