Source code for DiatomTrack.gui.parser

import os
import tkinter as tk

from tkinter import filedialog, messagebox
from tkinter import ttk
from sys import exit


[docs]class ParserDirectory: """ GUI for parsing initial directories for processing from scratch. """ def __init__(self): """ Initialize the window. """ # Window self.master = tk.Tk() self.master.title("Select directoy") self.master.protocol("WM_DELETE_WINDOW", self.close_window) self.master.lift() self.master.focus_force() # Variables self.skip = False self.image_dir = tk.StringVar() self.model_states = tk.StringVar() self.destination_dir = tk.StringVar() self.file_name = tk.StringVar() self.frame_limit = tk.IntVar() self.only_segmentation = tk.BooleanVar(value=False) # Input fields tk.Label( self.master, text="Images:" ).grid(row=0, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.image_dir, width=40 ).grid(row=0, column=1, padx=10, pady=5) tk.Button( self.master, text="Browse...", command=self.select_source ).grid(row=0, column=2, padx=10, pady=5) tk.Label( self.master, text="Model states:" ).grid(row=1, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.model_states, width=40 ).grid(row=1, column=1, padx=10, pady=5) tk.Button( self.master, text="Browse...", command=self.select_states ).grid(row=1, column=2, padx=10, pady=5) tk.Label( self.master, text="Save in:" ).grid(row=2, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.destination_dir, width=40 ).grid(row=2, column=1, padx=10, pady=5) tk.Button( self.master, text="Browse...", command=self.select_saving ).grid(row=2, column=2, padx=10, pady=5) tk.Label( self.master, text="Save as:" ).grid(row=3, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.file_name, width=40 ).grid(row=3, column=1, padx=10, pady=5) tk.Label( self.master, text="Until frame:" ).grid(row=4, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.frame_limit, width=40 ).grid(row=4, column=1, padx=10, pady=5) tk.Label( self.master, text="Only run image segmentation and save data for later editing." ).grid(row=5, column=0, columnspan=2, padx=10, pady=5) checkbox_original = ttk.Checkbutton( self.master, variable=self.only_segmentation) checkbox_original.grid(row=5, column=2, padx=10, pady=5) # Progress buttons frame = tk.Frame(self.master) frame.grid( row=6, column=0, columnspan=3, sticky='nsew', padx=10, pady=5) frame.grid_columnconfigure(0, weight=1) frame.grid_columnconfigure(1, weight=1) frame.grid_columnconfigure(2, weight=1) frame.grid_rowconfigure(1, weight=1) self.confirm = tk.Button(frame, text="Ok", command=self.parse) reset = tk.Button(frame, text="Reset", command=self.reset_inputs) skip = tk.Button(frame, text="Skip", command=self.skip_window) self.confirm.grid(row=0, column=0, padx=5, pady=5, sticky='ew') reset.grid(row=0, column=1, padx=5, pady=5, sticky='ew') skip.grid(row=0, column=2, padx=5, pady=5, sticky='ew') # Return key bind self.master.bind('<Return>', self.invoke_confirm) # Start self.master.mainloop()
[docs] def select_source(self): """ Select the image directory. """ dir_ = filedialog.askdirectory() if dir_: self.image_dir.set(dir_)
[docs] def select_saving(self): """ Select the directory for saving. """ dir_ = filedialog.askdirectory() if dir_: self.destination_dir.set(dir_)
[docs] def select_states(self): """ Select the model states. """ path = filedialog.askopenfilename() if path: self.model_states.set(path)
[docs] def skip_window(self): """ Skip this window and go to the next step. """ self.skip = True self.master.destroy()
[docs] def invoke_confirm(self, event): """ Invoke the Ok button with Return to progress. """ self.confirm.invoke()
[docs] def parse(self): """ Parse and check inputs and close window if no error. """ source_dir = self.image_dir.get() destination_dir = self.destination_dir.get() states = self.model_states.get() save_as_name = self.file_name.get() if not os.path.isdir(source_dir): messagebox.showerror("Error", "Invalid source directory!") return if not os.path.isdir(destination_dir): messagebox.showerror("Error", "Invalid destination directory!") return if not os.path.isfile(states): messagebox.showerror("Error", "Invalid states file selected!") return if not save_as_name : messagebox.showerror("Error", "Save as file name is required!") return self.master.destroy()
[docs] def reset_inputs(self): """ Reset all input fields. """ self.image_dir.set('') self.model_states.set('') self.destination_dir.set('') self.file_name.set('') self.frame_limit.set(0)
[docs] def close_window(self): """ Confirm abrupt exit. """ if messagebox.askyesno( "Confirm Exit", "Are you sure you want to exit?"): self.master.destroy() self.window_exception()
[docs] def window_exception(self): """ Exit immediately. """ messagebox.showerror( "Window closed.", "Window was closed unexpectedly. The program terminates now.") exit()
[docs]class ParserSkip: """ GUI for parsing directories for processing from tracking. """ def __init__(self): """ Initialize the window. """ # Window self.master = tk.Tk() self.master.title("Select directory") self.master.protocol("WM_DELETE_WINDOW", self.close_window) self.master.lift() self.master.focus_force() # Variables self.skip = False self.segmentation_name = tk.StringVar() self.video_name = tk.StringVar() self.destination_dir = tk.StringVar() self.file_name = tk.StringVar() self.limit = tk.IntVar() self.file_name.set('Experiment1') self.limit.set(0) # Input fields tk.Label( self.master, text="Segmentation:" ).grid(row=0, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.segmentation_name, width=40 ).grid(row=0, column=1, padx=10, pady=5) tk.Button( self.master, text="Browse...", command=self.select_segmentation ).grid(row=0, column=2, padx=10, pady=5) tk.Label( self.master, text="Video file:" ).grid(row=1, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.video_name, width=40 ).grid(row=1, column=1, padx=10, pady=5) tk.Button( self.master, text="Browse...", command=self.select_video ).grid(row=1, column=2, padx=10, pady=5) tk.Label( self.master, text="Save in:" ).grid(row=2, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.destination_dir, width=40 ).grid(row=2, column=1, padx=10, pady=5) tk.Button( self.master, text="Browse...", command=self.select_saving ).grid(row=2, column=2, padx=10, pady=5) tk.Label( self.master, text="Save as:" ).grid(row=3, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.file_name, width=40 ).grid(row=3, column=1, padx=10, pady=5) tk.Label( self.master, text="Frame limit:" ).grid(row=4, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.limit, width=40 ).grid(row=4, column=1, padx=10, pady=5) # Progress buttons frame = tk.Frame(self.master) frame.grid( row=5, column=0, columnspan=3, sticky='nsew', padx=10, pady=5) frame.grid_columnconfigure(0, weight=1) frame.grid_columnconfigure(1, weight=1) frame.grid_columnconfigure(2, weight=1) frame.grid_rowconfigure(1, weight=1) self.confirm = tk.Button(frame, text="Ok", command=self.parse) reset = tk.Button(frame, text="Reset", command=self.reset_inputs) skip = tk.Button(frame, text="Skip", command=self.skip_window) self.confirm.grid(row=0, column=0, padx=5, pady=5, sticky='ew') reset.grid(row=0, column=1, padx=5, pady=5, sticky='ew') skip.grid(row=0, column=2, padx=5, pady=5, sticky='ew') # Return key bind self.master.bind('<Return>', self.invoke_confirm) # Start self.master.mainloop()
[docs] def select_segmentation(self): """ Select segmentation data. """ path = filedialog.askopenfilename() if path: self.segmentation_name.set(path)
[docs] def select_video(self): """ Select video file. """ path = filedialog.askopenfilename() if path: self.video_name.set(path)
[docs] def select_saving(self): """ Select directory for saving. """ dir_ = filedialog.askdirectory() if dir_: self.destination_dir.set(dir_)
[docs] def select_states(self): """ Select model states. """ path = filedialog.askopenfilename() if path: self.model_states.set(path)
[docs] def skip_window(self): """ Skip this window and go to the next step. """ self.skip = True self.master.destroy()
[docs] def invoke_confirm(self, event): """ Invoke the Ok button with Return to progress. """ self.confirm.invoke()
[docs] def parse(self): """ Parse and check inputs and close window if no error. """ segmentation = self.segmentation_name.get() video = self.video_name.get() destination_dir = self.destination_dir.get() save_as_name = self.file_name.get() if not os.path.isfile(segmentation): messagebox.showerror( "Error", "Invalid segmentation file selected!") return if ( segmentation.split('.')[-1] != 'pkl' and segmentation.split('.')[-1] != 'csv' ): messagebox.showerror( "Error", "Segmentation file needs to be .pkl or .csv!") return if not os.path.isfile(video): messagebox.showerror( "Error", "Invalid segmentation file selected!") return if not os.path.isdir(destination_dir): messagebox.showerror("Error", "Invalid destination directory!") return if not save_as_name : messagebox.showerror("Error", "Save as file name is required!") return try: _ = self.limit.get() except: messagebox.showerror("Error", "Limit needs to be integer!") return self.master.destroy()
[docs] def reset_inputs(self): """ Reset all input fields. """ self.segmentation_name.set('') self.video_name.set('') self.destination_dir.set('') self.file_name.set('Experiment1') self.limit.set(0)
[docs] def close_window(self): """ Confirm abrupt exit. """ if messagebox.askyesno( "Confirm Exit", "Are you sure you want to exit?"): self.master.destroy() self.window_exception()
[docs] def window_exception(self): """ Exit immediately. """ messagebox.showerror( "Window closed.", "Window was closed unexpectedly. The program terminates now.") exit()
[docs]class ParserTrack: """ GUI for parsing tracking parameters. """ def __init__(self): """ Initialize the window. """ # Window self.master = tk.Tk() self.master.title("Tracker setup") self.master.protocol("WM_DELETE_WINDOW", self.close_window) self.master.lift() self.master.focus_force() # Variables self.age = tk.IntVar() self.gap = tk.IntVar() self.split = tk.IntVar() self.offset = tk.IntVar() self.age.set(500) self.gap.set(200) self.split.set(50) self.offset.set(80) # Create input fields and buttons tk.Label( self.master, text="Enter maximum age:" ).grid(row=0, column=0, padx=10, pady=5, sticky='w') ttk.Entry( self.master, textvariable=self.age, width=20 ).grid(row=0, column=1, padx=10, pady=5) tk.Label( self.master, text="Enter offset from prediction:" ).grid(row=1, column=0, padx=10, pady=5, sticky='w') ttk.Entry( self.master, textvariable=self.offset, width=20 ).grid(row=1, column=1, padx=10, pady=5) tk.Label( self.master, text="Enter distance after splitting:" ).grid(row=2, column=0, padx=10, pady=5, sticky='w') ttk.Entry( self.master, textvariable=self.split, width=20 ).grid(row=2, column=1, padx=10, pady=5) tk.Label( self.master, text="Enter gap closing distance:" ).grid(row=3, column=0, padx=10, pady=5, sticky='w') ttk.Entry( self.master, textvariable=self.gap, width=20 ).grid(row=3, column=1, padx=10, pady=5) # Progress buttons frame = tk.Frame(self.master) frame.grid( row=4, column=0, columnspan=3, sticky='nsew', padx=10, pady=5) frame.grid_columnconfigure(0, weight=1) frame.grid_columnconfigure(1, weight=1) self.confirm = tk.Button(frame, text="Ok", command=self.parse) reset = tk.Button(frame, text="Reset", command=self.reset_inputs) self.confirm.grid(row=0, column=0, padx=5, pady=5, sticky='ew') reset.grid(row=0, column=1, padx=5, pady=5, sticky='ew') # Return key bind self.master.bind('<Return>', self.invoke_confirm) # Start self.master.mainloop()
[docs] def invoke_confirm(self, event): """ Invoke the Ok button with Return to progress. """ self.confirm.invoke()
[docs] def parse(self): """ Parse and check inputs and close window if no error. """ try: _ = self.age.get() _ = self.offset.get() _ = self.split.get() _ = self.gap.get() except: messagebox.showerror("Error", "Entry needs to be integer!") return self.master.destroy()
[docs] def reset_inputs(self): """ Reset all input fields. """ self.age.set(200) self.offset.set(80) self.split.set(50) self.gap.set(200)
[docs] def close_window(self): """ Confirm abrupt exit. """ if messagebox.askyesno( "Confirm Exit", "Are you sure you want to exit?"): self.master.destroy() self.window_exception()
[docs] def window_exception(self): """ Exit immediately. """ messagebox.showerror( "Window closed.", "Window was closed unexpectedly. The program terminates now.") exit()
[docs]class ParserEditor: """ GUI for parsing directories and files for editor. """ def __init__(self): """ Initialize the window. """ # Window self.master = tk.Tk() self.master.title("Open previous experiment") self.master.protocol("WM_DELETE_WINDOW", self.close_window) self.master.lift() self.master.focus_force() # Variables self.track_video_name = tk.StringVar() self.video_name = tk.StringVar() self.track_name = tk.StringVar() self.destination_dir = tk.StringVar() self.file_name = tk.StringVar() # Input fields tk.Label( self.master, text="Video track file:" ).grid(row=0, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.track_video_name, width=40 ).grid(row=0, column=1, padx=10, pady=5) tk.Button( self.master, text="Browse...", command=self.select_track_video ).grid(row=0, column=2, padx=10, pady=5) tk.Label( self.master, text="Or" ).grid(row=1, column=0, columnspan=3, padx=10, pady=10) tk.Label( self.master, text="Video file:" ).grid(row=2, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.video_name, width=40 ).grid(row=2, column=1, padx=10, pady=5) tk.Button( self.master, text="Browse...", command=self.select_video ).grid(row=2, column=2, padx=10, pady=5) tk.Label( self.master, text="Track file:" ).grid(row=3, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.track_name, width=40 ).grid(row=3, column=1, padx=10, pady=5) tk.Button( self.master, text="Browse...", command=self.select_track ).grid(row=3, column=2, padx=10, pady=5) tk.Label( self.master, text="Save in:" ).grid(row=4, column=0, padx=10, pady=5, sticky='e') tk.Entry( self.master, textvariable=self.destination_dir, width=40 ).grid(row=4, column=1, padx=10, pady=5) tk.Button( self.master, text="Browse...", command=self.select_saving ).grid(row=4, column=2, padx=10, pady=5) tk.Label( self.master, text="Save as:" ).grid(row=5, column=0, padx=10, pady=5, sticky='e') ttk.Entry( self.master, textvariable=self.file_name, width=40 ).grid(row=5, column=1, padx=10, pady=5) # Progress buttons frame = tk.Frame(self.master) frame.grid( row=6, column=0, columnspan=3, sticky='nsew', padx=10, pady=5) frame.grid_columnconfigure(0, weight=1) frame.grid_columnconfigure(1, weight=1) self.confirm = tk.Button(frame, text="Ok", command=self.parse) reset = tk.Button(frame, text="Reset", command=self.reset_inputs) self.confirm.grid(row=0, column=0, padx=5, pady=5, sticky='ew') reset.grid(row=0, column=1, padx=5, pady=5, sticky='ew') # Return key bind self.master.bind('<Return>', self.invoke_confirm) # Start self.master.mainloop()
[docs] def select_track_video(self): """ Select track video file. """ path = filedialog.askopenfilename() if path: name, ext = os.path.split(path)[-1].split('.') if ext == 'tvf': self.track_video_name.set(path) self.file_name.set(name) self.video_name.set('') self.track_name.set('') else: messagebox.showerror( "Error", "Selected file needs to be .tvf file.")
[docs] def select_video(self): """ Select video file. """ path = filedialog.askopenfilename() if path: name, ext = os.path.split(path)[-1].split('.') if ext == 'avi': self.video_name.set(path) self.file_name.set(name) self.track_video_name.set('') else: messagebox.showerror( "Error", "Selected file needs to be .avi file.")
[docs] def select_track(self): """ Select track data. """ path = filedialog.askopenfilename() if path: name, ext = os.path.split(path)[-1].split('.') if ext == 'csv': self.track_name.set(path) self.file_name.set(name) self.track_video_name.set('') else: messagebox.showerror( "Error", "Selected file needs to be .csv file.")
[docs] def select_saving(self): """ Select directory for saving. """ dir_ = filedialog.askdirectory() if dir_: self.destination_dir.set(dir_)
[docs] def invoke_confirm(self, event): """ Invoke the Ok button with Return to progress. """ self.confirm.invoke()
[docs] def parse(self): """ Parse and check inputs and close window if no error. """ if (not os.path.isfile(self.track_video_name.get()) and not os.path.isfile(self.video_name.get()) and not os.path.isfile(self.track_name.get())): messagebox.showerror("Error", "No files selected!") return if os.path.isfile(self.track_video_name.get()): pass elif not os.path.isfile(self.video_name.get()): messagebox.showerror("Error", "Invalid video file selected!") return elif not os.path.isfile(self.track_name.get()): messagebox.showerror("Error", "Invalid track file selected!") return if not os.path.isdir(self.destination_dir.get()): messagebox.showerror("Error", "Invalid destination directory!") return try: _ = self.file_name.get() except: messagebox.showerror("Error", "File name is required!") return self.master.destroy()
[docs] def reset_inputs(self): """ Reset all input fields. """ self.track_video_name.set('') self.video_name.set('') self.track_name.set('') self.destination_dir.set('') self.file_name.set('')
[docs] def close_window(self): """ Confirm abrupt exit. """ if messagebox.askyesno( "Confirm Exit", "Are you sure you want to exit?"): self.master.destroy() self.window_exception()
[docs] def window_exception(self): """ Exit immediately. """ messagebox.showerror( "Window closed.", "Window was closed unexpectedly. The program terminates now.") exit()
[docs]def parse_segmentation(): """ Get the paths and directories for segmentation and additional information, None if parsing / step is skipped. Returns ------- tuple or None Parsed directories, paths and parameters, or None. """ p = ParserDirectory() if p.skip == False: source_dir = p.image_dir.get().replace('/', '\\') destination_dir = p.destination_dir.get().replace('/', '\\') states = p.model_states.get().replace('/', '\\') save_as_name = p.file_name.get() limit = p.frame_limit.get() only_seg = p.only_segmentation.get() return ( source_dir, destination_dir, states, save_as_name, limit, only_seg, True) else: p = ParserSkip() if p.skip == False: segmentation_name = p.segmentation_name.get().replace('/', '\\') video_name = p.video_name.get().replace('/', '\\') destination_dir = p.destination_dir.get().replace('/', '\\') save_as_name = p.file_name.get() limit = p.limit.get() return ( segmentation_name, video_name, destination_dir, save_as_name, limit, False) else: return None
[docs]def parse_tracker(): """ Get the tracking parameters. Returns ------- age : int Maximum frames an object may be undetected. offset : int The maximum distance in Euclidean tracking. split : int The maximum distance to consider splitting. gap : int The maximum distance for matching after detection gap. """ p = ParserTrack() age = p.age.get() offset = p.offset.get() split = p.split.get() gap = p.gap.get() return age, offset, split, gap
[docs]def parse_editor(): """ Get the file and saving information for the editor. Returns ------- tuple Paths to video, track data or combined as track video file, and save directory, and save name. """ p = ParserEditor() destination_dir = p.destination_dir.get().replace('/', '\\') save_as_name = p.file_name.get() if len(p.track_video_name.get()) > 0: track_video = p.track_video_name.get().replace('/', '\\') return track_video, destination_dir, save_as_name else: video = p.video_name.get().replace('/', '\\') track = p.track_name.get().replace('/', '\\') return video, track, destination_dir, save_as_name