import tkinter as tk
from tkinter import ttk
import tkinter.filedialog
import threading
import time
from PIL import Image, ImageOps, ImageTk
import lumen_profiler
class GuiApp:
def __init__(self):
self.tkroot = tk.Tk()
self.lp = lumen_profiler.LumenProfiler()
self.is_open = False
self.is_analyzed = False
def make_window(self):
self.tkroot.title("Lumen Profiler")
self.tkroot.geometry("800x600")
# ファイル入力フレーム
self.top_frame = tk.Frame(self.tkroot)
self.top_frame.pack(fill=tk.X, pady=5)
self.file_button = tk.Button(
self.top_frame, text="映像ファイルを開く", command=self.open_movie
)
self.file_button.pack(side=tk.LEFT)
self.file_text = tk.Label(self.top_frame, text="no movie")
self.file_text.pack(side=tk.LEFT, fill=tk.X, padx=(20, 0))
self.progressbar = ttk.Progressbar(self.top_frame, orient="horizontal", length=200, mode="determinate", maximum=99)
self.progressbar.pack(side=tk.LEFT, padx=(20, 0))
# 分析フレーム
self.analize_frame = tk.Frame(self.tkroot)
# self.analize_frame.pack(fill=tk.X, pady=5)
self.analyze_button = tk.Button(
self.analize_frame, text="分析を実行", command=self.analyze
)
self.analyze_button.pack(side=tk.LEFT)
self.area_ratio_label = tk.Label(self.analize_frame, text="暗部の面積比率(%)")
self.area_ratio_label.pack(side=tk.LEFT, padx=(20, 0))
self.area_ratio_text = tk.Entry(self.analize_frame, width=5, justify=tk.RIGHT)
self.area_ratio_text.insert(tk.END, "8.0")
self.area_ratio_text.pack(side=tk.LEFT)
self.interval_label = tk.Label(self.analize_frame, text="分析フレーム間隔")
self.interval_label.pack(side=tk.LEFT, padx=(20, 0))
self.interval_text = tk.Entry(self.analize_frame, width=5, justify=tk.RIGHT)
self.interval_text.insert(tk.END, "2")
self.interval_text.pack(side=tk.LEFT)
self.sigma_label = tk.Label(self.analize_frame, text="シグマ(輪郭の円滑性)")
self.sigma_label.pack(side=tk.LEFT, padx=(20, 0))
self.sigma_text = tk.Entry(self.analize_frame, width=5, justify=tk.RIGHT)
self.sigma_text.insert(tk.END, "5.0")
self.sigma_text.pack(side=tk.LEFT)
self.save_button = tk.Button(
self.analize_frame, text="分析結果を保存", command=self.on_save
)
self.save_button.pack(side=tk.LEFT)
# 画像表示
self.canvas = tk.Canvas(self.tkroot, bg="black")
self.canvas.pack(fill=tk.BOTH, expand=True)
self.time_slider = tk.Scale(
self.tkroot,
from_=0,
to=0,
orient=tk.HORIZONTAL,
command=self.on_time_slider_change,
)
self.time_slider.pack(fill=tk.X)
self.tkroot.mainloop()
# 分析
def analyze(self):
interval = int(self.interval_text.get())
ratio = float(self.area_ratio_text.get()) / 100
sigma = float(self.sigma_text.get())
self.lp.profiling(ratio, sigma, interval)
self.time_slider.config(to=len(self.lp.results) - 1)
self.time_slider.set(0)
self.is_analyzed = True
self.show_image()
# 映像ファイルを開く
def open_movie(self):
filename = tk.filedialog.askopenfilename(filetypes=[("mp4", "*.mp4")])
if filename == "": # cancel
return
# 映像読み込み(ワーカースレッド)
thread = threading.Thread(target=self.lp.load_movie, args=(filename,))
thread.start()
while thread.is_alive():
self.progressbar.configure(value=len(self.lp.frames) % 100)
self.progressbar.update()
time.sleep(0.01)
thread.join()
self.progressbar.configure(value=0)
# self.lp.load_movie(filename)
# 読み込み後の処理
self.file_text.config(text=filename)
self.time_slider.set(0)
self.time_slider.config(to=self.lp.frame_count - 1)
self.is_analyzed = False
self.show_image()
if not self.is_open:
self.analize_frame.pack(fill=tk.X, pady=5, after=self.top_frame)
self.is_open = True
# 分析結果を保存
def on_save(self):
self.lp.csv_output("result.csv")
# スライダー操作イベント
def on_time_slider_change(self, event):
self.show_image()
# 画像表示
def show_image(self):
rid = self.time_slider.get()
if not self.is_analyzed:
img = self.lp.bgr2rgb(self.lp.frames[rid])
else:
img = self.lp.bgr2rgb(self.lp.draw(rid))
pil = Image.fromarray(img)
pil = ImageOps.pad(pil, (self.canvas.winfo_width(), self.canvas.winfo_height()))
self.disp = ImageTk.PhotoImage(pil)
# self.canvas.delete("all")
self.canvas.create_image(0, 0, image=self.disp, anchor=tk.NW)
self.save_button.config(state=tk.NORMAL if self.is_analyzed else tk.DISABLED)
# main
if __name__ == "__main__":
app = GuiApp()
app.make_window()