참고: https://blog.daum.net/ejleep1/1001?category=585379
Flask_webcam_claculator.py의 코드 구조를 살펴보자. 이미 작성된 calculator HTML/JavaScript 코드에 파이선으로 작성된 Opencv 웹캠 라이브 스트리밍 파트를 함께 넣어 보도록 한다. 윈도우즈 PC에 웹캠이 하나 설치되어 있어야 영상을 볼 수 있다.
전체 형태는 html 파일로 구성하지만 웹캠 영역은 Flask 파이선 코드에서 html 처리가 가능한 기능을 사용하여 끼워 넣도록 하자.
calculator HTML/JavaScript 코드 편집을 위해서는 별도의 HTML 무료 편집기인 Notepad++ 을 사용하도록 하자. 여기에서 사용하는 html 코드는 제목이 {{title}}로 되어 있는데 이 부분은 아래 코드의 templateData 의 'title' 에 대응한다. 사용자가 재목을 바꾸고 싶으면 이 부분을 수정 입력 후 그대로 calculatorwebcam.html 로 저장하자.
아나콘다 Spider에서 Flask 파이선 편집 작업을 위해서는 사용하는 가상공간 여기서는 base(root) 를 사용하였는데 필히 open terminal 기능을 사용하여 work frame을 지원하는 Flask 를 미리 install 해두어야 할 것이다.
웹상에 웹캠화면 설정하는 방법에 대해서는 별도로 살펴보기로 하자.
아울러 root 의 하부 폴더 위치에 해당하는 즉 ‘/video_feed’, 웹의 host 로컬 ip 와 port 설정 영역으로 구성된다.
현재의 코드에서처럼 port 설정이 생략되어 있으면 Default인 5000 이 된다. 이 port 넘버는 반드시 4자리라야 하며 예를 들어 2자리 수는 안 된다.
한편 위에서 보듯이 host 로컬 ip 는 0.0.0.0 으로 설정할 경우 네트워킹 된 외부 컴퓨터의 웹에서 현재 Flask 코드를 실행 중인 컴퓨터의 로컬 ip + ‘:5000’ 을 웹 url에 입력하여 request를 보낼 수 있으나 로컬 ip를 127.0.0.1 로 설정하는 경우에는 외부네트워크로부터 request를 받을 수 없음에 유의하자. 아울러 외부로부터 네트워킹을 위해서는 Flask 코드를 실행하는 컴퓨터의 웹을 반드시 꺼야 함에도 유의하자.
위 파이선 코드에서 '0.0.0.0:5000'으로 수정하여 실행할 경우 아래와 같이 http://192.168.0.12:5000/ 와 같이 자체생성한 로컬 ip:5000 을 제공하므로 이 url 을 함게네트워크 된 즉 동일한 무선공유기에서 유선이나 무선으로 네트워킹 된 경우 웹 url 박스에 입력하면 웹캠을 포함한 스크린 화면을 관찰할 수 있다.
라이브러리 영역에서 Flask 와 한 세트인 render_template, Response 와 함께 Opencv에 해당하는 cv2를 import 하자.
Flask 코드의 특징 적인 구조는 Flask 선언과 함께 root 즉 ‘/’에서 index.html을 사용하는 @app.route(‘/’)에서 calculator 및 시계 기능을 하는 HTML/JavaScript 코드 내용과 웹캠 스트리밍 부분을 통합하여 그 파일명을 calculatorwebcam.html 로 부여하고 현재의 Flask 파이선 코드가 저장되어 있는 폴더 내에 templates 폴더를 준비한 후 옮겨 넣도록 한다.
index.html에서 비데오 라이브 웹캠 영상 처리를 담당했던 코드를 살펴보자.
이 부분을 다시 calculatorwebcam.html 에 수정해서 넣어야 한다. calculator 및 시계를 보여주는 HTML 웹 코드는 <table></table>을 사용하여 버튼 및 오브젝트 요소들을 배치하므로 웹캠 화면 역시 row 와 column 위치를 지정한 후 강제로 집어넣어야 한다. 아울러 width=50% 변수 설정을 사용하여 줄 바꿈이 일어나지 않도록 조정하여야 한다.
한편 실행코드인 Flask_webcam_calculator.py 가 위치한 폴더에 templates폴더가 함께 위치해야 하며 그 안에 index.html 대신에 이번에는 calculatorwebcam.html 이 있어야 한다.
이와같이 Flask workframe 을 사용하면 웹화면에 필요한 정보들을 입력하고 아울러 실시간으로 봐야 할 동영상 공간을 확보하여 웹 화면을 구성할 수 있음을 알아 보았다. 필요하다면 html 파일을 손보아 login 화면을 추가할 수도 있을 것이다. 우리가 실생활에서 접하는 다양한 요소로 구성된 웹화면을 구성함에 Flask가 얼마나 유용한지 알 수 있을 것이다. Flask 는 작은 규모의 웹 구성에 적합하며 본격적인 웹 구성에서는 Django 가 전문적으로 사용되고 있음에 유의하자.
#Flask_webcam_calculator.py
# JavaScript Calculator WebCam Flask WebServer:
#---------------------------------------------------------
from flask import Flask, render_template, Response
import cv2
import datetime
app = Flask(__name__)
camera = cv2.VideoCapture(0) # use 0 for web camera
def gen_frames(): # generate frame by frame from camera
while True:
# Capture frame-by-frame
success, frame = camera.read() # read the camera frame
if (not success):
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
# concat frame one by one and show result
@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')
@app.route('/')
def hello():
now = datetime.datetime.now()
timeString = now.strftime("%Y-%m-%d %H:%M")
templateData = { 'title' : 'Raspberry Pi Calculator WebCam Server',
'time' : timeString }
return render_template('calculatorwebcam.html', **templateData)
if (__name__ == '__main__'):
app.run(host='0.0.0.0', port=5000)
---calculatorwebcam.html: 이하의 html 코드에서 Notepad++ 을 사용하여 확장자 html로 저장 후 templates 폴더에 넣는다---
<!-----webcam calculator-->
<!DOCTYPE HTML>
<html>
<body>
<center><h1>{{title}}</h1>
</body>
<head>
<style>
body{
background-color:tan;}
.box{background-color:#3d4543;height:490px;width:510px; border-style:solid; border-color:lightblue;
border-radius:10px;position:relative;top:50px;left:1%;}
.display{background-color:#222;width:440px; position:relative;
left:2px;top:20px;height:35px;}
.display input{width:415px;position:relative;left:2px;top:2px;height:30px;
color:black;background-color:#bccd95;font-size:21px;text-align:right;}
.keys{position:relative;top:15px;}
.button{width:40px;height:30px;border-radius:8px; border-style:solid; border-color:green;
margin-left:12px;cursor:pointer;border-top:2px solid transparent;}
.button.gray{color:white;background-color:#6f6f6f;
border-bottom:black 2px solid;border-top:2px #6f6f6f solid;}
.button.pink{color:black;background-color:#ff4561;
border-bottom:black 2px solid;}
.button.black{color:white;background-color:#303030;
border-bottom:black 2px solid;border-top:2px #303030 solid;}
.button.orange{color:black;background-color:FF9933;
border-bottom:black 2px solid;border-top:2px FF9933 solid;}
.gray:active{border-top:black 2px solid;
border-bottom:2px #6f6f6f solid;}
.pink:active{border-top:black 2px solid;
border-bottom:#ff4561 2px solid;}
.black:active{border-top:black 2px solid;
border-bottom:#303030 2px solid;}
.orange:active{border-top:black 2px solid;
border-bottom:FF9933 2px solid;}
.buttondigiclock{width:125px;height:40px;border:none;border-radius:8px;margin-left:15px;
cursor:pointer;border-top:2px solid transparent;}
.buttondigiclock.black{color:white;background-color:;
border-bottom:lightblue 2px solid;border-top:2px 303030 solid;}
p{line-height:10px;}
</style>
</head>
<body>
<div class="box">
<div class="display">
<input type="text" readonly size="18" id="d">
</div>
<div class="displayx">
<input type="text" readonly size="18" id="dx">
</div>
<div class="keys">
<table>
<tbody>
<tr>
<td><input type="button" class="button gray" value="Pi" onclick='v("3.14159")'></td>
<td><input type="button" class="button gray" value="(" onclick='v("(")'></td>
<td><input type="button" class="button gray" value=")" onclick='v(")")'></td>
<td><input type="button" class="button black" value="7" onclick='v("7")'></td>
<td><input type="button" class="button black" value="8" onclick='v("8")'></td>
<td><input type="button" class="button black" value="9" onclick='v("9")'></td>
<td><input type="button" class="button pink" value="/" onclick='v("/")'></td>
<td><input type="button" class="button pink" value="*" onclick='v("*")'></td>
</tr>
</tbody>
<tr>
<td><input type="button" class="button black" value="4" onclick='v("4")'></td>
<td><input type="button" class="button black" value="5" onclick='v("5")'></td>
<td><input type="button" class="button black" value="6" onclick='v("6")'></td>
<td><input type="button" class="button black"value="1" onclick='v("1")'></td>
<td><input type="button" class="button black" value="2" onclick='v("2")'></td>
<td><input type="button" class="button black" value="3" onclick='v("3")'></td>
<td><input type="button" class="button pink" value="-" onclick='v("-")'></td>
<td><input type="button" class="button pink" value="+" onclick='v("+")'></td>
</tr>
<tr>
<td><input type="button" class="button black" value="0" onclick='v("0")'></td>
<td><input type="button" class="button black" value="." onclick='v(".")'></td>
<td><input type="button" class="button black" value="sin" onclick='v("Math.sin")'></td>
<td><input type="button" class="button black" value="cos" onclick='v("Math.cos")'></td>
<td><input type="button" class="button black" value="tan" onclick='v("Math.tan")'></td>
<td><input type="button" class="button black" value="log" onclick='v("Math.log")'></td>
<td><input type="button" class="button black" value="C" onclick='c("")'></td>
<td><input type="button" class="button orange" value="=" onclick='e()'></td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<td>
<body onload="updateTime()">
<!-- viewBox is coordinate system, width and height are on-screen size -->
<svg id="clock" viewBox="0 0 100 100" width="120" height="120">
<circle id="face" cx="50" cy="50" r="45"/> <!-- the clock face -->
<circle id="smallface" cx="50" cy="32" r="10"/> <!-- the small clock face -->
<g id="ticks">
<!-- 12 hour tick marks -->
<line x1='50' y1='5.000' x2='50.00' y2='10.00'/>
<line x1='72.50' y1='11.03' x2='70.00' y2='15.36'/>
<line x1='88.97' y1='27.50' x2='84.64' y2='30.00'/>
<line x1='95.00' y1='50.00' x2='90.00' y2='50.00'/>
<line x1='88.97' y1='72.50' x2='84.64' y2='70.00'/>
<line x1='72.50' y1='88.97' x2='70.00' y2='84.64'/>
<line x1='50.00' y1='95.00' x2='50.00' y2='90.00'/>
<line x1='27.50' y1='88.97' x2='30.00' y2='84.64'/>
<line x1='11.03' y1='72.50' x2='15.36' y2='70.00'/>
<line x1='5.000' y1='50.00' x2='10.00' y2='50.00'/>
<line x1='11.03' y1='27.50' x2='15.36' y2='30.00'/>
<line x1='27.50' y1='11.03' x2='30.00' y2='15.36'/>
</g>
<g id="smallticks">
<!-- 12 hour tick marks -->
<line x1='50' y1='24' x2='50' y2='22'/>
<line x1='58' y1='32' x2='60' y2='32'/>
<line x1='50' y1='40' x2='50' y2='42'/>
<line x1='42' y1='32' x2='40' y2='32'/>
</g>
<g id="numbers">
<!-- Number the cardinal directions-->
<text x="50" y="18">12</text><text x="85" y="53">3</text>
<text x="50" y="88">6</text><text x="15" y="53">9</text>
</g>
<!-- Draw hands pointing straight up. We rotate them in the code. -->
<g id="hands"> <!-- Add shadows to the hands -->
<line id="hourhand" x1="50" y1="50" x2="50" y2="24"/>
<line id="minutehand" x1="50" y1="50" x2="50" y2="20"/>
<line id="secondhand" x1="50" y1="32" x2="50" y2="24"/>
</g>
</svg>
</body>
</td>
<td>
<form name="theClock">
<input type=text class="button buttondigiclock black" name="theDate" style="font-size:20px;text-align: center;">
</td>
<td>
<input type=text class="button buttondigiclock black" name="theTime" style="font-size:20px;text-align: center;">
</form>
</td>
</tr>
</tbody>
</table>
<table><tbody><tr>
<td><h3 style="color:#FFFFFF;">Live WebCam</h3></td>
<td><img src="{{ url_for('video_feed') }}" width="50%"></td>
</tr></tbody></table>
</div>
</div>
<script type='text/javascript'>
function c(val){
document.getElementById("d").value=val;}
function v(val){
document.getElementById("d").value+=val;}
function e() {
try {
c(eval(document.getElementById("d").value)) }
catch(e) {
c('Error') } }
</script>
</body>
<head>
<script>
function updateTime() { // Update the SVG clock
var now = new Date();
var sec = now.getSeconds();
var min = now.getMinutes();
var hour = (now.getHours() % 12) + min/60;
var secangle = sec*6;
var minangle = min*6;
var hourangle = hour*30;
var actualMonth = now.getMonth() + 1;
//Prepare time output!
document.theClock.theTime.value = ""
+ now.getHours() + ":"
+ now.getMinutes() + ":"
+ now.getSeconds();
document.theClock.theDate.value = ""
+ now.getFullYear() + ":"
+ actualMonth + ":"
+ now.getDate();
// Get SVG elements for the hands of the clock
var sechand = document.getElementById("secondhand");
var minhand = document.getElementById("minutehand");
var hourhand = document.getElementById("hourhand");
// Set an SVG attribute on them to move them around the clock face
sechand.setAttribute("transform", "rotate(" + secangle + ",50,32)");
minhand.setAttribute("transform", "rotate(" + minangle + ",50,50)");
hourhand.setAttribute("transform", "rotate(" + hourangle + ",50,50)");
setTimeout(updateTime, 1000);
}
</script>
<style>
/* These CSS styles all apply to the SVG elements defined below */
#clock {
/* styles for everything in the clock */
stroke: black;
/* black lines */
stroke-linecap: round;
/* with rounded ends */
fill: #eef;
/* on a light blue gray background */
}
#face { stroke-width: 3px;}
/* clock face outline */
#smallface { stroke:green; stroke-width: 1px;}
/* clock face outline */
#ticks { stroke-width: 2; }
/* lines that mark each hour */
#smallticks { stroke:green; stroke-width: 1; }
#hourhand {stroke-width: 5px;}
/* wide hour hand */
#minutehand {stroke: deepskyblue; stroke-width: 3px;} /* narrow minute hand */
#secondhand {stroke:red; stroke-width: 1px;}
#numbers {
/* how to draw the numbers */
font-family: sans-serif; font-size: 7pt; font-weight: bold;
text-anchor: middle; stroke: none; fill: blue;
}
</style>
</head>
<table>
</table>
</html>
'Opencv' 카테고리의 다른 글
tflite 사전학습 가중치를 사용한 OpenCV 이미지 분류 (0) | 2023.06.02 |
---|---|
붓꽃 데이터 세트 퍼셉트론 분석 (0) | 2023.05.19 |
라즈베리 파이 B/B+에 파이 카메라와 Stretch 버전에 Opencv3.3을 설치해 보자. (0) | 2021.07.11 |
9-5 Opencv에 의한 세균 이미지 RGB HUE 색상 필터링 처리 (0) | 2020.06.01 |
Flask Opencv 웹캠에 의한 웹서버상에서 안면인식 (0) | 2020.05.02 |