아나콘다나 라즈베리 파이에서 웹캠에 의한 안면 인식 어신 러닝이 가능하다면 이 웹캠 화면을 웹서버 방식으로 사용하기 위해서 Flask 에 의한 코드를 작성해 보기로 한다. 물론 라즈베리 파이와 같은 작은 보드에서 구현 가능한 웹서버를 완성하기 위해서는 실행 속도 차이가 7배에 달하므로 윈도우즈 10에서 코드를 작성 시험해 본 후에 라즈베리 파이에 옮기기로 하자.
단 윈도우즈 PC 의 아나콘다에서 face_detect.py를 Flask 화하여 코딩하여 실행할 경우 웹에서 0.0.0.0:5000 이 아니고 local:5000 또는 127.0.0.1:5000 임에 유의하자. 아무래도 Flask 시스템에서 face_detect.py 실행 시간이 조금 증가할 수 있는데 80~100 밀리 초 수준이며 라즈베리 파이에서도 당연히 실행이 가능하지만 600~900 밀리 초 수준으로 느려진다. 따라서 이 Flask 시스템 코드 작성 개발은 반드시 데스크톱에서 해야 할 필요가 있다.
아래 그림을 참조하면 윈도우즈 PC 의 아나콘다에서 안면 인식에 소요되는 시간이 녹색 80 밀리 초임을 알 수 있다. 특히 ‘title’로 출력된 timeString 시간은 웹서버 시작 초기에 한번 출력되며 한편 gen_frame() 루틴 내에서 cv2.VideoCapture(0) 화면에 더하여 loop 과정에서 체크하는 안면 인식 결과 원을 cv2.circle 명령에 의해 작도함과 아울러 안면인식 소요 시간 및 timeString을 cv2.putText 명령을 사용하여 출력한 결과를 추가한 최종 이미지 즉 image를 웹 출력한 것이다.
Flask 구조에 따른 웹서버 알고리듬 코드 구조를 살펴보자. haarcacade 라이브러리는 import 과정에 해당하므로 헤더 영역에 그냥 두면 된다. Flask(__name__)를 선언하고 root 영역 즉 @app.route(‘/’)에서 함수 def index(): 와 def gen_frames():를 배치하면 순서대로 실행이 이루어진다. cv2.VidepCapure() 후 cv2.imshow()에 이르는 과정은 웹캠 Opencv 파이선 코드와 동일하며 이머서 “q”를 입력하면 break 하여 루프를 중지하는 과정까지 그대로 사용한다. 여기까지 단계의 image 는 cv2.VideoCapture(0)에서 읽은 이미지에 안면 인식 결과 원을 작도한 이미지이다. 주의해야 할 점은 필요한 모든 정보를 화면상에 출력한 후 최종적으로 imencode를 실행하할 필요가 있다. 이 부분부터는 image를 Flask 웹에 올릴 수 있도록 imencode 명령 처리를 하여 바이트로 변환이 필요하다.
아래의 코드에서 ∙∙∙ 부분이 이미지에 정보를 추가하기 위한 루틴을 넣을 수 있는 공간이다.
∙∙∙에 해당하는 부분에 Opencv 명령을 사용하여 안면 인식 소요 시간을 계산하고 인식된 안면에 원을 작도한 후 안면인식 소요시간과 timeString 값을 추력하여 웹에 올릴 최종 이미지를 완성한다.
image encoding 즉 imencode 명령은 Opencv에서 초당 frame rate 속도로 처리되는 각각 이미지 frame을 하나의‘jpg’ 파일로 간주하고 엔코딩 작업 후 바이트 단위로 변환하여 Flask 웹에서 사용할 frame 이미지를 얻게 된다. 이과정이 함수 gen_frame()이 하게 되는 역할이며 @app.route(‘/video_feed’) 즉 root 아래에 위치한 폴더 ‘/video_feed’에서 video_feed() 함수의 리턴 항목에 gen_frames()를 일종의 callback 으로 사용하게 된다. 이러한 Flask 코드의 구조는 거의 정해져 있으므로 그대로 사용하면 된다. 사용자가 해야 할 코드 작업은 Flask 구조를 제외한 효율적인 머신 러닝 코드를 수정하는 작업에 국한 될 것이다.
한편 index.html 는 그대로 사용하되 frame 의 크기를 조절하는 기능이 있으므로 width 값을 조정하면 된다. 100% 이상의 크기도 가능하다. 성공적으로 실행이 되면 라즈베리 파이에서도 상당히 느리겠지만 실행이 가능하므로 감시용 시스템 제작이 가능할 것이다.
#face_detect_webserver.py
from flask import Flask, render_template, Response
import cv2
import numpy as np
import time
import datetime
import sys
faceCascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
num = 3
app = Flask(__name__)
@app.route('/')
def index():
"""Video streaming home page."""
now = datetime.datetime.now()
timeString = now.strftime("%Y-%m-%d %H:%M")
templateData = {
'title':'Image Streaming',
'time': timeString
}
return render_template('index.html', **templateData)
def gen_frames():
camera = cv2.VideoCapture(0)
time.sleep(0.2)
lastTime = time.time()*1000.0
while True:
ret, image = camera.read()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(gray,scaleFactor=1.1,minNeighbors=6)
delt = time.time()*1000.0-lastTime
s = str(int(delt))
#print (delt," Found {0} faces!".format(len(faces)) )
lastTime = time.time()*1000.0
# Draw a rectangle around the faces
for (x, y, w, h) in faces:
cv2.circle(image, (int(x+w/2), int(y+h/2)), int((w+h)/3), (255, 255, 255), 3)
cv2.putText(image, s, (10, 25),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
now = datetime.datetime.now()
timeString = now.strftime("%Y-%m-%d %H:%M")
cv2.putText(image, timeString, (10, 45),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
cv2.imshow("Frame", image)
key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
ret, buffer = cv2.imencode('.jpg', image)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/video_feed')
def video_feed():
"""Video streaming route. Put this in the src attribute of an img tag."""
return Response(gen_frames(),
mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='0.0.0.0')
#index.html
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<title>{{title}}</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 offset-lg-2">
<h3 class="mt-5">{{time}}</h3>
<img src="{{ url_for('video_feed') }}" width="100%">
</div>
</div>
</div>
</body>
</html>
'Opencv' 카테고리의 다른 글
라즈베리 파이 B/B+에 파이 카메라와 Stretch 버전에 Opencv3.3을 설치해 보자. (0) | 2021.07.11 |
---|---|
9-5 Opencv에 의한 세균 이미지 RGB HUE 색상 필터링 처리 (0) | 2020.06.01 |
아나콘다 OpenCV 웹캠에 의한 얼굴인식 (0) | 2020.05.02 |
3-17 라즈베리 파이 HTML 계산기+ 시계 + Opencv 웹캠 Flask 웹서버 (0) | 2020.05.01 |
7-3-6 라즈베리파이 OpenCV에 Webcam 설치 및 실행 (0) | 2020.04.21 |