前言
在做一个深度学习视频目标检测的项目,需要根据深度学习的视频处理进度来更新进度条的百分比。
一开始以为很简单,直接用当前帧数/视频总帧数得到处理进度百分比,再返回给前端进行展示就行。
#深度学习代码文件
import cv2
video = cv2.VideoCapture('video.mp4')
#获取总帧数
frame_count = int(video.get(cv2.CAP_PROP_FRAME_COUNT)
#获取进度比例,当前帧可以自己用while循环自增得到
ratio = current_frame_id/framcount
但是发现在实际实现过程中遇到了许多坑,这里便写个教程记录下。
一、后端代码
首先,我在后端里定义了一个全局变量progress_bar_ratio用来记录当前百分比,然后每当视频处理完视频下一帧时,我就更新这个progress_bar_ratio的值:
#深度学习代码文件
#将百分比定义全局变量,方便其他函数获取
progress_bar_ratio = 0.
def 视频处理伪代码():
global progress_bar_ratio #函数内加global才能使用全局变量
#用浮点数方法储存数据
progress_bar_ratio = current_frame_id/float(frame_count)
#保留两位小数,乘以100%
progress_bar_ratio = int(round(progress_bar_ratio,2)*100)
再在深度学习代码文件中定义一个额外的函数用来供前端获取后端的进度条值
#将百分比定义全局变量,方便其他函数获取
progress_bar_ratio = 0.
def 视频处理伪代码():
global progress_bar_ratio #函数内加global才能使用全局变量
#用浮点数方法储存数据
progress_bar_ratio = current_frame_id/float(frame_count)
#保留两位小数,乘以100%
progress_bar_ratio = int(round(progress_bar_ratio,2)*100)
#供前端访问
def get_bar_ratio():
global progress_bar_ratio
return progress_bar_ratio
二、Flask和前端代码
1.Flask
progress_bar_ratio的值会以数据流的方式将进度条值传给前端。
from 深度学习代码 import get_bar_ratio
from flask import Response, stream_with_context
@app.route('/progress') #随便自己定义,前端javascript要靠这个路由来访问数据
def progress():
@stream_with_context
def generate():
global ratio
ratio = get_bar_ratio() #获取后端进度条数据,最初的时候是0
while ratio < 100: #循环获取,直到达到100%
yield "data:" + str(ratio) + "\n\n"
print("ratio:",ratio)
ratio = get_bar_ratio()
#最好设置睡眠时间,不然后端在处理一帧的过程中前端就访问了好多次
time.sleep(1)
return Response(generate(), mimetype='text/event-stream') #用数据流的方式发送给后端
这里简单解释以下yield的作用,yiled其实类似于return,都是用来返回一个值。但yiled和return的区别在于,yield在返回值后会退出函数,当程序下次再次访问该函数时,会从yield的下一条语句开始执行。
简单来说,yield就相当于游戏中的存档点,你第一次调用函数的时候,函数执行到yield那行后会退出函数并返回"data:" + str(ratio) + "\n\n"
,并存档。当你第二次调用函数的时候,函数是从print("ratio:",ratio)
开始执行,相当于从上次结束的地方开始读档,并循环运行函数直到遇到下个yield结束。如此往复,从而形成数据流的效果,每次发一段数据给前端。
代码里的stream_with_context很重要!!!一定要加,不然前端没效果!!!
2.html和javascript
前端的进度条样式是由bootstrap5提供的(需要自己导入bootstrap5的包或者其他有进度条样式的包都可以):
//html文件
<div class="progress" style="margin-bottom:20px;">
<div class="progress-bar" id="flask_progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%"> 0%
</div>
</div>
javascript代码:
//加到html代码末尾即可
<script>
var source = new EventSource("/progress"); //前端向flask的/progress路由发送请求
source.onmessage = function(event) {
//获取当前的进度条数值,并对数值进行更改
let div = document.querySelector('#flask_progress')
let text = document.getElementById('flask_progress')
//更改进度条的进度长度以及进度条中的值
div.style.width = event.data+'%'
text.innerHTML = event.data+'%'
if(event.data == 101){
//当进度条超过100%后结束
source.close()
}
}
</script>