137 lines
4.6 KiB
Python
137 lines
4.6 KiB
Python
import threading
|
|
from pathlib import Path
|
|
from tkinter import (
|
|
DISABLED,
|
|
HORIZONTAL,
|
|
NORMAL,
|
|
Button,
|
|
Entry,
|
|
Frame,
|
|
Label,
|
|
Scale,
|
|
StringVar,
|
|
Tk,
|
|
filedialog,
|
|
messagebox,
|
|
)
|
|
|
|
from generate_head_extension_video import generate_video
|
|
|
|
|
|
class VideoGeneratorApp:
|
|
def __init__(self, root):
|
|
self.root = root
|
|
self.root.title("仰头角度变化视频生成工具")
|
|
self.root.geometry("760x260")
|
|
|
|
self.input_dir = StringVar(value="input_ct_2F")
|
|
self.output_file = StringVar(value=str(Path("ppt_video") / "head_extension_0_to_20deg.mp4"))
|
|
self.status = StringVar(value="请选择 DICOM 文件夹,然后点击生成视频。")
|
|
self.angle_text = StringVar(value="20°")
|
|
self.duration_text = StringVar(value="6 秒")
|
|
|
|
self.build_ui()
|
|
|
|
def build_ui(self):
|
|
top = Frame(self.root)
|
|
top.pack(fill="x", padx=12, pady=12)
|
|
|
|
Label(top, text="DICOM 文件夹").grid(row=0, column=0, sticky="w")
|
|
Entry(top, textvariable=self.input_dir, width=72).grid(row=0, column=1, padx=8)
|
|
Button(top, text="选择", command=self.choose_input).grid(row=0, column=2)
|
|
|
|
Label(top, text="输出视频").grid(row=1, column=0, sticky="w", pady=8)
|
|
Entry(top, textvariable=self.output_file, width=72).grid(row=1, column=1, padx=8)
|
|
Button(top, text="选择", command=self.choose_output).grid(row=1, column=2)
|
|
|
|
controls = Frame(self.root)
|
|
controls.pack(fill="x", padx=12, pady=4)
|
|
|
|
Label(controls, text="最大仰头角度").grid(row=0, column=0, sticky="w")
|
|
self.max_angle = Scale(
|
|
controls,
|
|
from_=5,
|
|
to=45,
|
|
orient=HORIZONTAL,
|
|
resolution=1,
|
|
length=360,
|
|
command=self.on_angle_change,
|
|
)
|
|
self.max_angle.set(20)
|
|
self.max_angle.grid(row=0, column=1, padx=8)
|
|
Label(controls, textvariable=self.angle_text, width=8, anchor="w").grid(row=0, column=2)
|
|
|
|
Label(controls, text="动画时长").grid(row=1, column=0, sticky="w")
|
|
self.duration = Scale(
|
|
controls,
|
|
from_=3,
|
|
to=12,
|
|
orient=HORIZONTAL,
|
|
resolution=1,
|
|
length=360,
|
|
command=self.on_duration_change,
|
|
)
|
|
self.duration.set(6)
|
|
self.duration.grid(row=1, column=1, padx=8)
|
|
Label(controls, textvariable=self.duration_text, width=8, anchor="w").grid(row=1, column=2)
|
|
|
|
bottom = Frame(self.root)
|
|
bottom.pack(fill="x", padx=12, pady=12)
|
|
self.generate_button = Button(bottom, text="生成视频", width=18, command=self.start_generate)
|
|
self.generate_button.pack(side="left")
|
|
Label(bottom, textvariable=self.status, anchor="w").pack(side="left", padx=12)
|
|
|
|
def choose_input(self):
|
|
path = filedialog.askdirectory(title="选择 DICOM 文件夹")
|
|
if path:
|
|
self.input_dir.set(path)
|
|
|
|
def choose_output(self):
|
|
path = filedialog.asksaveasfilename(
|
|
title="选择输出视频路径",
|
|
defaultextension=".mp4",
|
|
filetypes=[("MP4 视频", "*.mp4")],
|
|
initialfile="head_extension_0_to_20deg.mp4",
|
|
)
|
|
if path:
|
|
self.output_file.set(path)
|
|
|
|
def on_angle_change(self, value):
|
|
self.angle_text.set(f"{float(value):.0f}°")
|
|
|
|
def on_duration_change(self, value):
|
|
self.duration_text.set(f"{float(value):.0f} 秒")
|
|
|
|
def start_generate(self):
|
|
self.generate_button.config(state=DISABLED)
|
|
self.status.set("正在生成视频,请稍等...")
|
|
thread = threading.Thread(target=self.generate_worker, daemon=True)
|
|
thread.start()
|
|
|
|
def generate_worker(self):
|
|
try:
|
|
output = generate_video(
|
|
self.input_dir.get(),
|
|
self.output_file.get(),
|
|
float(self.max_angle.get()),
|
|
float(self.duration.get()),
|
|
)
|
|
self.root.after(0, lambda: self.status.set(f"完成:{output}"))
|
|
self.root.after(0, lambda: messagebox.showinfo("完成", f"视频已生成:\n{output}"))
|
|
except Exception as exc:
|
|
error_message = str(exc)
|
|
self.root.after(0, lambda: self.status.set("生成失败。"))
|
|
self.root.after(0, lambda: messagebox.showerror("生成失败", error_message))
|
|
finally:
|
|
self.root.after(0, lambda: self.generate_button.config(state=NORMAL))
|
|
|
|
|
|
def main():
|
|
root = Tk()
|
|
VideoGeneratorApp(root)
|
|
root.mainloop()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|