Python视频裁剪工具开发遇NameError:VideoTrimmer未定义
解决Python视频裁剪工具的NameError问题
问题场景
开发一款支持路径选择、滑块剪辑的Python视频裁剪工具时,运行代码触发NameError,报错信息如下:
Exception has occurred: NameError name 'VideoTrimmer' is not defined File "D:\Programs\Visual Studio\Video-trimmer.py", line 141, in VideoTrimmer VideoTrimmer(root) File "D:\Programs\Visual Studio\Video-trimmer.py", line 7, in <module> class VideoTrimmer: NameError: name 'VideoTrimmer' is not defined
错误原因
- 缩进层级错误:
update_video_player和slider_changed两个类方法被错误嵌套在trim_video方法内部,导致VideoTrimmer类的定义未正常完成,Python解释器无法识别该类。 - 缺失依赖导入:
update_video_player方法中使用了PIL库的相关模块,但代码顶部未导入PIL.Image和PIL.ImageTk。
修复后的完整代码
import tkinter as tk from tkinter import filedialog, messagebox from moviepy.video.io.VideoFileClip import VideoFileClip import numpy as np import cv2 # 新增PIL库导入 from PIL import Image, ImageTk class VideoTrimmer: def __init__(self, master): self.master = master self.master.title("Video Trimmer") self.video_path_label = tk.Label(self.master, text="Video path:") self.video_path_label.pack() self.video_path_entry = tk.Entry(self.master) self.video_path_entry.pack() self.browse_video_button = tk.Button(self.master, text="Browse", command=self.browse_video) self.browse_video_button.pack() self.start_time_label = tk.Label(self.master, text="Start time (seconds):") self.start_time_label.pack() self.start_time_entry = tk.Entry(self.master) self.start_time_entry.pack() self.end_time_label = tk.Label(self.master, text="End time (seconds):") self.end_time_label.pack() self.end_time_entry = tk.Entry(self.master) self.end_time_entry.pack() self.output_path_label = tk.Label(self.master, text="Output path:") self.output_path_label.pack() self.output_path_entry = tk.Entry(self.master) self.output_path_entry.pack() self.browse_output_button = tk.Button(self.master, text="Browse", command=self.browse_output) self.browse_output_button.pack() self.video_frame = tk.Frame(self.master, width=640, height=480) self.video_frame.pack() self.slider_frame = tk.Frame(self.master) self.slider_frame.pack() self.trim_button = tk.Button(self.master, text="Trim Video", command=self.trim_video) self.trim_button.pack() self.cap = None self.photo = None self.video_canvas = tk.Canvas(self.video_frame, width=640, height=480) self.video_canvas.pack() self.slider = tk.Scale(self.slider_frame, from_=0, to=0, orient=tk.HORIZONTAL, length=640, command=self.slider_changed) self.slider.pack() def browse_video(self): filetypes = [("MP4 files", "*.mp4"), ("AVI files", "*.avi"), ("All files", "*.*")] filepath = filedialog.askopenfilename(filetypes=filetypes) self.video_path_entry.delete(0, tk.END) self.video_path_entry.insert(0, filepath) self.cap = cv2.VideoCapture(filepath) self.slider.configure(to=int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))-1) self.slider.set(0) self.update_video_player() def browse_output(self): filetypes = [("MP4 files", "*.mp4"), ("All files", "*.*")] filepath = filedialog.asksaveasfilename(filetypes=filetypes, defaultextension=".mp4") self.output_path_entry.delete(0, tk.END) self.output_path_entry.insert(0, filepath) def trim_video(self): start_time = float(self.start_time_entry.get()) end_time = float(self.end_time_entry.get()) fps = int(self.cap.get(cv2.CAP_PROP_FPS)) start_frame = int(start_time * fps) end_frame = int(end_time * fps) self.cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame) output_path = self.output_path_entry.get() fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 获取原视频的宽高,避免强制设置640x480导致画面变形 width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) writer = cv2.VideoWriter(output_path, fourcc, fps, (width, height)) for frame_num in range(start_frame, end_frame): ret, frame = self.cap.read() if not ret: break writer.write(frame) self.cap.release() writer.release() messagebox.showinfo("Trimming Complete", "Video trimming complete.") # 调整缩进,作为类的顶级方法 def update_video_player(self): if self.cap is None: return ret, frame = self.cap.read() if not ret: return frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) frame = np.rot90(frame) frame = np.flipud(frame) frame = ImageTk.PhotoImage(image=Image.fromarray(frame)) if self.photo is None: self.photo = self.video_canvas.create_image(0, 0, image=frame, anchor=tk.NW) else: self.video_canvas.itemconfig(self.photo, image=frame) # 保留引用,避免图像被GC回收 self.video_canvas.image = frame self.master.after(30, self.update_video_player) # 调整缩进,作为类的顶级方法 def slider_changed(self, value): if self.cap is None: return frame_num = int(value) self.cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num) if __name__ == "__main__": root = tk.Tk() app = VideoTrimmer(root) root.mainloop()
额外注意事项
- 安装所需依赖包:执行
pip install opencv-python pillow moviepy numpy(tkinter通常随Python自带,若缺失需单独安装) - 修复了视频写入时强制设置640x480导致的画面变形问题,改为使用原视频的宽高
- 添加了图像引用保留,避免tkinter中图像被垃圾回收导致显示异常
内容的提问来源于stack exchange,提问作者Alber
相关产品推荐
相关产品推荐

