看小姐姐的效果棒极了,写了一个工具,逐帧解析视频转成图片,有没有带上商业思维的小伙伴一起研究下

在这里插入图片描述

一个突然的想法,促成了这个项目雏形。

原理是:
上传一个视频,自动将视频每一帧保存成图片 然后前端访问 就能实现如图效果

后端是python/flask 数据库mysql

前端uniapp

项目演示: xt.iiar.cn

后端代码如下:

#学习交流 访问
# https://v.iiar.cnimport os
from flask import Flask, request, jsonify, send_from_directory
from flask_migrate import Migrate
from flask_cors import CORS
from datetime import datetime
import uuid
import cv2app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://xt:EcWzFKyTJHLjpx@127.0.0.1/xt'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
from models import db, XFile, XVideoBASE_DIR = os.path.dirname(os.path.abspath(__file__))
app.config['UPLOAD_FOLDER'] = os.path.join(BASE_DIR, 'uploads')
db.init_app(app)
migrate = Migrate(app, db)
CORS(app)@app.route('/')
def index():return '欢迎使用XTools'@app.route('/upload-video', methods=['POST'])
def upload_video():if 'video' not in request.files:return jsonify({'error': 'No video part'}), 400video_file = request.files['video']if video_file.filename == '':return jsonify({'error': 'No selected video'}), 400if video_file:base_path = 'files'date_path = datetime.now().strftime('%Y%m%d')random_dir = str(uuid.uuid4())output_dir = os.path.join(base_path, date_path, random_dir)# 检查输出目录是否存在,如果不存在,则创建if not os.path.exists(output_dir):os.makedirs(output_dir)video_path = os.path.join(output_dir, video_file.filename)video_file.save(video_path)new_video = XVideo(name=video_file.filename,loc_url=f'{str(output_dir)}/{video_file.filename}',)db.session.add(new_video)db.session.commit()# 使用OpenCV读取视频cap = cv2.VideoCapture(video_path)frame_count = 0while True:ret, frame = cap.read()if not ret:break# 图片命名:视频名+帧数+P.jpgframe_name = f"{os.path.splitext(video_file.filename)[0]}_frame_{frame_count:05d}P.jpg"frame_path = os.path.join(output_dir, frame_name)frame_url = f'{str(output_dir)}/{str(frame_name)}'new_img = XFile(loc_url=frame_url,video_id=new_video.id)db.session.add(new_img)cv2.imwrite(frame_path, frame)frame_count += 1print('frame_count', frame_count)if frame_count % 100 == 0:db.session.commit()db.session.commit()cap.release()return jsonify({'message': f'分析完成, {frame_count} 张图片.'}), 200@app.route('/v_img', methods=['GET', 'POST'])
def get_page():data = request.jsonv_id = data.get('v_id')page = data.get('page')per_page = data.get('per_page')video_info = XVideo.query.get(v_id)if not video_info:return reg_func(500, '', '片子不存在')img_s = XFile.query.filter_by(video_id=v_id)query_data = img_s.paginate(page=int(page), per_page=int(per_page), error_out=False)img_list = []domain = request.url_rootfor item in query_data.items:item_dict = item.to_dict()img_url = f"{domain}{item_dict['loc_url']}"img_list.append(img_url)video_dict = video_info.to_dict()video_dict['url'] = f"{domain}{video_dict['loc_url']}"video_dict['img_list'] = img_listreturn reg_func(200, video_dict, '有搞头')@app.route('/files/<path:date>/<uuid:random_dir>/<filename>')
def uploaded_file(date, random_dir, filename):base_path = 'files'file_path = os.path.join(base_path, date, str(random_dir))return send_from_directory(file_path, filename)def reg_func(code, data, msg):return jsonify({'code': code,'data': data,'msg': msg,'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')}), codeif __name__ == '__main__':app.run(debug=True, port=6789)# 迁移脚本
# flask db init    # 初始化迁移目录
# flask db migrate -m "one"  # 创建迁移脚本
# flask db upgrade# 导出依赖库
# pip freeze > requirements.txt

代码解释

这段代码是一个使用Flask框架实现的简单Web应用程序,旨在处理视频上传、视频帧提取,并将信息存储到MySQL数据库中。下面是代码的主要组成部分及其功能解释:

配置和初始化

  • 数据库配置: 使用SQLAlchemy作为ORM工具来操作MySQL数据库。数据库URI配置为mysql+pymysql://username:password@localhost/dbname格式,其中包含数据库类型、用户名、密码、主机和数据库名。
  • 上传目录配置: 设定一个文件上传的目录,所有上传的视频文件将保存在此目录下。
  • CORS配置: 通过CORS(app)允许跨域资源共享,这是在Web应用中常见的配置,以便于前端应用能够与后端服务进行交互。
  • 数据库迁移: 使用Flask-Migrate进行数据库迁移管理,这是一个基于Alembic的Flask扩展,用于处理SQLAlchemy数据库迁移。

路由和视图函数

  • 首页路由 (/): 返回欢迎信息。
  • 上传视频路由 (/upload-video): 处理视频文件的上传,包括文件存储和视频帧的提取。使用cv2(OpenCV库)读取视频帧,并将每帧作为图片保存到指定目录,同时将视频和图片信息存储到数据库中。
  • 获取视频图片路由 (/v_img): 根据视频ID分页查询关联的图片信息,并返回图片列表。
  • 访问上传文件路由 (/files/<path:date>/<uuid:random_dir>/<filename>): 提供一个静态文件访问的路由,允许用户通过URL直接访问上传的文件。

辅助函数

  • reg_func: 一个用于构建统一响应格式的辅助函数,包含响应码、数据、消息和时间戳。

运行和数据库迁移命令

  • 运行应用: 使用app.run(debug=True, port=6789)启动Flask应用,开启调试模式,并设置运行端口为6789。
  • 数据库迁移命令: 提供了Flask-Migrate的使用命令,用于初始化迁移目录、创建迁移脚本和升级数据库。

总结

这段代码是一个视频处理和存储的Web应用程序的后端部分。它接收上传的视频文件,提取视频帧,保存帧为图片,并将视频及图片信息存储到MySQL数据库中。同时,它也提供了API接口,用于查询和访问这些视频和图片资源。

数据模型如下:

#学习交流 访问
# https://v.iiar.cnfrom flask_sqlalchemy import SQLAlchemy
from datetime import datetimedb = SQLAlchemy()class XFile(db.Model):id = db.Column(db.Integer, primary_key=True)video_id = db.Column(db.Integer, comment='视频id')create_time = db.Column(db.DateTime, default=datetime.now, comment='文件上传时间')loc_url = db.Column(db.String(256), comment='本地路径')def to_dict(self):return {'id': self.id,'video_id': self.video_id,'create_time': self.create_time.strftime('%Y-%m-%d %H:%M:%S') if self.create_time else None,'loc_url': self.loc_url,}class XVideo(db.Model):id = db.Column(db.Integer, primary_key=True)create_time = db.Column(db.DateTime, default=datetime.now, comment='文件上传时间')name = db.Column(db.String(256), comment='视频名称')loc_url = db.Column(db.String(256), comment='本地路径')def to_dict(self):return {'id': self.id,'create_time': self.create_time.strftime('%Y-%m-%d %H:%M:%S') if self.create_time else None,'name': self.name,'loc_url': self.loc_url,}

模型解释

这段代码定义了两个Python类,XFileXVideo,它们都继承自db.Model,这是Flask-SQLAlchemy扩展提供的,用于在Flask应用中操作数据库的ORM(Object-Relational Mapping,对象关系映射)模型。这些类定义了两个数据库模型,用于存储文件和视频的相关信息。

XFile 类

  • 作用: 代表一个文件实体,用于存储视频帧图片的信息。
  • 属性:
    • id: 文件的唯一标识符,设为主键。
    • video_id: 关联的视频ID,表示这个文件属于哪个视频。
    • create_time: 文件的上传时间,默认为创建记录的当前时间。
    • loc_url: 文件在本地系统中的路径。
  • 方法:
    • to_dict(): 将文件对象的信息转换为字典格式,便于将数据序列化为JSON格式进行API响应。日期时间通过strftime格式化为易读的字符串。

XVideo 类

  • 作用: 代表一个视频实体,用于存储上传的视频信息。
  • 属性:
    • id: 视频的唯一标识符,设为主键。
    • create_time: 视频的上传时间,默认为创建记录的当前时间。
    • name: 视频的名称。
    • loc_url: 视频在本地系统中的路径。
  • 方法:
    • to_dict(): 类似于XFile的方法,将视频对象的信息转换为字典格式,用于API响应。

总结

通过使用Flask-SQLAlchemy,这些类不仅定义了数据库表的结构,还提供了与数据库进行交互的方法。例如,可以直接通过这些类的实例来创建、查询、更新或删除数据库中的记录,而无需编写原始的SQL语句。这大大简化了数据库操作,使得开发者可以更专注于应用逻辑的实现。

这两个模型通过video_id属性相互关联,XFilevideo_id作为外键,指向XVideoid,表明多个XFile(视频帧图片)可以关联到一个XVideo(视频)上。这种关系在数据库设计中被称为“一对多”关系。

前端文件 uniapp写的,请求方法封装了一下 如果需要的话可以找我拿

<!--学习交流 访问-->
<!-- https://v.iiar.cn --><template><view class="content" style="user-select:text"><!-- {{image_list.data.url}} --><view class="" style="margin: 40px;"><video :src="image_list.data.url" v-if="image_list.data" style="width: 300px;height: 600px;"></video></view><!-- {{image_list.data.img_list}} --><view class="" style="display: flex;width: 100%;flex-wrap: wrap;" v-if="image_list.data"><view v-for="(item,index) in image_list.data.img_list" :key="index" @click="look_images(index)"><image :src="item" mode="" class="image_css"></image></view></view></view>
</template><script>import {get_img_list} from '@/api/url.js'export default {data() {return {title: 'Hello',image_list: [],v_id: 2,page: 1,per_page: 50}},onLoad() {this.get_img_list_func()},onReachBottom() {this.page += 1this.get_more_img_list_func()},methods: {async get_img_list_func() {const data = await get_img_list({v_id: this.v_id,page: this.page,per_page: this.per_page})this.image_list = data},async get_more_img_list_func() {uni.showLoading({})const data = await get_img_list({v_id: this.v_id,page: this.page,per_page: this.per_page})console.log('data', data)uni.hideLoading()// 检查data.img_list的长度if (data.data.img_list && data.data.img_list.length > 0) {// 如果有数据,将其追加到this.image_list.data.img_list中this.image_list.data.img_list.push(...data.data.img_list);} else {// data.img_list长度为0时的处理方案// 例如:显示提示信息,或执行其他逻辑console.log('没有新的图片数据添加');this.page -= 1uni.showToast({title: '到底了!真的'})}},look_images(index) {uni.previewImage({current: index,urls: this.image_list.data.img_list});}}}
</script><style>.image_css {width: 450rpx;height: 800rpx;margin: 10px;border-radius: 20px;transition: transform 0.2s;}.image_css:hover {transform: scale(1.1);/* 放大1.2倍 */}.content {display: flex;flex-direction: column;align-items: center;justify-content: center;background-color: #1c1c1c;min-height: 100vh;}.logo {height: 200rpx;width: 200rpx;margin-top: 200rpx;margin-left: auto;margin-right: auto;margin-bottom: 50rpx;}.text-area {display: flex;justify-content: center;}.title {font-size: 36rpx;color: #8f8f94;}
</style>

代码解释

这段代码是一个使用Vue框架开发的uni-app页面模板,主要功能是显示一个视频和它关联的一系列图片。它从后端API获取视频和图片列表,支持触底加载更多图片,并提供图片预览功能。下面是代码的详细解释:

模板部分 (<template>)

  • 视频展示: 使用<video>标签显示从image_list.data.url获取的视频。如果image_list.data存在,则展示视频。
  • 图片列表展示: 通过v-for循环遍历image_list.data.img_list,显示所有图片。每个图片都可以点击,点击后会调用look_images方法进行预览。
  • user-select:text样式允许用户选择文本,可能用于调试或特定设计需求。

脚本部分 (<script>)

  • 数据部分: 包含image_list对象存储视频和图片列表,v_id表示视频的ID,pageper_page用于分页加载图片。
  • 生命周期钩子:
    • onLoad: 页面加载时调用get_img_list_func方法,获取视频及其关联的图片列表。
    • onReachBottom: 页面滚动到底部时自动触发,实现触底加载更多图片的功能。
  • 方法:
    • get_img_list_func: 获取初始视频和图片列表。
    • get_more_img_list_func: 加载更多图片,当滚动到页面底部时被调用。
    • look_images: 实现图片预览功能,uni.previewImage用于打开uni-app的图片预览界面。

样式部分 (<style>)

  • 定义.image_css类为图片添加样式,包括尺寸、边距、圆角以及过渡效果,实现鼠标悬停时的放大效果(注意:在uni-app中,:hover伪类主要用于Web平台)。
  • .content类设置了页面的布局和背景色,使内容垂直居中显示,并填充整个视口高度。

功能和特性

  • 视频和图片的动态加载: 通过异步请求从后端获取数据,并动态渲染到页面上。
  • 分页和触底加载: 支持通过分页参数加载更多图片,提高页面加载效率和用户体验。
  • 图片预览: 提供点击图片进行全屏预览的功能,增强了用户交互体验。

注意事项

  • uni.showLoading, uni.hideLoading, 和 uni.showToast是uni-app框架提供的API,用于显示加载提示和消息提示。
  • 由于uni-app支持编译到多个平台(如Web、微信小程序、App等),某些功能(如:hover伪类效果)在非Web平台上可能有所不同。开发时需考虑目标平台的特性和限制。

如果考虑手机版本的话
图片尺寸可以改为:
width: 300rpx;
height: 530rpx;
在这里插入图片描述
只是这样 电脑就会小一点
在这里插入图片描述
不过没关系,做了点击放大,左右滑动

在这里插入图片描述
但是有个小bug 就是

这个方法
uni.previewImage

在滑动到最后一张的时候 无法获取下一页的内容, 也就是网页触底加载更多

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

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

相关文章

【C深剖】数组名的细节

本系列博客为个人刷题思路分享&#xff0c;有需要借鉴即可。 引言&#xff1a;我想我说的这个数组名细节可能很多人并没有留意&#xff0c;现在先来C设计者这样设计也很合理。 就是数组名本质上是一个指针&#xff0c;但是这个指针的内容也就是说指向的空间是固定的&#xff0c…

unplugin-vue-components解决命名冲突

我们在vue项目中通常会利用unplugin-vue-components插件进行自定义组件的自动引入 注&#xff1a;如果不知道怎么配置unplugin-vue-components插件&#xff0c;欢迎看我整理的这篇&#xff1a; vue3项目配置按需自动引入自定义组件unplugin-vue-components 当出现同名文件时&a…

先进电机技术——感应电机与同步电机

一、感应电机 感应电机&#xff08;Induction Motor&#xff09;是一种广泛应用的交流电动机&#xff0c;其工作原理基于电磁感应定律。在感应电机中&#xff0c;定子绕组连接到电源后会因通入的交流电而产生一个旋转磁场。这个磁场在空间中是连续变化并以恒定的速度&#xff…

【医学大模型】Text2MDT :从医学指南中,构建医学决策树

Text2MDT &#xff1a;从医学指南中&#xff0c;构建医学决策树 提出背景Text2MDT 逻辑Text2MDT 实现框架管道化框架端到端框架 效果 提出背景 论文&#xff1a;https://arxiv.org/pdf/2401.02034.pdf 代码&#xff1a;https://github.com/michael-wzhu/text2dt 假设我们有一…

算法-矩阵置零

1、题目来源 73. 矩阵置零 - 力扣&#xff08;LeetCode&#xff09; 2、题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1…

机器学习---规则学习(一阶规则学习、归纳逻辑程序设计)

1. 一阶规则学习 “一阶”的目的&#xff1a;描述一类物体的性质、相互关系&#xff0c;比如利用一阶关系来挑“ 更好的”瓜&#xff0c;但实际应用 中很难量化颜色、 …、敲声的属性值。一般情况下可以省略全称量词。 命题逻辑&#xff1a;属性-值数据 色泽程度&#xff1a…

CSS:BFC

BFC&#xff0c;Block Formatting Context&#xff0c;块级格式化上下文&#xff0c;是一个独立的渲染区域或隔离的独立容器&#xff0c;它决定了其子元素如何布局&#xff0c;并且与这个区域外部的元素无关。 形成 BFC 的条件 float 的值不为 none&#xff08;left、right&a…

爬虫入门一

文章目录 一、什么是爬虫&#xff1f;二、爬虫基本流程三、requests模块介绍四、requests模块发送Get请求五、Get请求携带参数六、携带请求头七、发送post请求八、携带cookie方式一&#xff1a;放在请求头中方式二&#xff1a;放在cookie参数中 九、post请求携带参数十、模拟登…

HTTPS网络通信协议基础

目录 前言&#xff1a; 1.HTTPS协议理论 1.1协议概念 1.2加密 2.两类加密 2.1对称加密 2.2非对称加密 3.引入“证书” 3.1证书概念 3.2数据证书内容 3.3数据签名 4.总结 前言&#xff1a; 了解完HTTP协议后&#xff0c;HTTPS协议是HTTP协议的升级加强版&#xff0c…

设计模式二:代理模式

1、什么是动态代理 可能很多小伙伴首次接触动态代理这个名词的时候&#xff0c;或者是在面试过程中被问到动态代理的时候&#xff0c;不能很好的描述出来&#xff0c;动态代理到底是个什么高大上的技术。不方&#xff0c;其实动态代理的使用非常广泛&#xff0c;例如我们平常使…

unity 使用VS Code 开发,VS Code配置注意事项

vscode 对应的插件&#xff08;unity开发&#xff09; 插件&#xff1a;.Net Install Tool,c#,c# Dev Kit,IntelliCode For C# Dev Kit,Unity,Unity Code Snippets 本人现在是用了这些插件 unity需要安装Visual Studio Editor 1、.Net Install Tool 设置 需要在设置里面配置…

jvm gc日志拿取与分析思路

前言 参考文章:Java中9种常见的CMS GC问题分析与解决 - 美团技术团队 排查过程 进入容器里 生产应用是跑在docker上的&#xff0c;所以需要先进入到应用里面去&#xff0c;步骤如下 1. docker ps 找到对应的应用id&#xff0c;比如 zxc 2. 进入容器内部 docker exec -it 7690…

Elasticsearch:什么是搜索引擎?

搜索引擎定义 搜索引擎是一种软件程序或系统&#xff0c;旨在帮助用户查找存储在互联网或特定数据库中的信息。 搜索引擎的工作原理是对各种来源的内容进行索引和编目&#xff0c;然后根据用户的搜索查询向用户提供相关结果列表。 搜索引擎对于希望快速有效地查找特定信息的用…

怎么清理mac系统缓存系统垃圾文件 ?怎么清理mac系统DNS缓存

很多使用苹果电脑的用户都喜欢在同时运行多个软件&#xff0c;不过这样会导致在运行一些大型软件的时候出现不必要的卡顿现象&#xff0c;这时候我们就可以去清理下内存&#xff0c;不过很多人可能并不知道正确的清内存方式&#xff0c;下面就和小编一起来看看吧。 mac系统是一…

读十堂极简人工智能课笔记07_模拟与情感

1. 数码式考察 1.1. 制作计算机动画或游戏 1.1.1. 想怎么制作都可以 1.2. 计算机模拟 1.2.1. 目标是建造一个虚拟的实验室&#xff0c;其行为与现实完全一致&#xff0c;只是某些变量由我们来控制 1.3. 对现实世界进行建模并不容易&#xff0c;需要非常谨慎地收集和使用数…

Vscode vim 插件使用Ctrl+C和V进行复制粘贴到剪切板

Vscode vim 插件使用CtrlC和V进行复制粘贴到剪切板 使用这一个插件的时候复制粘贴和其他软件互动的时候体验不好, 并且不可以用Ctrl c, Ctrl v很不爽 "vim.commandLineModeKeyBindings": [{"before" : ["Ctrl", "c"],"after&q…

httpd apache

虚拟主机 配置环境 [rootlocalhost ~]#cd /var/www/html/ [rootlocalhost html]#mkdir 123 [rootlocalhost html]#mkdir abc [rootlocalhost html]#ls 123 abc [rootlocalhost html]#cd 123/ [rootlocalhost 123]#echo 123 > index.html [rootlocalhost 123]#cd ../abc/ […

泰山派摄像头使用-opencv流程

1. 泰山派添加camera 连接摄像头连接到usb接口,查看dev设备: # 在终端中输入如下命令&#xff0c;可以查看到camera设备资源&#xff1a; ls /dev/video* 检查板卡上的camera设备资源示例 也可以使用v4l2命令查看 v4l2-ctl --list-devices v4l2-ctl --list-devices是一个命令…

CentOS上如何配置手动和定时任务自动进行时间同步

场景 Linux(Centos)上使用crontab实现定时任务(定时执行脚本)&#xff1a; Linux(Centos)上使用crontab实现定时任务(定时执行脚本)_centos 定时任务-CSDN博客 Winserver上如何配置和开启NTP客户端进行时间同步&#xff1a; Winserver上如何配置和开启NTP客户端进行时间同步…

ADS-B Receiver Module TT-SC1 for UAV and Drones

目录 Introduction Applications Main features Technical parameters Basic technical information Electrical specification Recommended operation conditions General electrical parameters Introduction TT-SC1 is a high quality and low price OEM ADS-B…