Newer
Older
LumenProfiler / gui_app.py
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()