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()函数发送数据给前端。”
相关文章:

Flask如何在后端实时处理视频帧在前端展示
怎么样在前端->选择视频文件->点击上传视频后->后端实时分析上传的视频->在前端展示后端分析结果(视频,文本) ↓ 咱们先看整看整体代码,有个大概的印象。 Flask后端代码 cljc车流检测Demofrom pytz import timezon…...

04-15 周一 GitHub仓库CI服务器actions-runner和workflow yaml配置文档解析
04-15 周一 GitHub仓库CI服务器配置过程文档 时间版本修改人描述2024年4月15日10:35:52V0.1宋全恒新建文档2024年4月17日10:33:20v1.0宋全恒完成github actions CI的配置和工作流配置文件解读文档的撰写 简介 一些基础概念 前提知识 仓库介绍 地址镜像介绍https://github.…...

论文笔记:SmartPlay : A Benchmark for LLMs as Intelligent Agents
iclr 2024 reviewer评分 5688 引入了 SmartPlay,一种从 6 种不同游戏中提取的基准 衡量LLM作为智能体的能力 1 智能代理所需的能力 论文借鉴游戏设计的概念,确定了智能LLM代理的九项关键能力,并为每项能力确定了多个等级: 长文…...

搜维尔科技:【工业仿真】煤矿安全知识基础学习VR系统
产品概述 煤矿安全知识基础学习VR系统 系统内容: 煤矿安全知识基础学习VR系统内容包括:下井流程(正确乘坐罐笼、班前会、井下行走注意事项、工作服穿戴、入井检身及人员清点、下井前准备工作、提升运输安全);运煤流程…...
线程和进程的区别(面试)
线程和进程的区别 进程和线程的区别线程的优点 进程和线程的区别 1. 进程是系统进行资源分配和调度的一个独立单位,线程是程序执行的最小单位. 2. 进程有自己的内存地址空间,线程只独享指令流执行的必要资源,如寄存器和栈. 3. 由于同一进程的各线程共享内存和文件资源,可以不通…...
抓取电商产品数据的方法|电商平台商品详情数据|批量上架|商品搬家|电商封装API数据采集接口更高效安全的数据采集
大量级电商数据采集时使用电商API接口有以下优势: 1. 数据准确性:通过电商API接口获取数据,可以保证数据的准确性和实时性,避免了手动采集可能出现的错误和延迟。 2. 自动化采集:API接口可以实现自动化的数据获取和更…...
关联规则Apriori算法
1.前置知识 经典应用场景:购物车商品的关联规则。 符号表示: I代表项集,项是可能出现的值,例如购物车中能有尿布、啤酒、奶粉等,I{尿布、啤酒、奶粉},尿布是项 K代表I中包含的项的数目,上面的k3 事…...

书生·浦语大模型全链路开源体系-第4课
书生浦语大模型全链路开源体系-第4课 书生浦语大模型全链路开源体系-第4课相关资源XTuner 微调 LLMXTuner 微调小助手认知环境安装前期准备启动微调模型格式转换模型合并微调结果验证 将认知助手上传至OpenXLab将认知助手应用部署到OpenXLab使用XTuner微调多模态LLM前期准备启动…...
HTML优化SEO
在网站开发中,除了关注设计和用户体验,SEO(搜索引擎优化)也是提升网站流量和可见度的关键。合理的HTML结构和元素运用能够帮助搜索引擎更好地理解页面内容,从而提高搜索排名。以下是一些基于HTML的SEO优化技巧…...

RabbitMQ-交换机
文章目录 交换机fanoutDirecttopicHeadersRPC 交换机 **交换机 **是消息队列中的一个组件,其作用类似于网络路由器。它负责将我们发送的消息转发到相应的目标,就像快递站将快递发送到对应的站点,或者网络路由器将网络请求转发到相应的服务器…...
mapreduce中的MapTask工作机制(Hadoop)
MapTask工作机制 MapReduce中的Map任务是整个计算过程的第一阶段,其主要工作是将输入数据分片并进行处理,生成中间键值对,为后续的Shuffle和Sort阶段做准备。 1. 输入数据的划分: 输入数据通常存储在分布式文件系统(…...
景区文旅剧本杀小程序亲子公园寻宝闯关系统开发搭建
要开发景区文旅剧本杀小程序亲子公园寻宝闯关系统,您需要考虑以下步骤: 1. 设计游戏场景和规则:根据亲子公园的主题和特点,设计适合亲子游玩的游戏场景和规则。您需要考虑游戏的安全性、趣味性和互动性,确保孩子们能够…...
性能优化---webpack优化
1、如何提高webpack打包速度 a、优化Loader--影响Loader打包速度的首要元素是Babel,Babel 会将代码转为字符串生成 AST,然后对 AST 继续进行转变最后再生成新的代码,项目越大,转换代码越多,效率就越低。先优化 Loader …...

YOLOv9改进策略 | 损失函数篇 | EIoU、SIoU、WIoU、DIoU、FocusIoU等二十余种损失函数
一、本文介绍 这篇文章介绍了YOLOv9的重大改进,特别是在损失函数方面的创新。它不仅包括了多种IoU损失函数的改进和变体,如SIoU、WIoU、GIoU、DIoU、EIOU、CIoU,还融合了“Focus”思想,创造了一系列新的损失函数。这些组合形式的…...
贪心算法-跳跃游戏
给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 示例 1: 输…...

sql知识总结二
一.报错注入 1.什么是报错注入? 这是一种页面响应形式,响应过程如下: 用户在前台页面输入检索内容----->后台将前台输入的检索内容无加区别的拼接成sql语句,送给数据库执行------>数据库将执行的结果返回给后台ÿ…...
VSCode和CMake实现C/C++开发
VSCode和CMake实现Ubuntu下C/C++开发总结 目录 0.简介1.Linux系统介绍2.开发环境搭建2.1 编译器,调试器安装2.2 CMake安装3.GCC编译器3.1 编译过程3.2 g++重要编译参数4.g++编译实战4.0 编译前4.1 直接编译4.2 生成库文件并编译4.3 编译后4.3.1 编译完成后的目录结构4.3.2 运行…...

【机器学习300问】74、如何理解深度学习中L2正则化技术?
深度学习过程中,若模型出现了过拟合问题体现为高方差。有两种解决方法: 增加训练样本的数量采用正则化技术 增加训练样本的数量是一种非常可靠的方法,但有时候你没办法获得足够多的训练数据或者获取数据的成本很高,这时候正则化技…...
C语言程序设计每日一练(4)
完全平方数 首先,我们需要明确什么是完全平方数。完全平方数是指一个整数,它可以表示为另一个整数的平方。例如,1、4、9、16等都是完全平方数,因为它们分别是1、2、3、4的平方。 现在,让我们回到这个问题。我们知道这…...

m4p转换mp3格式怎么转?3个Mac端应用~
M4P文件格式的诞生伴随着苹果公司引入FairPlay版权管理系统,该系统旨在保护音频的内容。M4P因此而生,成为受到FairPlay系统保护的音频格式,常见于苹果设备的iTunes等平台。 MP3文件格式的多个优点 MP3格式的优点显而易见。首先,其…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...