【GPT寫代碼】動作視頻切截圖研究器

目錄

  • 背景
    • 源代碼
  • end

背景

用python寫一個windows環境運行的動作視頻切截圖研究器,用路徑瀏覽的方式指定待處理的視頻文件,然后點擊分析按鈕,再預覽區域顯示視頻預覽畫面,然后拖動時間軸,可以在預覽區域刷新顯示相應的畫面,時間軸要能夠顯示視頻總時長和當前按鈕所在位置的,輸入想要截取的視頻時間范圍和間隔的毫秒數,最后再視頻所在路徑保存所有截取的視頻畫面圖片。

遇到CV2中文路徑無法保存的問題
filename = os.path.join(output_dir, f"frame_{i:04d}.jpg")
cv2.imwrite(filename, frame)
filename = os.path.normpath(os.path.join(output_dir, self.video_name+f"_{i:04d}.jpg"))

源代碼

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import cv2
import os
from PIL import Image, ImageTk
import threading
import queueclass VideoSlicerApp:def __init__(self, root):self.root = rootself.root.title("動作視頻切片研究器")# 窗口設置screen_width = root.winfo_screenwidth()screen_height = root.winfo_screenheight()self.root.geometry(f"{int(screen_width * 0.7)}x{int(screen_height * 0.7)}")self.root.minsize(800, 600)# 初始化變量self.video_path = tk.StringVar()self.video_name = "video"self.cap = Noneself.total_frames = 0self.fps = 0self.current_frame = 0self.original_size = (0, 0)self.preview_size = (800, 450)self.progress_queue = queue.Queue()# 創建界面self.create_widgets()self.root.bind("<Configure>", self.on_window_resize)# 定期檢查進度self.root.after(100, self.check_progress)def create_widgets(self):main_frame = ttk.Frame(self.root)main_frame.pack(fill='both', expand=True, padx=10, pady=5)# 文件選擇file_frame = ttk.Frame(main_frame)file_frame.pack(fill='x', pady=5)ttk.Label(file_frame, text="視頻文件:").pack(side='left')ttk.Entry(file_frame, textvariable=self.video_path, width=40).pack(side='left', padx=5, fill='x', expand=True)ttk.Button(file_frame, text="瀏覽", command=self.browse_file).pack(side='left')# 分析按鈕self.analyze_button = ttk.Button(main_frame, text="分析視頻", command=self.analyze_video)self.analyze_button.pack(pady=5)# 預覽區域self.preview_container = ttk.Frame(main_frame)self.preview_container.pack(fill='both', expand=True)self.preview_label = ttk.Label(self.preview_container)self.preview_label.pack(fill='both', expand=True)# 時間軸control_frame = ttk.Frame(main_frame)control_frame.pack(fill='x', pady=5)self.time_label = ttk.Label(control_frame, text="00:00:00 / 00:00:00")self.time_label.pack(side='bottom', fill='x')self.time_scale = ttk.Scale(control_frame, from_=0, to=100, command=self.update_frame)self.time_scale.pack(fill='x', padx=5)# 參數輸入param_frame = ttk.Frame(main_frame)param_frame.pack(fill='x', pady=5)ttk.Label(param_frame, text="開始時間(ms):").grid(row=0, column=0, padx=5)self.start_time = ttk.Entry(param_frame, width=10)self.start_time.grid(row=0, column=1, padx=5)ttk.Label(param_frame, text="結束時間(ms):").grid(row=0, column=2, padx=5)self.end_time = ttk.Entry(param_frame, width=10)self.end_time.grid(row=0, column=3, padx=5)ttk.Label(param_frame, text="間隔(ms):").grid(row=0, column=4, padx=5)self.interval = ttk.Entry(param_frame, width=10)self.interval.grid(row=0, column=5, padx=5)# 進度條self.progress = ttk.Progressbar(main_frame, orient='horizontal', mode='determinate')self.progress.pack(fill='x', pady=5)# 保存按鈕self.save_button = ttk.Button(main_frame, text="保存切片", command=self.save_slices)self.save_button.pack(pady=5)def browse_file(self):file_path = filedialog.askopenfilename(filetypes=[("視頻文件", "*.mp4 *.avi *.mov")])if file_path:self.video_path.set(file_path)def analyze_video(self):if not self.video_path.get():messagebox.showerror("錯誤", "請先選擇視頻文件")returnself.video_name = os.path.splitext(os.path.basename(repr(self.video_path.get())))[0]print(self.video_name)self.cap = cv2.VideoCapture(self.video_path.get())if not self.cap.isOpened():messagebox.showerror("錯誤", "無法打開視頻文件")returnself.fps = self.cap.get(cv2.CAP_PROP_FPS)self.total_frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))self.time_scale.config(to=self.total_frames)self.original_size = (int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))self.update_preview_size()self.show_frame(0)def update_preview_size(self):container_width = self.preview_container.winfo_width()container_height = self.preview_container.winfo_height()max_width = max(container_width - 20, 100)max_height = max(container_height - 20, 100)ratio = min(max_width / self.original_size[0], max_height / self.original_size[1])self.preview_size = (int(self.original_size[0] * ratio),int(self.original_size[1] * ratio))def on_window_resize(self, event):if self.cap and self.cap.isOpened():self.update_preview_size()self.show_frame(self.current_frame)def show_frame(self, frame_num):self.current_frame = frame_numself.cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)ret, frame = self.cap.read()if ret:frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)img = Image.fromarray(frame)img = img.resize(self.preview_size, Image.Resampling.LANCZOS)img_tk = ImageTk.PhotoImage(img)self.preview_label.config(image=img_tk)self.preview_label.image = img_tkcurrent_time = frame_num / self.fpstotal_time = self.total_frames / self.fpsself.time_label.config(text=f"{self.format_time(current_time)} / {self.format_time(total_time)}")def format_time(self, seconds):ms = int((seconds - int(seconds)) * 1000)seconds = int(seconds)h = seconds // 3600m = (seconds % 3600) // 60s = seconds % 60return f"{h:02d}:{m:02d}:{s:02d}.{ms:03d}"def update_frame(self, value):frame_num = int(float(value))self.show_frame(frame_num)def save_slices(self):if not self.cap:messagebox.showerror("錯誤", "請先分析視頻")returntry:start = int(self.start_time.get())end = int(self.end_time.get())interval = int(self.interval.get())if start >= end or interval <= 0:raise ValueErrorexcept ValueError:messagebox.showerror("輸入錯誤", "請輸入有效的時間范圍\n(開始<結束,間隔>0)")return# 禁用按鈕防止重復點擊self.save_button["state"] = "disabled"self.analyze_button["state"] = "disabled"# 計算幀數范圍start_frame = int(start * self.fps / 1000)end_frame = int(end * self.fps / 1000)interval_frames = int(interval * self.fps / 1000)total_saves = (end_frame - start_frame) // interval_framesself.progress['maximum'] = total_savesself.progress['value'] = 0save_thread = threading.Thread(target=self.process_slices,args=(start_frame, end_frame, interval_frames))save_thread.daemon = Truesave_thread.start()def process_slices(self, start_frame, end_frame, interval_frames):try:# 使用獨立視頻實例cap = cv2.VideoCapture(self.video_path.get())output_dir = os.path.join(os.path.dirname(self.video_path.get()),self.video_name+"_slices")if not os.path.exists(output_dir):os.makedirs(output_dir)frame_count = 0total = (end_frame - start_frame) // interval_framesfor i in range(total):frame_num = start_frame + i * interval_framescap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)ret, frame = cap.read()if ret:filename = os.path.normpath(os.path.join(output_dir, self.video_name+f"_{i:04d}.jpg"))print(filename)# cv2.imwrite(filename, frame)img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)img_pil = Image.fromarray(img)img_pil.save(filename)self.progress_queue.put(("progress", i + 1))else:self.progress_queue.put(("error", f"無法讀取 {frame_num} 幀"))cap.release()self.progress_queue.put(("done", total))except Exception as e:self.progress_queue.put(("error", str(e)))def check_progress(self):try:while not self.progress_queue.empty():msg_type, msg_data = self.progress_queue.get_nowait()if msg_type == "error":messagebox.showerror("保存錯誤", msg_data)self.reset_controls()elif msg_type == "done":self.progress['value'] = self.progress['maximum']messagebox.showinfo("完成", f"成功保存{msg_data}張切片")self.reset_controls()elif msg_type == "progress":self.progress['value'] = msg_dataexcept queue.Empty:passself.root.after(100, self.check_progress)def reset_controls(self):self.save_button["state"] = "normal"self.analyze_button["state"] = "normal"if __name__ == "__main__":root = tk.Tk()app = VideoSlicerApp(root)root.mainloop()

end

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/75689.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/75689.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/75689.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在 .NET 8 中使用自定義令牌身份驗證掌握 SignalR Hub 安全性

最近在練習做一個 Web 開發項目&#xff0c;需要使用 WebSockets 傳輸數據&#xff0c;實現實時通信。這是一個 React.js 項目&#xff0c;后端是 .NET。 雖然 MSDN 提供了出色的頂級文檔&#xff0c;但它通常缺少高級用例所需的低級細節。 一種這樣的場景是使用自定義令牌對…

[2018][note]用于超快偏振開關和動態光束分裂的all-optical有源THz超表——

前言 類型 太赫茲 + 超表面 太赫茲 + 超表面 太赫茲+超表面 期刊 O p e n A c c e s s Open Access Open

家里網絡訪問Github有時候打不開,解決辦法

1、修改Hosts文件修改法 通過DNS查詢工具&#xff08;如&#xff09;獲取最新GitHub域名解析IP修改系統hosts文件&#xff08;路徑&#xff1a;C:\Windows\System32\drivers\etc\hosts&#xff09;&#xff0c;添加&#xff1a;20.205.243.166 github.com 20.27.177.113 github…

MyBatis操作數據庫(1)

1. MyBatis 簡介 MyBatis 是一款持久層框架&#xff0c;簡化了 JDBC 的復雜操作&#xff0c;通過配置和映射文件將 Java 對象與數據庫表關聯。核心優勢&#xff1a; 自動管理資源&#xff1a;無需手動關閉連接、釋放資源。 動態 SQL&#xff1a;支持參數綁定、條件查詢等。 …

ModuleNotFoundError: No module named ‘matplotlib_inline‘

ModuleNotFoundError: No module named matplotlib_inline 1. ModuleNotFoundError: No module named matplotlib_inline2. matplotlib-inlineReferences 如果你在普通的 Python 腳本或命令行中運行代碼&#xff0c;那么不需要 matplotlib_inline&#xff0c;因為普通的 Python…

SSL證書自動化管理(ACME協議)工作流程介紹

SSL證書自動化管理&#xff08;ACME協議&#xff09;是一種用于自動化管理SSL/TLS證書的協議&#xff0c;以下是其詳細介紹&#xff1a; 一、ACME協議概述 ACME協議由互聯網安全研究小組&#xff08;ISRG&#xff09;設計開發&#xff0c;旨在實現SSL證書獲取流程的自動化。通…

基于FPGA的特定序列檢測器verilog實現,包含testbench和開發板硬件測試

目錄 1.課題概述 2.系統測試效果 3.核心程序與模型 4.系統原理簡介 5.完整工程文件 1.課題概述 本課題采用基于偽碼匹配相關峰檢測的方式實現基于FPGA的特定序列檢測器verilog實現,包含testbench和開發板硬件測試。 2.系統測試效果 仿真測試 當檢測到序列的時候&#xf…

#管理Node.js的多個版本

在 Windows 11 上管理 Node.js 的多個版本&#xff0c;最方便的方法是使用 nvm-windows&#xff08;Node Version Manager for Windows&#xff09;。它允許你輕松安裝、切換和管理多個 Node.js 版本。 &#x1f4cc; 方法 1&#xff1a;使用 nvm-windows&#xff08;推薦 ?&a…

【已解決】Webstorm 每次使用 git pull/push 都要輸入令牌/密碼登錄

解決辦法&#xff1a;勾上【使用憑據幫助程序】&#xff08;英文&#xff1a;Use credential helper&#xff09;

大模型架構記錄13【hr agent】

一 Function calling 函數調用 from dotenv import load_dotenv, find_dotenvload_dotenv(find_dotenv())from openai import OpenAI import jsonclient OpenAI()# Example dummy function hard coded to return the same weather # In production, this could be your back…

Spring Boot向Vue發送消息通過WebSocket實現通信

注意&#xff1a;如果后端有contextPath&#xff0c;如/app&#xff0c;那么前端訪問的url就是ip:port/app/ws 后端實現步驟 添加Spring Boot WebSocket依賴配置WebSocket端點和消息代理創建控制器&#xff0c;使用SimpMessagingTemplate發送消息 前端實現步驟 安裝sockjs-…

【嵌入式學習5】PyQt5模塊介紹、創建第一個窗口

目錄 1、PyQt介紹 ①特點 ②主要組件 2、創建第一個窗口 exce_() 1、PyQt介紹 PyQt 是一個用于創建圖形用戶界面&#xff08;GUI&#xff09;應用程序的 Python 庫&#xff0c;它是 Qt 框架的 Python 綁定。 ①特點 跨平臺&#xff1a;支持多種操作系統&#xff0c;包括…

封裝自己的api簽名sdk

api平臺接口調用&#xff0c;需要通過簽名去核對是不是有效的用戶&#xff0c;&#xff0c;一般會給兩個key&#xff0c;acceeKey 和 secretKey,第一個相當于用戶名&#xff0c;第二個相當于密鑰&#xff0c;&#xff0c;&#xff0c;前端通過一定的算法&#xff0c;&#xff0…

很簡單 的 將字幕生成視頻的 方法

一、一鍵將字幕生成視頻的 方法 1、下載任性動圖 10.7 以上版本 2、設置背景 1&#xff09;背景大小 拉伸背景到合適大小&#xff0c;或者選擇右側比例 2&#xff09;、直接空背景&#xff0c;設置背景顏色等詳細信息 3&#xff09;、或者 復制或者突然圖片做背景 3、設置文…

Spring 核心技術解析【純干貨版】- XXI:Spring 第三方工具整合模塊 Spring-Context-Suppor 模塊精講

在企業級開發中&#xff0c;我們經常需要與 第三方工具 進行集成&#xff0c;如 郵件發送、任務調度、緩存管理等。Spring 為此提供了 Spring-Context-Support 模塊&#xff0c;它封裝了多個常見的第三方工具庫&#xff0c;使得開發者可以更方便地將它們集成到 Spring 項目中。…

c++柔性數組、友元、類模版

目錄 1、柔性數組&#xff1a; 2、友元函數&#xff1a; 3、靜態成員 注意事項 面試題&#xff1a;c/c static的作用? C語言&#xff1a; C: 為什么可以創建出 objx 4、對象與對象之間的關系 5、類模版 1、柔性數組&#xff1a; #define _CRT_SECURE_NO_WARNINGS #…

主相機綁定小地圖

資源初始化&#xff1a;在類中通過 property 裝飾器定義主相機、小地圖相機、小地圖精靈等資源屬性&#xff0c;便于在編輯器中賦值。在 start 方法里&#xff0c;當確認這些資源存在后&#xff0c;創建渲染紋理并設置其大小&#xff0c;將渲染紋理與小地圖相機關聯&#xff0c…

linux-core分析-柔性數組越界訪問

文章目錄 core的調用棧core分析修改修改原因柔性數組定義代碼修改總結core的調用棧 vocb core 崩潰:core的大小都是573M左右 Program terminated with signal SIGSEGV, Segmentation fault. #0 0x0000007f789af0d0 in strlen () from /lib/libc.so.6[Current thread is 1 (LW…

leetcode 代碼隨想錄 數組-區間和

題目 給定一個整數數組 Array&#xff0c;請計算該數組在每個指定區間內元素的總和。 輸入&#xff1a; 第一行輸入&#xff1a;為整數數組 Array 的長度 n&#xff0c;接下來 n 行&#xff0c;每行一個整數&#xff0c;表示數組的元素。隨后的輸入為需要計算總和的區間&…

部署nerdctl工具

nerdctl 是一個專為Containerd設計的容器管理命令行工具&#xff0c;旨在提供類似 Docker 的用戶體驗&#xff0c;同時支持 Containerd 的高級特性&#xff08;如命名空間、compose等&#xff09;。 1、下載安裝 wget https://github.com/containerd/nerdctl/releases/downlo…