小工具之视频抽帧

'''
视频抽帧工具,所有视频所在目录以及抽帧图片保存路径
单个视频抽帧操作步骤:
选择文件路径->选择保存路径->拖动跳帧间隔->点击抽取帧
批量视频抽帧操作步骤:
选择文件夹路径->选择保存路径->拖动跳帧间隔->点击抽取帧
'''import sys
import cv2
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QLabel, QFileDialog, QSlider, QHBoxLayout, QProgressBar
from PyQt5.QtCore import Qt
import os
from shortuuid import uuid# include image suffixes
IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm'
# include video suffixes
VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv'def is_img(file_path: str):return file_path.split('.')[-1].lower() in IMG_FORMATSdef is_video(file_path: str):return file_path.split('.')[-1].lower() in VID_FORMATSclass VideoFrameExtractor(QMainWindow):def __init__(self):super().__init__()self.videoCapture = Noneself.frame_counter = 0self.save_path = ""self.central_widget = QWidget(self)self.setCentralWidget(self.central_widget)self.layout = QVBoxLayout()self.central_widget.setLayout(self.layout)self.progress_bar = QProgressBar()self.layout.addWidget(self.progress_bar)self.video_label = QLabel(self)self.layout.addWidget(self.video_label)file_select_layout = QHBoxLayout()self.file_button = QPushButton("选择文件路径", self)self.file_button.clicked.connect(self.openFile)file_select_layout.addWidget(self.file_button)self.dir_button = QPushButton("选择文件夹路径", self)self.dir_button.clicked.connect(self.openFileDir)file_select_layout.addWidget(self.dir_button)self.layout.addLayout(file_select_layout)save_start_layout = QHBoxLayout()self.save_button = QPushButton("选择保存路径", self)self.save_button.clicked.connect(self.openSavePath)save_start_layout.addWidget(self.save_button)self.extract_button = QPushButton("抽取帧", self)self.extract_button.clicked.connect(self.extractFrames)self.extract_button.setEnabled(False)save_start_layout.addWidget(self.extract_button)self.layout.addLayout(save_start_layout)param_start_layout = QHBoxLayout()self.frame_label = QLabel("跳帧间隔: 1", self)param_start_layout.addWidget(self.frame_label)self.frame_slider = QSlider(Qt.Horizontal, self)self.frame_slider.setRange(1, 100)self.frame_slider.setValue(1)self.frame_slider.valueChanged.connect(self.update_skip_param)param_start_layout.addWidget(self.frame_slider)self.layout.addLayout(param_start_layout)self.videos = []self.setGeometry(100, 100, 800, 100)self.setWindowTitle("视频抽帧应用")self.show()def update_skip_param(self):self.skip_param = self.frame_slider.value()self.frame_label.setText(f"跳帧间隔: {self.skip_param}")def openFileDir(self):options = QFileDialog.Options()# options |= QFileDialog.DontUseNativeDialogoptions |= QFileDialog.ShowDirsOnlyfile_dir = QFileDialog.getExistingDirectory(self, "选择视频文件夹", "", options=options)if file_dir:self.extract_button.setEnabled(True)all_files = os.listdir(file_dir)self.videos = [os.path.join(file_dir, file)for file in all_files if is_video(file)]def openFile(self):options = QFileDialog.Options()options |= QFileDialog.ReadOnlyfile_path, _ = QFileDialog.getOpenFileName(self, "选择视频文件", "", "视频文件 (*.mp4 *.avi *.mkv)", options=options)if file_path:self.extract_button.setEnabled(True)self.videos = [file_path]def openSavePath(self):options = QFileDialog.Options()options |= QFileDialog.ReadOnlydirectory = QFileDialog.getExistingDirectory(self, "选择保存路径", options=options)if directory:self.save_path = directorydef disable_elems(self):self.extract_button.setEnabled(False)self.file_button.setEnabled(False)self.dir_button.setEnabled(False)self.save_button.setEnabled(False)self.frame_slider.setEnabled(False)def enable_elems(self):self.extract_button.setEnabled(True)self.file_button.setEnabled(True)self.dir_button.setEnabled(True)self.save_button.setEnabled(True)self.frame_slider.setEnabled(True)def handle(self):passdef extractFrames(self):self.disable_elems()frame_skip = self.frame_slider.value()max_value = len(self.videos)self.progress_bar.setValue(0)for idx, video_path in enumerate(self.videos):cap = cv2.VideoCapture(video_path)prefix = str(uuid())# 以视频名称命名文件夹save_name = os.path.join(os.path.splitext(os.path.basename(video_path))[0])save_dir = os.path.join(self.save_path, save_name)os.makedirs(save_dir, exist_ok=True)frame_idx = -1while True:frame_idx += 1cap.grab()if frame_idx % frame_skip != 0:continueret, frame = cap.retrieve()if not ret:breakcv2.imencode('.jpg', frame, [int(cv2.IMWRITE_JPEG_QUALITY), 100])[1].tofile(f"{save_dir}/{prefix}_{str(frame_idx).zfill(6)}.jpg")cap.release()self.progress_bar.setValue(int((idx+1) / max_value * 100))QApplication.processEvents()  # 实时刷新界面,防止界面卡住self.progress_bar.repaint()# self.progress_bar.setFormat(f"{idx}% 完成")self.enable_elems()if __name__ == "__main__":app = QApplication(sys.argv)window = VideoFrameExtractor()sys.exit(app.exec_())

在这里插入图片描述

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

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

相关文章

iview label-in-value 和 @on-change 的使用

在select加上label-in-value 之后&#xff0c;就可以调用通过on-change默认的方法&#xff0c;获取到value和label的值了 <Select v-model"params.area" placeholder"选择区县" label-in-value clearable style"width: 102px"><Option…

pip和conda的环境管理,二者到底应该如何使用

关于pip与conda是否能混用的问题&#xff0c;Anaconda官方早就给出了回答 先说结论&#xff0c;如果conda和pip在相同环境下掺杂使用&#xff0c;尤其是频繁使用这两个工具进行包的安装&#xff0c;可能会导致环境状态混乱 就像其他包管理器一样&#xff0c;大部分这些问题均…

mysql在ubuntu上命令行登陆密码不正确

1.登陆提示如下 2.使用mysql -u root -p登录也是类似的 3.打开宝塔面板 点击root密码&#xff0c;更改密码后即可在命令行界面登录 4.登录效果如下

深度学习环境搭建——之Anaconda3安装配置

序言&#xff1a; 工作中一直从事的是FPGA嵌入式开发&#xff0c;图像处理相关的工作。目前随着AI的浪潮&#xff0c;也被动卷入到深度学习的漩涡中&#xff0c;为了不被漩涡卷入深渊&#xff0c;只能自学些深度学习相关的知识&#xff0c;俗话说“好记性不如烂笔头”何况已经…

profinet是什么?

profinet是什么&#xff1f; 参考&#xff1a;一文读懂Profibus、Profinet、Ethernet的区别 PROFINETPROFIbusetherNET&#xff0c;把Profibus的主从结构移植到以太网上&#xff0c;所以profinet会有Controller和Device&#xff0c;他们的关系可以简单的对应于profibus的Maste…

【C++】构造函数意义 ( 构造函数显式调用与隐式调用 | 构造函数替代方案 - 初始化函数 | 初始化函数缺陷 | 默认构造函数 )

文章目录 一、构造函数意义1、类的构造函数2、构造函数显式调用与隐式调用3、构造函数替代方案 - 初始化函数4、初始化函数缺陷5、默认构造函数6、代码示例 - 初始化函数无法及时调用 一、构造函数意义 1、类的构造函数 C 提供的 构造函数 和 析构函数 作为 类实例对象的 初始化…

长短期记忆网络(LSTM)

概念 三个门&#xff1a;遗忘门、输入门、输出门 候选记忆单元 记忆单元 隐状态 ot 控制是否让输出&#xff0c;是否要进行重置。 总结 代码实现 import torch from torch import nn from d2l import torch as d2lbatch_size,num_steps 32,35 train_iter,vocab d2l.load_…

Linux中安装MySQL_图解_2023新

1.卸载 为了避免不必要的错误发生,先将原有的文件包进行查询并卸载 // 查询 rpm -qa | grep mysql rpm -qa | grep mari// 卸载 rpm -e 文件名 --nodeps2.将安装包上传到指定文件夹中 这里采用的是Xftp 3.将安装包进行解压 tar -zxvf 文件名 -C 解压路径4.获取解压的全路…

day55:C++ day5,运算符重载剩余部分、静态成员、继承

#include <iostream> #include <cstring> #define pi 3.14 using namespace std;class Shape { protected:double round;double area; public://无参构造Shape():round(40),area(100){cout<<"Shape::无参构造函数&#xff0c;默认周长为40&#xff0c;面…

sql 时间函数

1&#xff0c;前提 今天看同事写的sql里面出现了时间类的函数&#xff0c;平时自己也经常用到&#xff0c;每次都要百度&#xff0c;还不如自己整理记录在一起&#xff0c;方便后续使用。 2&#xff0c;sql时间函数 2.1 获取当前时间&#xff1a; selectNOW() as 当前日期时…

docker 部署 node.js(express) 服务

1、在 express 项目根目录下新增 Dockerfile 文件&#xff0c;内容如下&#xff1a; 创建服务容器的方法&#xff0c;可以根据自己的情况选择&#xff1a; 1、以下示例为宿主机没有安装 node 环境的写法&#xff1b; 2、先在本地构建包含 node 和 express 的基础镜像&#xff0…

JavaScript中的事件捕获(event capturing)和事件冒泡(event bubbling)

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 事件捕获和事件冒泡⭐ 事件捕获&#xff08;Event Capturing&#xff09;示例&#xff1a; ⭐ 事件冒泡&#xff08;Event Bubbling&#xff09;示例&#xff1a; ⭐ 应用场景⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开…

计算机组成与设计硬件软件接口学习1

计算机的算术运算 子字并行 &#xff08;大致浏览&#xff09;pdf 170页左右 浮点加法不满足结合律&#xff1a; 适用于整型数据类型的并行执行策略并不适用于浮点数据类型 &#xff0c;原因如上↑ 处理器 流水线 流水线是一种能使多条指令重叠执行的实现技术 流水线技术通…

【C++】类和对象核心总结

类和对象核心知识目录&#xff1a; 一、面向过程和面向对象初步认识 二、类的引入定义&#xff08;struct > class&#xff09; 2.1自定义类型 struct 和 class 的区别 2.2类放在内存中的什么存储区&#xff1f; 2.3类中函数定义的方式 2.3.1声明和定义分离&#xff0…

C++项目:在线五子棋对战(网页版)

文章目录 一、项目介绍&#xff08;一&#xff09;用户管理&#xff08;二&#xff09;匹配对战&#xff08;三&#xff09;聊天功能 二、开发环境三、核心技术四、项目大流程 一、项目介绍 本项目主要实现⼀个网页版的五⼦棋对战游戏&#xff0c;其主要支持以下核心功能&…

【Redis】Bitmap 使用及应用场景

前言&#xff1a;bitmap 占用空间小&#xff0c;查询效率高&#xff0c;在一些场景中使用 bitmap 是一个很好的选择。 一、bitmap 相关命令 SETBIT - 设置指定位置的比特值&#xff0c;可以设为 1 或 0 例如 SETBIT key 10 1&#xff0c;将在 key 对应的 bitmap 中第10位设置为…

Springboot后端跨域处理

跨域 当一台服务器资源从另一台服务器&#xff08;不同的域名或者端口&#xff09;请求一个资源或者接口&#xff0c;就会发起一个跨域HTTP请求。 同源&#xff1a;协议、域名、端口都相同 只要一个不同&#xff0c;就是跨域。 例子 请求方响应方是否跨域原因http://www.ba…

Docker认识即安装

Docker及相关概念 Docker和虚拟机方式的区别&#xff1a;虚拟机技术是虚拟出一套硬件后&#xff0c;在其上运行一个完整的操作系统&#xff0c;在该系统上在运行所需应用进程&#xff1b;而容器内的应用进程是直接运行于宿主的内核&#xff0c;容器内没有自己的内核&#xff0…

GO语言网络编程(并发编程)Channel

GO语言网络编程&#xff08;并发编程&#xff09;Channel 1、Channel 1.1.1 Channel 单纯地将函数并发执行是没有意义的。函数与函数间需要交换数据才能体现并发执行函数的意义。 虽然可以使用共享内存进行数据交换&#xff0c;但是共享内存在不同的goroutine中容易发生竞态…

java并发编程 CyclicBarrier详解

文章目录 1. CyclicBarrier是什么2 核心属性详解3 核心方法详解3.1 await()3.1 breakBarrier() 4 总结 java 并发编程系列文章目录 1. CyclicBarrier是什么 在java的类注释上描述&#xff1a;一种同步辅助工具&#xff0c;允许一组线程都等待对方到达一个共同的障碍点。Cycli…