Flask如何在后端实时处理视频帧在前端展示

        怎么样在前端->选择视频文件->点击上传视频后->后端实时分析上传的视频->在前端展示后端分析结果(视频,文本)

咱们先看整看整体代码,有个大概的印象。

Flask后端代码

'''
cljc车流检测Demo
'''
from pytz import timezone
from datetime import datetime# 用于上传保存视频
@app.route('/upload', methods=['POST'])
def upload_video():VIDEOS_FOLDER = 'static\Videos'video = request.files['video']video.save(os.path.join(VIDEOS_FOLDER, '视频1.mp4'))return jsonify({'message': 'Video uploaded and saved successfully'}), 200# 用于把后端处理的视频帧数据传输到前端展示
@app.route('/video_feed')
def video_feed():return Response(generate_frames(),mimetype='multipart/x-mixed-replace; boundary=frame')# 处理函数
def generate_frames():frame_Num = 1                                   max_cars = 0video_path = './static/Videos/视频1.mp4' # 必须固定一个位置,用于存放上传的视频文件cap = cv2.VideoCapture(video_path)fps = cap.get(cv2.CAP_PROP_FPS)              carsCascade = cv2.CascadeClassifier("car_rear.xml")  while cap.isOpened():success, frame = cap.read()if not success:break   cv2.putText(frame,"second:"+str(round(frame_Num/fps,2))+"s",(0,100),cv2.FONT_HERSHEY_SIMPLEX,1,(255,0,255),1)cars = carsCascade.detectMultiScale(frame[700:1280,0:720], 1.2,minSize=(10,10))   for (x, y, w, h) in cars:  # 遍历所有汽车的区域cv2.rectangle(frame[700:1280,0:720], (x, y), (x + w, y + h), (0, 0, 255), 2)  # !!!!将每一帧转换为JPEG格式并以字节流方式返回,!!!!!ret, buffer = cv2.imencode('.jpg', frame)frame = buffer.tobytes()frame_Num+=1yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')@app.route('/')     ###主页面路由
def index():return render_template('index.html')

HTML前端代码 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head><link rel="stylesheet" type="text/css" href="/static/css/cljc.css">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge"><title>车流监测</title>
<style type="text/css">
body {
margin:0;
padding:0;
font-size:12px;
}</style>
</head>
<body>
<div class="header"><div><style>* { box-sizing: border-box; } body {margin: 0;}
.c14101{padding:10px;
text-align:center;
font-weight:600;
color:#ffffff;
font-family:"Microsoft Yahei", sans-serif;
background-image:url(/static/img/bg3.jpg);
background-repeat:repeat;
background-position:left top;
background-attachment:scroll;
background-size:auto;}</style>
<div id="ib1w" class="c14101">车流监测</div></div>
</div>
<div class="colmask threecol">
<div class="colmid">
<div class="colleft">
<div class="col1">
<div><style>* {box-sizing: border-box; 
} body {margin: 0;}
.c14101{padding:10px;
text-align:center;
font-weight:600;
color:#ffffff;
font-family:"Microsoft Yahei", sans-serif;
background-image:url(/static/img/bg1.jpg);
background-repeat:repeat;
background-position:left top;background-attachment:scroll;
background-size:auto;}
.htmlpage-row{display:table;
padding-top:10px;
padding-right:10px;
padding-bottom:10px;
padding-left:10px;
width:100%;}
.htmlpage-cell{
width:8%;
display:table-cell;height:75px;}
.c4195{height:400px;width:950px;
text-align:center;
position:relative;}
@media (max-width: 768px){
.htmlpage-cell{width:100%;display:block;}}.footer {display: flex;justify-content: center;align-items: center;height: 50; /* 设置合适的高度 */
}#upload-form {display: flex;flex-direction: column;/* align-items: center; */
}</style><div class="htmlpage-row"><!-- <div class="htmlpage-cell"></div> --><!-- <div class="htmlpage-cell"><video allowfullscreen="allowfullscreen" class="c4195" src="/static/img/video2.webm" controls="controls"></video></div> --><img src="{{ url_for('video_feed') }}" width="600px" height=590px"><!-- <div class="htmlpage-cell"></div> -->
</div></div>
</div><div class="col2"> <div class="BoxConTop">当前帧数</div><input type="text" id="frameNumber" name="frameNumber" readonly style="margin-top: -100px;"><div class="BoxConTop">当前车辆数</div><input type="text" id="vehicleNumber" name="vehicleNumber" readonly style="margin-top: -100px;"><div class="BoxConTop">车流量峰值</div><input type="text" id="peakTraffic" name="peakTraffic" readonly style="margin-top: -100px;">
</div><div class="col3"><p>北京时间</p><input type="text" id="timeShow" name="timeWarning" readonly><p>安全预警栏</p><input type="text" id="safetyWarning" name="safetyWarning" readonly>
</div></div>
</div>
</div>
</div>
<div class="footer"><form id="upload-form"><input type="file" id="video" name="video" accept="video/*"><button type="submit">上传视频</button></form>
</div>
<script src="https://cdn.socket.io/4.0.1/socket.io.min.js"></script>
<script>var socket = io();socket.on('update_data', function(data) {document.getElementById('frameNumber').value = data.frame_Num;document.getElementById('vehicleNumber').value = data.car_number;document.getElementById('peakTraffic').value = data.max_cars;document.getElementById('timeShow').value = data.timeShow;document.getElementById('safetyWarning').value = data.safetyWarning;});
</script>
</body>
<script>document.getElementById('upload-form').addEventListener('submit', async (e) => {e.preventDefault();const formData = new FormData(e.target);const response = await fetch('/upload', { method: 'POST', body: formData });const data = await response.json();console.log(data.message);});document.getElementById('play-btn').addEventListener('click', () => {const videoFrame = document.getElementById('video-frame');const source = new EventSource('/play');source.onmessage = (event) => {videoFrame.src = event.data;};});
</script>
</html>

代码可以创建一个.py文件,在编译软件(vscode,pycharm)中打开,这样看起来比较清晰。 

video_path = './static/Videos/视频1.mp4' 

必须固定一个位置,这个位置是upload路由从前端传输过来视频数据,保存的地址,上面是处理函数generate_frames()里面读取的步骤。

下面是保存的步骤,在upload_video()路由:

 video.save(os.path.join(VIDEOS_FOLDER, '视频1.mp4')) #固定保存视频的地方,

二、前后端代码结合讲解

实现上传视频并保存在指定路径的功能! 

@app.route('/upload', methods=['POST'])
def upload_video():VIDEOS_FOLDER = 'static\Videos'video = request.files['video']video.save(os.path.join(VIDEOS_FOLDER, '视频1.mp4')) #固定保存视频的地方,return jsonify({'message': 'Video uploaded and saved successfully'}), 200
<div class="footer"><form id="upload-form"><input type="file" id="video" name="video" accept="video/*"><button type="submit">上传视频</button></form>
</div>

↓ 

传输在后端处理好的视频帧数据到前端展示

@app.route('/video_feed')
def video_feed():return Response(generate_frames(),mimetype='multipart/x-mixed-replace; boundary=frame')
# 处理函数
def generate_frames():frame_Num = 1                                   max_cars = 0video_path = './static/Videos/视频1.mp4' # 必须固定一个位置,用于存放上传的视频文件cap = cv2.VideoCapture(video_path)fps = cap.get(cv2.CAP_PROP_FPS)              carsCascade = cv2.CascadeClassifier("car_rear.xml")  while cap.isOpened():success, frame = cap.read()if not success:break   cv2.putText(frame,"second:"+str(round(frame_Num/fps,2))+"s",(0,100),cv2.FONT_HERSHEY_SIMPLEX,1,(255,0,255),1)cars = carsCascade.detectMultiScale(frame[700:1280,0:720], 1.2,minSize=(10,10))   for (x, y, w, h) in cars:  # 遍历所有汽车的区域cv2.rectangle(frame[700:1280,0:720], (x, y), (x + w, y + h), (0, 0, 255), 2)  # !!!!将每一帧转换为JPEG格式并以字节流方式返回,!!!!!ret, buffer = cv2.imencode('.jpg', frame)frame = buffer.tobytes()frame_Num+=1yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

这是最关键的,其余都是处理函数。最后这一步将每一帧数据转换为了JPEG的格式并以字节流的方式返回。

        # !!!!将每一帧转换为JPEG格式并以字节流方式返回,!!!!!# 1.转换为JPEG格式ret, buffer = cv2.imencode('.jpg', frame)# 2.转换为字节流frame = buffer.tobytes()# 3.通过路由函数发送给前端yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

 通过上面这个方法yield(),把转换好的图像以字节流的方式传送给前端,那么前端如何接收到呢?这很简单,  

<div class="htmlpage-row"><img src="{{ url_for('video_feed') }}" width="600px" height=590px"></div>
  • 前端HTML:“接收来自后端路由video_feed()函数传过来的参数。”
  • 后端FLASK:“yield()通过video_feed()函数发送数据给前端。”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/313002.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java PDF文件流传输过程中速度很慢,如何解决?

专栏集锦&#xff0c;大佬们可以收藏以备不时之需&#xff1a; Spring Cloud 专栏&#xff1a;http://t.csdnimg.cn/WDmJ9 Python 专栏&#xff1a;http://t.csdnimg.cn/hMwPR Redis 专栏&#xff1a;http://t.csdnimg.cn/Qq0Xc TensorFlow 专栏&#xff1a;http://t.csdni…

MT3026 砍玉米

样例1&#xff1a; 输入&#xff1a; 6 1 3 4 2 5 1 7 8 19 10 30 2 输出&#xff1a; 6 其中1<n<10^5,1<xi,hi<10^9 思路&#xff1a;贪心&#xff1a;从左到右或者从右到左依次判断每一棵玉米是否可以倒下 &#xff08;以从左到右为例&#xff1a;先往左倒&…

elementui 弹窗展示自动校验表单项bug

表单校验失败一次之后&#xff0c;再次弹出表单&#xff0c;触发自动校验 解决方案&#xff1a; clearValidate() 方法清空表单校验项 this.$nextTick(() > {this.$refs[checkForm].clearValidate() }) 使用nextTick规避报错

stm32中的中断优先级

在工作中使用到多个定时器中断,由于中断的中断优先级不熟悉导致出错,下面来写一下中断的一些注意事项。 一、中断的分类 1、EXTI外部中断:由外部设备或外部信号引发,例如按键按下、外部传感器信号变化等。外部中断用于响应外部事件,并及时处理相关任务。 2、内部中断:…

java的Spring的Bean实例化深入理解

Bean的生命周期&#xff1a; 1、InstantiationAwareBeanPostProcessors前后置处理方法-》若是返回非空直接返回-》若不为空则执行doCreateBean-》首先创建实例-》进行属性注入-》调initializeBean-》首先判断是否实现了aware接口的方法进行相应的资源注入-》执行beanpostproce…

123页|华为项目管理精华-成功的项目管理(免费下载)

【1】关注本公众号&#xff0c;转发当前文章到微信朋友圈 【2】私信发送 华为项目管理精华 【3】获取本方案PDF下载链接&#xff0c;直接下载即可。 如需下载本方案PPT原格式&#xff0c;请加入微信扫描以下方案驿站知识星球&#xff0c;获取上万份PPT解决方案&#xff01;&a…

java项目实战之图书管理系统(1)

✅作者简介&#xff1a;大家好&#xff0c;我是再无B&#xff5e;U&#xff5e;G&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 1.背景 图书管理系统是一种用于管理图书…

挣钱新玩法,一文带你掌握流量卡推广秘诀

手机流量卡推广项目是什么&#xff1f;听名字我相信大家就已经猜出来了&#xff0c;就是三大运营商为了开发新用户&#xff0c;发起的有奖推广活动&#xff0c;也是为了长期黏贴用户。在这个活动中&#xff0c;用户通过我们的渠道&#xff0c;就能免费办理低套餐流量卡&#xf…

Flask Web框架的使用(合集)

Flask Web框架的使用-静态文件和模版 一、前言二、引言三、Web 框架简介1.什么是Web框架2.常用的 Web 框架FlaskDjangoBottleTornado 四、Flask Web框架的使用1.安装虚拟环境安装Virtualen创建虚拟环境激活虚拟环境 2.安装Flask3.第一个Flask 程序4.开启调试模式5.路由变量规则…

【UE5.1】使用MySQL and MariaDB Integration插件——(3)表格形式显示数据

在上一篇&#xff08;【UE5.1】使用MySQL and MariaDB Integration插件——&#xff08;2&#xff09;查询&#xff09;基础上继续实现以表格形式显示查询到的数据的功能 效果 步骤 1. 在“WBP_Query”中将多行文本框替换未网格面板控件&#xff0c;该控件可以用表格形式布局…

SQLite的知名用户(二十九)

返回&#xff1a;SQLite—系列文章目录 上一篇:SQLite作为应用程序文件格式&#xff08;二十八&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 SQLite被数以百万计的应用程序使用 从字面上看&#xff0c;有数十亿次部署。 SQLite 是 当今世界。 下面显示了一些…

8.Jetson AGX Orin Ubuntu20.04 gRPC编译安装

Jetson AGX Orin Ubuntu20.04 gRPC编译安装 一、CMake版本检查 grpc编译cmake要求最低版本为3.15。首先&#xff0c;cmake -version 查看当前cmake版本&#xff0c;如果低于3.15&#xff0c;按照以下步骤进行安装。 1.1 卸载已经安装的旧版的CMake sudo apt-get autoremove…

YOLOv9改进策略 | 损失函数篇 | EIoU、SIoU、WIoU、DIoU、FocusIoU等二十余种损失函数

一、本文介绍 这篇文章介绍了YOLOv9的重大改进&#xff0c;特别是在损失函数方面的创新。它不仅包括了多种IoU损失函数的改进和变体&#xff0c;如SIoU、WIoU、GIoU、DIoU、EIOU、CIoU&#xff0c;还融合了“Focus”思想&#xff0c;创造了一系列新的损失函数。这些组合形式的…

Mybatis generate xml 没有被覆盖

添加插件即可 <plugin type"org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>

Qt 系统相关

这里写目录标题 Qt 事件事件介绍事件的处理按键事件单个按键组合按键 ⿏标事件⿏标单击事件⿏标释放事件⿏标双击事件⿏标移动事件滚轮事件 定时器QTimerEvent 类QTimer 类获取系统⽇期及时间 事件分发器概述事件分发器⼯作原理 事件过滤器 Qt ⽂件Qt ⽂件概述输⼊输出设备类⽂…

Py之fireworks-ai:fireworks-ai的简介、安装和使用方法、案例应用之详细攻略

Py之fireworks-ai&#xff1a;fireworks-ai的简介、安装和使用方法、案例应用之详细攻略 目录 fireworks-ai的简介 fireworks-ai的安装和使用方法 1、安装 2、使用方法 # 使用Fireworks客户端库与某个预训练模型进行交互 fireworks-ai的案例应用 LLMs之Agent之Self-ask …

python-flask结合bootstrap实现网页小工具实例-半小时速通版

参考&#xff1a; Python之flask结合Bootstrap框架快速搭建Web应用_支持bootstrap的python软件-CSDN博客 https://blog.csdn.net/lovedingd/article/details/106696832 Bootstrap 警告框 | 菜鸟教程 https://www.runoob.com/bootstrap/bootstrap-alert-plugin.html flask框架…

论文笔记:SmartPlay : A Benchmark for LLMs as Intelligent Agents

iclr 2024 reviewer评分 5688 引入了 SmartPlay&#xff0c;一种从 6 种不同游戏中提取的基准 衡量LLM作为智能体的能力 1 智能代理所需的能力 论文借鉴游戏设计的概念&#xff0c;确定了智能LLM代理的九项关键能力&#xff0c;并为每项能力确定了多个等级&#xff1a; 长文…

(算法版)基于二值图像数字矩阵的距离变换算法

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本项目展示了欧氏距离、城市街区距离和棋盘距离变换的实现方法。通过定义一个距离变换类&#xff0c;对输入图像进行距离变换操作&#xff0c;并生成对应的距离矩阵。在示例中&#xff0c;展示了在一个480x480的全黑背景图像上设…

postman 调试 传base64字符串 原来选xml

上个图 工具类 package org.springblade.common.utils;import com.alibaba.fastjson.JSONObject; import org.springblade.modules.tc.mas.Submit;import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStrea…