在這篇博文中,我們將使用 Flask 框架構建一個相機應用程式,我們可以在其中單擊圖片、錄制視頻、應用諸如灰度、負片和“僅人臉”之類的濾鏡,就像出現在 Snapchat 上的濾鏡一樣,
文中為前端使用了一個非常基本的設計,因為該專案的主要動機是讓自己熟悉 Flask 網路框架并在其中包括實時視頻流,同樣可以擴展以添加更多功能,

演示:

我們使用了執行緒、HTTP請求-回應、全域變數、錯誤處理和人臉檢測等概念,讓我們看看這一切是如何做到的,
前端
首先,前端是一個基本的 HTML 檔案,帶有用于獲取輸入的按鈕和用于在后端進行預處理后顯示輸出幀的影像源標簽,檔案中的按鈕將資料發布到服務器,該檔案還顯示了一些使用該應用程式的說明,該檔案保存在專案目錄的“模板”檔案夾中,
<body>
<div class="container">
<div class="row">
<div class="col-lg-8 offset-lg-2">
<h2 class="mt-5">CAMERA APP by Hemanth Nag</h2>
<form method="post" action="{{ url_for('tasks') }}">
<input type="submit" value="Stop/Start" name="stop" />
<input type="submit" value="Capture" name="click"/>
<input type="submit" value="Grey" name="grey" />
<input type="submit" value="Negative" name="neg" />
<input type="submit" value="Face Only" name="face" />
<input type="submit" value="Start/Stop Recording" name="rec" />
</form>
<img src="{{ url_for('video_feed') }}" height="80%">
<h3 style="font-family:courier;">Instructions:</h3>
<ol style="font-family:courier;">
<li>Stop/Start--Toggle between stop or start live streaming</li>
<li>Capture--Take still-shot and save in the 'shots' directory</li>
<li>Grey--Toggle between grayscale and RGB output</li>
<li>Negative--Toggle between negative and RGB output</li>
<li>Face Only--Shows just your face if present(Toggle on/off)</li>
<li>Start/Stop Recording--Toggle between starting and stopping video recording</li>
</div>
</div>
</div>
</body>

后端
至于后端,它是一個完成所有“魔法”的單個 python 腳本,它保存在專案目錄中,
讓我們分別查看檔案的各個部分以了解它的作業原理,
初始化:
from flask import Flask, render_template, Response, request
import cv2
import datetime, time
import os, sys
import numpy as np
from threading import Thread
global capture,rec_frame, grey, switch, neg, face, rec, out
capture=0
grey=0
neg=0
face=0
switch=1
rec=0
#make shots directory to save pics
try:
os.mkdir('./shots')
except OSError as error:
pass
#Load pretrained face detection model
net = cv2.dnn.readNetFromCaffe('./saved_model/deploy.prototxt.txt', './saved_model/res10_300x300_ssd_iter_140000.caffemodel')
#instatiate flask app
app = Flask(__name__, template_folder='./templates')
camera = cv2.VideoCapture(0)
在上面的代碼中,我們匯入了所有必要的模塊,
Flask 是一個微型網路框架,它就像是前端和后端之間的橋梁,
我們從flask中匯入'Response'和'request'模塊來處理HTTP回應請求
'render_template ' 用于渲染之前顯示的 HTML 檔案,
OpenCV是用于執行所有計算機視覺任務的模塊,
“Thread”模塊用于產生新執行緒,
然后我們宣告所有全域變數,它們就像一個“切換開關”來執行不同的任務,比如捕獲影像、開始/停止記錄和應用濾鏡,將變數初始化為 0 以將所有內容設定為 false,
在第 18 行,我們嘗試創建一個名為“ shots ”的檔案夾(如果它不存在),這是保存所有捕獲影像的位置,
第 24 行加載一個預訓練的人臉檢測模型以備將來使用,第 27 行創建 Flask 應用程式的實體,第 30 行為內置攝像頭創建了一個視頻捕獲物件,
功能:
def record(out):
global rec_frame
while(rec):
time.sleep(0.05)
out.write(rec_frame)
' record ' 函式用于開始記錄,即在 ' rec ' 變數設定為 true 時將幀寫入 avi 檔案,它使用“ out ”,這是稍后初始化的視頻撰寫器的物件,
(注意:如果你覺得錄制的視頻快或慢,請修改 time.sleep 的值),
def detect_face(frame):
global net
(h, w) = frame.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0,
(300, 300), (104.0, 177.0, 123.0))
net.setInput(blob)
detections = net.forward()
confidence = detections[0, 0, 0, 2]
if confidence < 0.5:
return frame
box = detections[0, 0, 0, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
try:
frame=frame[startY:endY, startX:endX]
(h, w) = frame.shape[:2]
r = 480 / float(h)
dim = ( int(w * r), 480)
frame=cv2.resize(frame,dim)
except Exception as e:
pass
return frame
' detect_face() ' 將相機幀作為輸入,并回傳一個只包含在該幀中檢測到的人臉的裁剪幀,它使用之前加載的預訓練人臉檢測模型,
可以訪問此網站 https://www.pyimagesearch.com/2018/02/26/face-detection-with-opencv-and-deep-learning/ 以深入了解這是如何完成的,
def gen_frames(): # generate frame by frame from camera
global out, capture,rec_frame
while True:
success, frame = camera.read()
if success:
if(face):
frame= detect_face(frame)
if(grey):
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
if(neg):
frame=cv2.bitwise_not(frame)
if(capture):
capture=0
now = datetime.datetime.now()
p = os.path.sep.join(['shots', "shot_{}.png".format(str(now).replace(":",''))])
cv2.imwrite(p, frame)
if(rec):
rec_frame=frame
frame= cv2.putText(cv2.flip(frame,1),"Recording...", (0,25), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255),4)
frame=cv2.flip(frame,1)
try:
ret, buffer = cv2.imencode('.jpg', cv2.flip(frame,1))
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
except Exception as e:
pass
else:
pass
' gen_frames ' 是一個重要的函式,完成實際的幀捕獲(通過相機)和處理,它在無限回圈中運行,
第 4 行從相機物件捕獲幀,如果幀捕獲成功,它會檢查是否有任何濾鏡開關為真,如果' *face'、'neg'*或' gray '為真,則分別在讀取幀上應用面部濾鏡、負片濾鏡和灰度濾鏡,
如果 ' capture ' 變數設定為 true,則將其重置為 false(全域變數)并且當前幀以 'png' 格式保存,如果“ rec ”為真,則將幀復制到“ rec_frame”全域變數,觸發時將其保存到視頻檔案中,
第 25 行將幀編碼到記憶體緩沖區中,然后轉換為位元組陣列,第 27 行以需要作為 HTTP 回應發送的格式生成幀資料,
HTTP 路由:
這是前端與服務器通信的地方,通信通過 URL 路由在*'GET* ' 和 ' POST ' 方法中發生,
app.route('/')
def index():
return render_template('index.html')
‘@app. route(‘/’)’ 是一個 Python 裝飾器,Flask 提供它來輕松地將 URL 分配給我們應用程式中的函式,
路由'/'是根URL,輸入根URL時呼叫' index() '函式,*“index.html”*檔案從函式呈現到網頁中,
@app.route('/video_feed')
def video_feed():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
路由 ' /video_feed ' 被設定為 html 檔案中的影像源,此函式在回圈中回傳由“ gen_frames() ”產生的幀的回應塊,
@app.route('/requests',methods=['POST','GET'])
def tasks():
global switch,camera
if request.method == 'POST':
if request.form.get('click') == 'Capture':
global capture
capture=1
elif request.form.get('grey') == 'Grey':
global grey
grey=not grey
elif request.form.get('neg') == 'Negative':
global neg
neg=not neg
elif request.form.get('face') == 'Face Only':
global face
face=not face
if(face):
time.sleep(4)
elif request.form.get('stop') == 'Stop/Start':
if(switch==1):
switch=0
camera.release()
cv2.destroyAllWindows()
else:
camera = cv2.VideoCapture(0)
switch=1
elif request.form.get('rec') == 'Start/Stop Recording':
global rec, out
rec= not rec
if(rec):
now=datetime.datetime.now()
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('vid_{}.avi'.format(str(now).replace(":",'')), fourcc, 20.0, (640, 480))
#Start new thread for recording the video
thread = Thread(target = record, args=[out,])
thread.start()
elif(rec==False):
out.release()
elif request.method=='GET':
return render_template('index.html')
return render_template('index.html')
路由“ /requests ”被分配給“ tasks() ”函式,它處理所有的開關和視頻錄制,這個路由有' POST '和*'GET* '方法,即它接受資訊并發送資訊,默認情況下,所有以前的路由都是“ GET ”,
如果來自客戶端的 HTTP 方法是“POST”,則“ request.form.get ”接受來自用戶按下的按鈕的資料,并反轉全域變數的先前狀態,這些變數的作用類似于“ gen_frame ”函式中的開關,
例如,當用戶按下“灰色”按鈕時,“灰色”全域變數被設定為 True,從而在“ gen_frames ”函式中將幀轉換為灰度,當再次按下“灰色”按鈕時,“灰色”設定為假,使幀恢復正常,
在運行 Flask 應用程式的同時將幀錄制到視頻中非常棘手,最簡單的解決方案是啟動一個新執行緒,
執行緒是一個獨立的執行流,這意味著你的程式將同時發生兩件事,執行緒與其對等執行緒共享資料段、代碼段、檔案等資訊,同時包含自己的暫存器、堆疊、計數器等,
在我們的例子中,' record() ' 函式有它自己的 while 回圈,因此該回圈在新執行緒中運行,
首先,當“ rec ”為真時,我們創建一個“ VideoWriter ”物件,在第 37 行,我們初始化一個新執行緒,目標是“ record() ”函式,第 38 行開始運行“ *record()”*函式的新執行緒,
當再次按下錄制按鈕時,*'VideoWriter'*物件被釋放并且停止錄制以將視頻保存在根目錄中,
最后,如果來自客戶端的 HTTP 方法是“ GET ”,則呈現“index.html”模板,
主函式:
if __name__ == '__main__':
app.run()
*'app.run()'*用于在其默認地址啟動Flask應用程式: http://127.0.0.1:5000/
通過向函式“run”添加“host”和“port”引數,可以設定不同的主機和埠號,將主機設定為廣播地址0.0.0.0將使應用程式在整個局域網(wifi 等)中可見,
因此,如果你的移動設備連接到同一個 Wi-Fi,你就可以從它訪問該應用程式,這是一個很好的“間諜攝像頭”,
結論
要運行這個應用程式,你應該在你的 PC 上安裝 python、flask 和 OpenCV,
要啟動應用程式,請移至命令提示符中的專案目錄,鍵入并輸入
python camera_flask_app.py
現在,將http://127.0.0.1:5000/ 復制粘貼到你的瀏覽器中,就是這樣,
你可以添加更多功能(例如 AI 濾鏡)來構建 Snapchat 式應用程式,你還可以增強用戶界面,使其更具互動性和色彩,你可以在這個 GitHub 帳戶中獲取該專案的源代碼,
https://github.com/hemanth-nag/Camera_Flask_App
☆ END ☆
如果看到這里,說明你喜歡這篇文章,請轉發、點贊,微信搜索「uncle_pn」,歡迎添加小編微信「 mthler」,每日朋友圈更新一篇高質量博文,
↓掃描二維碼添加小編↓

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/289414.html
標籤:其他
