[OpenCV/Google Colab] 노트북 웹캠으로 얼굴인식하기
우리 노트북에는 거의 웹캠이 달려있습니다.
안 달린 노트북이 드물 정도죠.
지금 진행중인 프로젝트가 노트북 웹캠을 활용하는 겁니다. 웹캠으로 사용자의 모션을 인식하는 것이죠.
모션인식하는 방법을 찾던 중에 간단하게 예습할 수 있는 것을 찾아보았습니다.
바로 웹캠으로 '얼굴'을 인식하는 것인데요, 아주 간단한 코드로 진행할 수 있습니다.
- Google Colab 실행하기
우선 구글 코랩은 줄여서 'Colab'이라고도 하는 Colaboratory를 사용하면 브라우저에서 Python을 작성하고 실행할 수 있습니다.
구성이 필요하지 않으며, GPU를 무료 접근 가능하고 간편한 공유가 가능하다는 장점이 있습니다.
간단하게 구글에서 colab만 검색해도 바로 나옵니다.
들어가자마자 이런 창이 뜹니다. 처음 접속하셨다면 'Welcome To Colaboratory'가 뜰겁니다. 간단한 소개와 튜토리얼이 적혀 있습니다. 저는 오른쪽 하단에 'NEW NOTEBOOK'을 누르고 새롭게 만들었습니다.
2. OpenCV 코드
그리고 웹캠을 통해 캡쳐한 비디오를 저장할 디렉토리도 하나 만들어줍니다.
그리고 웹캠을 열기 위한 Javascript코드를 넣어줍니다.
!pip install ffmpeg-python | |
from IPython.display import HTML, Javascript, display | |
from google.colab.output import eval_js | |
from base64 import b64decode | |
import numpy as np | |
import io | |
import ffmpeg | |
video_file_test = '/content/Video/osy_test.mp4' | |
VIDEO_HTML = """ | |
<script> | |
var my_div = document.createElement("DIV"); | |
var my_p = document.createElement("P"); | |
var my_btn = document.createElement("BUTTON"); | |
var my_btn_txt = document.createTextNode("Press to start recording"); | |
my_btn.appendChild(my_btn_txt); | |
my_div.appendChild(my_btn); | |
document.body.appendChild(my_div); | |
var base64data = 0; | |
var reader; | |
var recorder, videoStream; | |
var recordButton = my_btn; | |
var handleSuccess = function(stream) { | |
videoStream = stream; | |
var options = { | |
mimeType : 'video/webm;codecs=vp9' | |
}; | |
recorder = new MediaRecorder(stream, options); | |
recorder.ondataavailable = function(e) { | |
var url = URL.createObjectURL(e.data); | |
var preview = document.createElement('video'); | |
preview.controls = true; | |
preview.src = url; | |
document.body.appendChild(preview); | |
reader = new FileReader(); | |
reader.readAsDataURL(e.data); | |
reader.onloadend = function() { | |
base64data = reader.result; | |
} | |
}; | |
recorder.start(); | |
}; | |
recordButton.innerText = "Recording... press to stop"; | |
navigator.mediaDevices.getUserMedia({video: true}).then(handleSuccess); | |
function toggleRecording() { | |
if (recorder && recorder.state == "recording") { | |
recorder.stop(); | |
videoStream.getVideoTracks()[0].stop(); | |
recordButton.innerText = "Saving the recording... Please wait!" | |
} | |
} | |
function sleep(ms) { | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
var data = new Promise(resolve=>{ | |
recordButton.onclick = ()=>{ | |
toggleRecording() | |
sleep(2000).then(() => { | |
// wait 2000ms for the data to be available | |
resolve(base64data.toString()) | |
}); | |
} | |
}); | |
</script> | |
""" | |
def start_webcam(): | |
js = Javascript(''' | |
async function startWebcam() { | |
const div = document.createElement('div'); | |
const video = document.createElement('video'); | |
video.style.display = 'block'; | |
const stream = await navigator.mediaDevices.getUserMedia({video: true}); | |
document.body.appendChild(div); | |
div.appendChild(video); | |
video.srcObject = stream; | |
await video.play(); | |
// Resize the output to fit the video element. | |
google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true); | |
return; | |
} | |
''') | |
display(js) | |
data = eval_js('startWebcam()') | |
start_webcam() | |
def get_video(): | |
display(HTML(VIDEO_HTML)) | |
data = eval_js("data") | |
binary = b64decode(data.split(',')[1]) | |
return binary |
그리고 캡쳐한 비디오를 get하기위한 코드를 실행합니다.
videofile = get_video()
with open(video_file_test, 'wb') as f:
f.write(videofile)
크롬을 사용하는 분들은 웹캠 권한을 물어볼 것입니다. 허락해줍니다.
이제 OpenCV 코드를 넣어서 얼굴의 눈, 코, 입을 인식하는 알고리즘을 돌립니다.
import cv2 | |
from google.colab.patches import cv2_imshow | |
face_cascade = cv2.CascadeClassifier('/content/opencv/data/haarcascades/haarcascade_frontalface_default.xml') | |
eye_cascade = cv2.CascadeClassifier('/content/opencv/data/haarcascades/haarcascade_eye.xml') | |
cap = cv2.VideoCapture(video_file_test) | |
count = 1 | |
while cap.isOpened() & count<30: | |
ret, img = cap.read() | |
# gray = cv2.cvtColor(img, cv2.COLOR_BGR2BGR) | |
# Detects faces of different sizes in the input image | |
faces = face_cascade.detectMultiScale(img, 1.3, 5) | |
for (x,y,w,h) in faces: | |
cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,0),2) | |
# roi_gray = gray[y:y+h, x:x+w] | |
roi_color = img[y:y+h, x:x+w] | |
eyes = eye_cascade.detectMultiScale(roi_color) | |
for (ex,ey,ew,eh) in eyes: | |
cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,127,255),2) | |
cv2_imshow(img) | |
k = cv2.waitKey(30) & 0xff | |
if k == 27: | |
break | |
cap.release() | |
cv2.destroyAllWindows() |
만약 전체 비디오를 보길 원한다면 while 루프에서 count를 제거하면 됩니다.
이 알고리즘을 실행하면 노트북에 소음이 일어나면서 기록된 비디오에서 이미지를 추출하여 인식된 결과가 주르륵 나오기 시작하는데요, 아마 비디오를 오래 기록했다면 한참 기다려야 할 것 같습니다.
직접 실행해봤더니 아주 잘 나오더군요. 제 얼굴을 올리고 싶지만 혹시나 싶어서 위 링크 블로그의 사진을 참고로 가져왔습니다.
3. 결과
인식 정확도는 그리 좋은편이 아니네요. 얼굴과 눈은 100%정도로 읽는데 안경을 눈으로 인식하는 점과, 입은 잘 인식 못하네요.
코드를 더 수정해서 정확도를 높여야할 것 같습니다.
댓글
댓글 쓰기