diff --git "a/rope/GUI.py" "b/rope/GUI.py" new file mode 100644--- /dev/null +++ "b/rope/GUI.py" @@ -0,0 +1,2338 @@ +import os +import cv2 +import tkinter as tk +from tkinter import filedialog, font +import numpy as np +from PIL import Image, ImageTk +import json +import time +import copy +import bisect +import torch +import torchvision +import customtkinter as ctk + +torchvision.disable_beta_transforms_warning() +import mimetypes +import webbrowser +from random import random + + +import rope.GUIElements as GE +import rope.Styles as style + +from skimage import transform as trans +from torchvision.transforms import v2 + +import inspect #print(inspect.currentframe().f_back.f_code.co_name, 'resize_image') + + +class GUI(tk.Tk): + def __init__(self, models): + super().__init__() + + self.models = models + self.title('Rope-Pearl-00') + self.target_media = [] + self.target_video_file = [] + self.action_q = [] + self.video_image = [] + self.video_loaded = False + self.image_loaded = False + self.image_file_name = [] + self.stop_marker = [] + self.stop_image = [] + self.stop_marker_icon = [] + self.window_last_change = [] + self.blank = tk.PhotoImage() + self.output_folder = [] + self.output_videos_text = [] + self.target_media_buttons = [] + self.input_videos_button = [] + self.input_videos_text = [] + self.target_media_canvas = [] + self.source_faces_buttons = [] + self.input_videos_button = [] + self.input_faces_text = [] + self.shift_i_len = 0 + self.source_faces_canvas = [] + self.video = [] + self.video_slider = [] + self.found_faces_canvas = [] + self.merged_embedding_name = [] + self.merged_embeddings_text = [] + self.me_name = [] + self.merged_faces_canvas = [] + self.parameters = {} + self.control = {} + self.widget = {} + self.static_widget = {} + self.layer = {} + + self.temp_emb = [] + + self.arcface_dst = np.array([[38.2946, 51.6963], [73.5318, 51.5014], [56.0252, 71.7366], [41.5493, 92.3655], [70.7299, 92.2041]], dtype=np.float32) + + + self.json_dict = { + "source videos": None, + "source faces": None, + "saved videos": None, + 'dock_win_geom': [1400, 800, self.winfo_screenwidth()/2-400, self.winfo_screenheight()/2-510], + } + + self.marker = { + 'frame': '0', + 'parameters': '', + 'icon_ref': '', + } + self.markers = [] + + self.target_face = { + "TKButton": [], + "ButtonState": "off", + "Image": [], + "Embedding": [], + "SourceFaceAssignments": [], + "EmbeddingNumber": 0, #used for adding additional found faces + 'AssignedEmbedding': [], #the currently assigned source embedding, including averaged ones + } + self.target_faces = [] + + self.source_face = { + "TKButton": [], + "ButtonState": "off", + "Image": [], + "Embedding": [] + } + self.source_faces = [] + + #region [#111111b4] + + script_dir = os.path.dirname(__file__) + icon_path = os.path.join(script_dir, 'media', 'rope.ico') + + #endregion + + #region [#131710b4] + + # Keyboard Shortcuts + self.widget = {} + + def load_shortcuts_from_json(): + try: + with open("shortcuts.json", "r") as json_file: + return json.load(json_file) + except FileNotFoundError: + return { + "Timeline Beginning": "z", + "Nudge Left 30 Frames": "a", + "Nudge Right 30 Frames": "d", + "Record": "r", + "Play": "space", + "Save Image": "ctrl+s", + "Add Marker": "f", + "Delete Marker": "alt+f", + "Previous Marker": "q", + "Next Marker": "w", + "Toggle Restorer": "1", + "Toggle Orientation": "2", + "Toggle Strength": "3", + "Toggle Differencing": "4", + "Toggle Occluder": "5", + "Toggle Face Parser": "6", + "Toggle Text-Based Masking": "7", + "Toggle Color Adjustments": "8", + "Toggle Face Adjustments": "9", + "Clear VRAM": "F1", + "Swap Faces": "s", + "Nudge Left 1 Frame": "c", + "Nudge Right 1 Frame": "v", + "Show Mask": "x", + } + shortcuts = load_shortcuts_from_json() + + # Update text variables with loaded shortcuts + text_vars = {} + for shortcut_name, default_value in shortcuts.items(): + text_vars[shortcut_name] = tk.StringVar(value=default_value) + + # Update self.key_actions with loaded shortcuts + self.key_actions = { + shortcuts["Timeline Beginning"]: lambda: self.preview_control('q'), + shortcuts["Nudge Left 30 Frames"]: lambda: self.preview_control('a'), + shortcuts["Record"]: lambda: self.toggle_rec_video(), + shortcuts["Play"]: lambda: self.toggle_play_video(), + shortcuts["Nudge Right 30 Frames"]: lambda: self.preview_control('d'), + shortcuts["Save Image"]: lambda: self.save_image(), + shortcuts["Add Marker"]: lambda: self.update_marker('add'), + shortcuts["Delete Marker"]: lambda: self.update_marker('delete'), + shortcuts["Previous Marker"]: lambda: self.update_marker('prev'), + shortcuts["Next Marker"]: lambda: self.update_marker('next'), + shortcuts["Toggle Restorer"]: lambda: self.toggle_and_update('Restorer', 'Restorer'), + shortcuts["Toggle Orientation"]: lambda: self.toggle_and_update('Orient', 'Orientation'), + shortcuts["Toggle Strength"]: lambda: self.toggle_and_update('Strength', 'Strength'), + shortcuts["Toggle Differencing"]: lambda: self.toggle_and_update('Diff', 'Differencing'), + shortcuts["Toggle Occluder"]: lambda: self.toggle_and_update('Occluder', 'Occluder'), + shortcuts["Toggle Face Parser"]: lambda: self.toggle_and_update('FaceParser', 'Face Parser'), + shortcuts["Toggle Text-Based Masking"]: lambda: self.toggle_and_update('CLIP', 'Text-Based Masking'), + shortcuts["Toggle Color Adjustments"]: lambda: self.toggle_and_update('Color', 'Color Adjustments'), + shortcuts["Toggle Face Adjustments"]: lambda: self.toggle_and_update('FaceAdj', 'Input Face Adjustments'), + shortcuts["Clear VRAM"]: lambda: self.clear_mem(), + shortcuts["Swap Faces"]: lambda: self.toggle_swapper(), + shortcuts["Nudge Left 1 Frame"]: lambda:self.back_one_frame(), + shortcuts["Nudge Right 1 Frame"]: lambda: self.forward_one_frame(), + shortcuts["Show Mask"]: lambda: self.toggle_maskview(), + } + self.bind('', self.handle_key_press) + self.bind("", lambda event: self.focus_set()) + + def handle_key_press(self, event): + if isinstance(self.focus_get(), tk.Entry): + return + f_keys = ['F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12'] + modifiers = [mod for mod, mask in [('shift', 0x0001), ('ctrl', 0x0004), ('alt', 0x20000)] if event.state & mask] + key_combination = event.keysym if event.keysym in f_keys else '+'.join(filter(None, ['+'.join(modifiers), event.keysym.lower()])) + action = self.key_actions.get(key_combination) + action and action() + + def toggle_and_update(self, switch_name, parameter_name): + self.widget[f"{switch_name}Switch"].set(not self.widget[f"{switch_name}Switch"].get()) + + + #endregion + + + # self.bind("", lambda event: self.focus_set()) + + +##### + def create_gui(self): + + #region [#111111b4] + + # v_f_frame == self.layer['InputVideoFrame'] + + self.configure(bg=style.bg) + ctk.set_appearance_mode("dark") + + global tmp + tmp = ctk.CTkFrame(self, border_width=0, fg_color=style.main, bg_color=style.bg) + tmp.grid(row=1, column=0, sticky='NEWS', padx=0, pady=0) + tmp.grid_forget() + + #endregion + + + #region [#111111b4] + + def vidupdate(): + self.resize_image() + + #Hide/Unhide Inputs Panel + def input_panel_checkbox(): + current_state = self.checkbox.get() + if current_state: + self.layer['InputVideoFrame'].grid(row=0, column=0, sticky='NEWS', padx=0, pady=(0,0)) + ks_frame.grid_forget() + else: + self.layer['InputVideoFrame'].grid_forget() + v_f_frame.grid_forget() + self.after(10, vidupdate) + + #Hide/Unhide Faces Panel + def collapse_faces_panel(): + current_state = self.collapse_bottom.get() + if current_state: + ff_frame.grid(row=5, column=0, sticky='NEWS', padx=0, pady=(1,0)) + mf_frame.grid(row=6, column=0, sticky='NEWS', padx=0, pady=1) + self.after(10, vidupdate) + else: + ff_frame.grid_forget() + mf_frame.grid_forget() + self.after(10, vidupdate) + + #Hide/Unhide Parameters Panel + def collapse_params_panel(): + current_state = self.collapse_params.get() + if current_state: + + self.layer['parameter_frame'].grid(row=0, column=2, sticky='NEWS', pady=0, padx=0) + self.after(10, vidupdate) + else: + self.layer['parameter_frame'].grid_forget() + self.after(10, vidupdate) + + #Keyboard Shortcuts + def keyboard_shortcuts(): + current_state = self.collapse_keyboardshortcuts.get() + if current_state: + ks_frame.grid(row=0, column=0, sticky='NEWS', padx=0, pady=(0,0)) + self.after(10, vidupdate) + self.layer['InputVideoFrame'].grid_forget() + self.after(10, vidupdate) + self.checkbox.deselect() + else: + ks_frame.grid_forget() + v_f_frame.grid_forget() + self.after(10, vidupdate) + self.layer['InputVideoFrame'].grid(row=0, column=0, sticky='NEWS', padx=0, pady=(0,0)) + self.after(10, vidupdate) + self.checkbox.select() + + #endregion + + + # 1 x 3 Top level grid + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=0) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=0) + + self.configure(style.frame_style_bg) + + # Top Frame + top_frame = tk.Frame(self, style.canvas_frame_label_1) + top_frame.grid(row=0, column=0, sticky='NEWS', padx=1, pady=1) + top_frame.grid_columnconfigure(0, weight=1) + top_frame.grid_columnconfigure(1, weight=0) + + # Middle Frame + middle_frame = tk.Frame( self, style.frame_style_bg) + middle_frame.grid(row=1, column=0, sticky='NEWS', padx=0, pady=0) + middle_frame.grid_rowconfigure(0, weight=1) + # Videos and Faces + middle_frame.grid_columnconfigure(0, weight=0) + # Preview + middle_frame.grid_columnconfigure(1, weight=1) + # Parameters + middle_frame.grid_columnconfigure(2, weight=0) + # Scrollbar + middle_frame.grid_columnconfigure(3, weight=0) + + #region [#131710b4] + + global v_f_frame + v_f_frame = ctk.CTkFrame(middle_frame, height = 42, border_width=0, fg_color=style.main) + v_f_frame.grid(row=0, column=0, sticky='NEWS', padx=0, pady=(0,0)) + + + y=0 + x=10 + global ks_frame + ks_frame = ctk.CTkFrame(middle_frame, height = 42, width=250, border_width=0, fg_color=style.main, background_corner_colors=(style.main,style.main,style.main,style.main)) + ks_frame.grid(row=0, column=0, sticky='NEWS', padx=0, pady=(0,0)) + ks_frame.grid_forget() + + + def load_shortcuts_from_json(): + try: + with open("shortcuts.json", "r") as json_file: + return json.load(json_file) + except FileNotFoundError: + return { + "Timeline Beginning": "z", + "Nudge Left 30 Frames": "a", + "Nudge Right 30 Frames": "d", + "Record": "r", + "Play": "space", + "Save Image": "ctrl+s", + "Add Marker": "f", + "Delete Marker": "alt+f", + "Previous Marker": "q", + "Next Marker": "w", + "Toggle Restorer": "1", + "Toggle Orientation": "2", + "Toggle Strength": "3", + "Toggle Differencing": "4", + "Toggle Occluder": "5", + "Toggle Face Parser": "6", + "Toggle Text-Based Masking": "7", + "Toggle Color Adjustments": "8", + "Toggle Face Adjustments": "9", + "Clear VRAM": "F1", + "Swap Faces": "s", + "Nudge Left 1 Frame": "c", + "Nudge Right 1 Frame": "v", + "Show Mask": "x", + } + shortcuts = load_shortcuts_from_json() + + def save_shortcuts_to_json(shortcuts): + with open("shortcuts.json", "w") as json_file: + json.dump(shortcuts, json_file) + + def update_key_actions(): + self.key_actions = { + shortcuts["Timeline Beginning"]: lambda: self.preview_control('q'), + shortcuts["Nudge Left 30 Frames"]: lambda: self.preview_control('a'), + shortcuts["Record"]: lambda: self.toggle_rec_video(), + shortcuts["Play"]: lambda: self.toggle_play_video(), + shortcuts["Nudge Right 30 Frames"]: lambda: self.preview_control('d'), + shortcuts["Save Image"]: lambda: self.save_image(), + shortcuts["Add Marker"]: lambda: self.update_marker('add'), + shortcuts["Delete Marker"]: lambda: self.update_marker('delete'), + shortcuts["Previous Marker"]: lambda: self.update_marker('prev'), + shortcuts["Next Marker"]: lambda: self.update_marker('next'), + shortcuts["Toggle Restorer"]: lambda: self.toggle_and_update('Restorer', 'Restorer'), + shortcuts["Toggle Orientation"]: lambda: self.toggle_and_update('Orient', 'Orientation'), + shortcuts["Toggle Strength"]: lambda: self.toggle_and_update('Strength', 'Strength'), + shortcuts["Toggle Differencing"]: lambda: self.toggle_and_update('Diff', 'Differencing'), + shortcuts["Toggle Occluder"]: lambda: self.toggle_and_update('Occluder', 'Occluder'), + shortcuts["Toggle Face Parser"]: lambda: self.toggle_and_update('FaceParser', 'Face Parser'), + shortcuts["Toggle Text-Based Masking"]: lambda: self.toggle_and_update('CLIP', 'Text-Based Masking'), + shortcuts["Toggle Color Adjustments"]: lambda: self.toggle_and_update('Color', 'Color Adjustments'), + shortcuts["Toggle Face Adjustments"]: lambda: self.toggle_and_update('FaceAdj', 'Input Face Adjustments'), + shortcuts["Clear VRAM"]: lambda: self.clear_mem(), + shortcuts["Swap Faces"]: lambda: self.toggle_swapper(), + shortcuts["Nudge Left 1 Frame"]: lambda:self.back_one_frame(), + shortcuts["Nudge Right 1 Frame"]: lambda: self.forward_one_frame(), + shortcuts["Show Mask"]: lambda: self.toggle_maskview(), + } + + # Load shortcuts from JSON + shortcuts = load_shortcuts_from_json() + + # Update text variables with loaded shortcuts + text_vars = {} + for shortcut_name, default_value in shortcuts.items(): + text_vars[shortcut_name] = tk.StringVar(value=default_value) + + # Create save_shortcuts function with parameters + def save_shortcuts(): + # Update the text variables with the current values from the entry widgets + for shortcut_name, text_var in text_vars.items(): + shortcuts[shortcut_name] = text_var.get() + + # Save the current shortcuts to JSON + save_shortcuts_to_json(shortcuts) + update_key_actions() + + # Create save button with lambda function + save_ks_button = ctk.CTkButton(ks_frame, text="Save Shortcuts", command=save_shortcuts, width=150, height=15, corner_radius=3, fg_color=style.main2, hover_color=style.main3) + save_ks_button.place(x=40, y=20) + + # Create labels and entry widgets for each shortcut + y = 60 + x = 10 + for shortcut_name, default_value in shortcuts.items(): + ctk.CTkLabel(ks_frame, text=shortcut_name).place(x=x, y=y) + ctk.CTkEntry(ks_frame, textvariable=text_vars[shortcut_name], width=50, height=15, border_width=0).place(x=180, y=y) + y += 20 + + #endregion + + # Bottom Frame + bottom_frame = tk.Frame( self, style.canvas_frame_label_1) + bottom_frame.grid(row=2, column=0, sticky='NEWS', padx=1, pady=1) + bottom_frame.grid_columnconfigure(0, minsize=100) + bottom_frame.grid_columnconfigure(1, weight=1) + bottom_frame.grid_columnconfigure(2, minsize=100) + +####### Top Frame + # Left + # Label + self.layer['topleft'] = tk.Frame(top_frame, style.canvas_frame_label_1, height = 42) + self.layer['topleft'].grid(row=0, column=0, sticky='NEWS', pady=0) + + # Buttons + self.widget['StartButton'] = GE.Button(self.layer['topleft'], 'StartRope', 1, self.load_all, None, 'control', 10, 9, width=200) + self.widget['OutputFolderButton'] = GE.Button(self.layer['topleft'], 'OutputFolder', 1, self.select_save_video_path, None, 'control', x=240, y=1, width=190) + self.output_videos_text = GE.Text(self.layer['topleft'], '', 1, 240, 20, 190, 20) + + # Right + self.layer['topright'] = tk.Frame(top_frame, style.canvas_frame_label_1, height=42, width=413) + self.layer['topright'].grid(row=0, column=1, sticky='NEWS', pady=0) + self.control['ClearVramButton'] = GE.Button(self.layer['topright'], 'ClearVramButton', 1, self.clear_mem, None, 'control', x=5, y=9, width=85, height=20) + self.static_widget['vram_indicator'] = GE.VRAM_Indicator(self.layer['topright'], 1, 300, 20, 100, 11) + + #region [#111111b4] + + ##Button - Hide/Unhide Faces Panel + self.checkbox = ctk.CTkCheckBox(self.layer['topleft'], text="Input Panel", text_color='#B0B0B0', command=input_panel_checkbox, onvalue=True, offvalue=False, checkbox_width=18, checkbox_height=18, border_width=0, hover_color='#303030', fg_color=style.main) + self.checkbox.place(x=500, y=10) + self.checkbox.select() + #Button - Hide/Unhide Inputs Panel + self.collapse_bottom = ctk.CTkCheckBox(self.layer['topleft'], text="Faces Panel",text_color='#B0B0B0', command=collapse_faces_panel, onvalue=True, offvalue=False, checkbox_width=18,checkbox_height=18,border_width=0,hover_color='#303030',fg_color=style.main) + self.collapse_bottom.place(x=600, y=10) + self.collapse_bottom.select() + #Button - Hide/Unhide Params Panel + self.collapse_params = ctk.CTkCheckBox(self.layer['topleft'], text="Parameters Panel",text_color='#B0B0B0', command=collapse_params_panel, onvalue=True, offvalue=False, checkbox_width=18,checkbox_height=18,border_width=0,hover_color='#303030',fg_color=style.main) + self.collapse_params.place(x=705, y=10) + self.collapse_params.select() + self.collapse_keyboardshortcuts = ctk.CTkCheckBox(self.layer['topleft'], text="Keyboard Shortcuts",text_color='#B0B0B0', command=keyboard_shortcuts, onvalue=True, offvalue=False, checkbox_width=18,checkbox_height=18,border_width=0,hover_color='#303030',fg_color=style.main) + self.collapse_keyboardshortcuts.place(x=840, y=10) + #endregion + +####### Middle Frame + + ### Videos and Faces + self.layer['InputVideoFrame'] = tk.Frame(middle_frame, style.canvas_frame_label_3) + self.layer['InputVideoFrame'].grid(row=0, column=0, sticky='NEWS', padx=1, pady=0) + # Buttons + self.layer['InputVideoFrame'].grid_rowconfigure(0, weight=0) + # Input Media Canvas + self.layer['InputVideoFrame'].grid_rowconfigure(1, weight=1) + + # Input Videos + self.layer['InputVideoFrame'].grid_columnconfigure(0, weight=0) + # Scrollbar + self.layer['InputVideoFrame'].grid_columnconfigure(1, weight=0) + # Input Faces Canvas + self.layer['InputVideoFrame'].grid_columnconfigure(0, weight=0) + # Scrollbar + self.layer['InputVideoFrame'].grid_columnconfigure(1, weight=0) + + # Input Videos + # Button Frame + frame = tk.Frame(self.layer['InputVideoFrame'], style.canvas_frame_label_2, height = 42) + frame.grid(row=0, column=0, columnspan = 2, sticky='NEWS', padx=0, pady=0) + + # Buttons + self.widget['VideoFolderButton'] = GE.Button(frame, 'LoadTVideos', 2, self.select_video_path, None, 'control', 10, 1, width=195) + self.input_videos_text = GE.Text(frame, '', 2, 10, 20, 190, 20) + + # Input Videos Canvas + self.target_media_canvas = tk.Canvas(self.layer['InputVideoFrame'], style.canvas_frame_label_3, height=100, width=195) + self.target_media_canvas.grid(row=1, column=0, sticky='NEWS', padx=10, pady=10) + self.target_media_canvas.bind("", self.target_videos_mouse_wheel) + self.target_media_canvas.create_text(8, 20, anchor='w', fill='grey25', font=("Arial italic", 20), text=" Input Videos") + + # Scroll Canvas + scroll_canvas = tk.Canvas(self.layer['InputVideoFrame'], style.canvas_frame_label_3, bd=0, ) + scroll_canvas.grid(row=1, column=1, sticky='NEWS', padx=0, pady=0) + scroll_canvas.grid_rowconfigure(0, weight=1) + scroll_canvas.grid_columnconfigure(0, weight=1) + + self.static_widget['input_videos_scrollbar'] = GE.Scrollbar_y(scroll_canvas, self.target_media_canvas) + + # Input Faces + # Button Frame + frame = tk.Frame(self.layer['InputVideoFrame'], style.canvas_frame_label_2, height = 42) + frame.grid(row=0, column=2, columnspan = 2, sticky='NEWS', padx=0, pady=0) + + # Buttons + self.widget['FacesFolderButton'] = GE.Button(frame, 'LoadSFaces', 2, self.select_faces_path, None, 'control', 10, 1, width=195) + self.input_faces_text = GE.Text(frame, '', 2, 10, 20, 190, 20) + + # Scroll Canvas + self.source_faces_canvas = tk.Canvas(self.layer['InputVideoFrame'], style.canvas_frame_label_3, height = 100, width=195) + self.source_faces_canvas.grid(row=1, column=2, sticky='NEWS', padx=10, pady=10) + self.source_faces_canvas.bind("", self.source_faces_mouse_wheel) + self.source_faces_canvas.create_text(8, 20, anchor='w', fill='grey25', font=("Arial italic", 20), text=" Input Faces") + + scroll_canvas = tk.Canvas(self.layer['InputVideoFrame'], style.canvas_frame_label_3, bd=0, ) + scroll_canvas.grid(row=1, column=3, sticky='NEWS', padx=0, pady=0) + scroll_canvas.grid_rowconfigure(0, weight=1) + scroll_canvas.grid_columnconfigure(0, weight=1) + + self.static_widget['input_faces_scrollbar'] = GE.Scrollbar_y(scroll_canvas, self.source_faces_canvas) + # GE.Separator_y(scroll_canvas, 14, 0) + GE.Separator_y(self.layer['InputVideoFrame'], 229, 0) + GE.Separator_x(self.layer['InputVideoFrame'], 0, 41) + + ### Preview + self.layer['preview_column'] = tk.Frame(middle_frame, style.canvas_bg) + self.layer['preview_column'].grid(row=0, column=1, sticky='NEWS', pady=0) + self.layer['preview_column'].grid_columnconfigure(0, weight=1) + # Preview Data + self.layer['preview_column'].grid_rowconfigure(0, weight=0) + # Preview Window + self.layer['preview_column'].grid_rowconfigure(1, weight=1) + # Timeline + self.layer['preview_column'].grid_rowconfigure(2, weight=0) + # MArkers + self.layer['preview_column'].grid_rowconfigure(3, weight=0) + # Controls + self.layer['preview_column'].grid_rowconfigure(4, weight=0) + # Found Faces + self.layer['preview_column'].grid_rowconfigure(5, weight=0) + # Merged Faces + self.layer['preview_column'].grid_rowconfigure(6, weight=0) + + # Preview Data + preview_data = tk.Frame(self.layer['preview_column'], style.canvas_frame_label_2, height = 24) + preview_data.grid(row=0, column=0, sticky='NEWS', pady=0) + preview_data.grid_columnconfigure(0, weight=1) + preview_data.grid_columnconfigure(1, weight=1) + preview_data.grid_columnconfigure(2, weight=1) + # preview_data.grid_columnconfigure(3, weight=1) + preview_data.grid_rowconfigure(0, weight=0) + + + + frame = tk.Frame(preview_data, style.canvas_frame_label_2, height = 24, width=100) + frame.grid(row=0, column=0) + self.widget['AudioButton'] = GE.Button(frame, 'Audio', 2, self.toggle_audio, None, 'control', x=0, y=0, width=100) + + frame = tk.Frame(preview_data, style.canvas_frame_label_2, height = 24, width=100) + frame.grid(row=0, column=1) + self.widget['MaskViewButton'] = GE.Button(frame, 'MaskView', 2, self.toggle_maskview, None, 'control', x=0, y=0, width=100) + + frame = tk.Frame(preview_data, style.canvas_frame_label_2, height = 24, width=200) + frame.grid(row=0, column=2) + self.widget['PreviewModeTextSel'] = GE.TextSelection(frame, 'PreviewModeTextSel', '', 2, self.set_view, True, 'control', width=200, height=20, x=0, y=0, text_percent=1) + + + # Preview Window + self.video = tk.Label(self.layer['preview_column'], bg='black') + self.video.grid(row=1, column=0, sticky='NEWS', padx=0, pady=0) + self.video.bind("", self.iterate_through_merged_embeddings) + self.video.bind("", lambda event: self.toggle_play_video()) + + # Videos + # Timeline + # Slider + self.layer['slider_frame'] = tk.Frame(self.layer['preview_column'], style.canvas_frame_label_2, height=20) + self.layer['slider_frame'].grid(row=2, column=0, sticky='NEWS', pady=0) + self.video_slider = GE.Timeline(self.layer['slider_frame'], self.widget, self.temp_toggle_swapper, self.add_action) + + # Markers + self.layer['markers_canvas'] = tk.Canvas(self.layer['preview_column'], style.canvas_frame_label_2, height = 20) + self.layer['markers_canvas'].grid(row=3, column=0, sticky='NEWS') + self.layer['markers_canvas'].bind('', lambda e:self.update_marker(e.width)) + + # self.create_ui_button('ToggleStop', marker_frame, 140, 2, width=36, height=36) + + # Controls + self.layer['preview_frame'] = tk.Frame(self.layer['preview_column'], style.canvas_bg, height = 40) + self.layer['preview_frame'].grid(row=4, column=0, sticky='NEWS') + self.layer['preview_frame'].grid_columnconfigure(0, weight=0) + self.layer['preview_frame'].grid_columnconfigure(1, weight=1) + self.layer['preview_frame'].grid_columnconfigure(2, weight=0) + self.layer['preview_frame'].grid_rowconfigure(0, weight=0) + self.layer['preview_frame'].grid_rowconfigure(1, weight=0) + + # Left Side + self.layer['play_controls_left'] = tk.Frame(self.layer['preview_frame'], style.canvas_frame_label_2, height=30, width=100 ) + self.layer['play_controls_left'].grid(row=0, column=0, sticky='NEWS', pady=0) + self.widget['SaveImageButton'] = GE.Button(self.layer['play_controls_left'], 'SaveImageButton', 2, self.save_image, None, 'control', x=10, y=5, width=100) + + # Center + cente_frame = tk.Frame(self.layer['preview_frame'], style.canvas_frame_label_2, height=30, ) + cente_frame.grid(row=0, column=1, sticky='NEWS', pady=0) + cente_frame.grid_columnconfigure(0, weight=0) + cente_frame.grid_rowconfigure(0, weight=0) + + play_control_frame = tk.Frame(cente_frame, style.canvas_frame_label_2, height=30, width=270 ) + play_control_frame.place(anchor="c", relx=.5, rely=.5) + + column = 0 + col_delta = 50 + self.widget['TLBegButton'] = GE.Button(play_control_frame, 'TLBeginning', 2, self.preview_control, 'q', 'control', x=column , y=2, width=20) + column += col_delta + self.widget['TLLeftButton'] = GE.Button(play_control_frame, 'TLLeft', 2, self.preview_control, 'a', 'control', x=column , y=2, width=20) + column += col_delta + self.widget['TLRecButton'] = GE.Button(play_control_frame, 'Record', 2, self.toggle_rec_video, None, 'control', x=column , y=2, width=20) + column += col_delta + self.widget['TLPlayButton'] = GE.Button(play_control_frame, 'Play', 2, self.toggle_play_video, None, 'control', x=column , y=2, width=20) + column += col_delta + self.widget['TLRightButton'] = GE.Button(play_control_frame, 'TLRight', 2, self.preview_control, 'd', 'control', x=column , y=2, width=20) + + # Right Side + right_playframe = tk.Frame(self.layer['preview_frame'], style.canvas_frame_label_2, height=30, width=120) + right_playframe.grid(row=0, column=2, sticky='NEWS', pady=0) + self.widget['AddMarkerButton'] = GE.Button(right_playframe, 'AddMarkerButton', 2, self.update_marker, 'add', 'control', x=0, y=5, width=20) + self.widget['DelMarkerButton'] = GE.Button(right_playframe, 'DelMarkerButton', 2, self.update_marker, 'delete', 'control', x=25, y=5, width=20) + self.widget['PrevMarkerButton'] = GE.Button(right_playframe, 'PrevMarkerButton', 2, self.update_marker, 'prev', 'control', x=50, y=5, width=20) + self.widget['NextMarkerButton'] = GE.Button(right_playframe, 'NextMarkerButton', 2, self.update_marker, 'next', 'control', x=75, y=5, width=20) + # self.widget['StopMarkerButton'] = GE.Button(right_playframe, 'StopMarkerButton', 2, self.update_marker, 'stop', 'control', x=100, y=5, width=20) + self.widget['SaveMarkerButton'] = GE.Button(right_playframe, 'SaveMarkerButton', 2, self.save_markers_json, None, 'control', x=95, y=5, width=20) + + # Images + self.layer['image_controls'] = tk.Frame(self.layer['preview_column'], style.canvas_frame_label_2, height=80) + self.layer['image_controls'].grid(row=2, column=0, rowspan=2, sticky='NEWS', pady=0) + self.widget['SaveImageButton'] = GE.Button(self.layer['image_controls'], 'SaveImageButton', 2, self.save_image, None, 'control', x=10, y=5, width=100) + self.widget['AutoSwapButton'] = GE.Button(self.layer['image_controls'], 'AutoSwapButton', 2, self.toggle_auto_swap, None, 'control', x=150, y=5, width=100) + + + self.layer['image_controls'].grid_forget() + + # FaceLab + self.layer['FaceLab_controls'] = tk.Frame(self.layer['preview_column'], style.canvas_frame_label_2, height=80) + self.layer['FaceLab_controls'].grid(row=2, column=0, rowspan=2, sticky='NEWS', pady=0) + + + + self.layer['FaceLab_controls'].grid_forget() + + + # Found Faces + ff_frame = tk.Frame(self.layer['preview_column'], style.canvas_frame_label_1) + ff_frame.grid(row=5, column=0, sticky='NEWS', pady=1) + ff_frame.grid_columnconfigure(0, weight=0) + ff_frame.grid_columnconfigure(1, weight=1) + ff_frame.grid_rowconfigure(0, weight=0) + + # Buttons + button_frame = tk.Frame(ff_frame, style.canvas_frame_label_2, height = 100, width = 112) + button_frame.grid( row = 0, column = 0, ) + + self.widget['FindFacesButton'] = GE.Button(button_frame, 'FindFaces', 2, self.find_faces, None, 'control', x=0, y=0, width=112, height=33) + self.widget['ClearFacesButton'] = GE.Button(button_frame, 'ClearFaces', 2, self.clear_faces, None, 'control', x=0, y=33, width=112, height=33) + self.widget['SwapFacesButton'] = GE.Button(button_frame, 'SwapFaces', 2, self.toggle_swapper, None, 'control', x=0, y=66, width=112, height=33) + + # Scroll Canvas + self.found_faces_canvas = tk.Canvas(ff_frame, style.canvas_frame_label_3, height = 100 ) + self.found_faces_canvas.grid( row = 0, column = 1, sticky='NEWS') + self.found_faces_canvas.bind("", self.target_faces_mouse_wheel) + self.found_faces_canvas.create_text(8, 45, anchor='w', fill='grey25', font=("Arial italic", 20), text=" Found Faces") + + self.static_widget['20'] = GE.Separator_y(ff_frame, 111, 0) + + + + # Merged Faces + mf_frame = tk.Frame(self.layer['preview_column'], style.canvas_frame_label_1) + mf_frame.grid(row=6, column=0, sticky='NEWS', pady=0) + mf_frame.grid_columnconfigure(0, minsize=10) + mf_frame.grid_columnconfigure(1, weight=1) + mf_frame.grid_rowconfigure(0, weight=0) + + # Buttons + button_frame = tk.Frame(mf_frame, style.canvas_frame_label_2, height = 100, width = 112) + button_frame.grid( row = 0, column = 0, ) + + self.widget['DelEmbedButton'] = GE.Button(button_frame, 'DelEmbed', 2, self.delete_merged_embedding, None, 'control', x=0, y=0, width=112, height=33) + + # Merged Embeddings Text + self.merged_embedding_name = tk.StringVar() + self.merged_embeddings_text = tk.Entry(button_frame, style.entry_2, textvariable=self.merged_embedding_name) + self.merged_embeddings_text.place(x=8, y=37, width = 96, height=20) + self.merged_embeddings_text.bind("", lambda event: self.save_selected_source_faces(self.merged_embedding_name)) + self.me_name = self.nametowidget(self.merged_embeddings_text) + + # Scroll Canvas + self.merged_faces_canvas = tk.Canvas(mf_frame, style.canvas_frame_label_3, height = 100) + self.merged_faces_canvas.grid( row = 0, column = 1, sticky='NEWS') + self.merged_faces_canvas.grid_rowconfigure(0, weight=1) + self.merged_faces_canvas.bind("", lambda event: self.merged_faces_canvas.xview_scroll(-int(event.delta/120.0), "units")) + self.merged_faces_canvas.create_text(8, 45, anchor='w', fill='grey25', font=("Arial italic", 20), text=" Merged Faces") + self.static_widget['21'] = GE.Separator_y(mf_frame, 111, 0) + + ### Parameters + width=398 + + self.layer['parameter_frame'] = tk.Frame(middle_frame, style.canvas_frame_label_3, bd=0, width=width) + self.layer['parameter_frame'].grid(row=0, column=2, sticky='NEWS', pady=0, padx=1) + + self.layer['parameter_frame'].grid_rowconfigure(0, weight=0) + self.layer['parameter_frame'].grid_rowconfigure(1, weight=1) + self.layer['parameter_frame'].grid_rowconfigure(2, weight=0) + self.layer['parameter_frame'].grid_columnconfigure(0, weight=0) + self.layer['parameter_frame'].grid_columnconfigure(1, weight=0) + + parameters_control_frame = tk.Frame(self.layer['parameter_frame'], style.canvas_frame_label_2, bd=0, width=width, height = 42) + parameters_control_frame.grid(row=0, column=0, columnspan=2, sticky='NEWS', pady=0, padx=0) + parameters_control_frame.grid_columnconfigure(0, weight=1) + parameters_control_frame.grid_columnconfigure(1, weight=1) + parameters_control_frame.grid_columnconfigure(2, weight=1) + parameters_control_frame.grid_rowconfigure(0, weight=0) + + + frame = tk.Frame(parameters_control_frame, style.canvas_frame_label_2, height = 42, width=100) + frame.grid(row=0, column=0) + self.widget['SaveParamsButton'] = GE.Button(frame, 'SaveParamsButton', 2, self.parameter_io, 'save', 'control', x=0 , y=8, width=100) + + frame = tk.Frame(parameters_control_frame, style.canvas_frame_label_2, height = 42, width=100) + frame.grid(row=0, column=1) + self.widget['LoadParamsButton'] = GE.Button(frame, 'LoadParamsButton', 2, self.parameter_io, 'load', 'control', x=0 , y=8, width=100) + + frame = tk.Frame(parameters_control_frame, style.canvas_frame_label_2, height = 42, width=100) + frame.grid(row=0, column=2) + self.widget['DefaultParamsButton'] = GE.Button(frame, 'DefaultParamsButton', 2, self.parameter_io, 'default', 'control', x=0 , y=8, width=100) + + + + self.layer['parameters_canvas'] = tk.Canvas(self.layer['parameter_frame'], style.canvas_frame_label_3, bd=0, width=width) + self.layer['parameters_canvas'].grid(row=1, column=0, sticky='NEWS', pady=0, padx=0) + + self.layer['parameters_frame'] = tk.Frame(self.layer['parameters_canvas'], style.canvas_frame_label_3, bd=0, width=width, height=1150) + self.layer['parameters_frame'].grid(row=0, column=0, sticky='NEWS', pady=0, padx=0) + + self.layer['parameters_canvas'].create_window(0, 0, window = self.layer['parameters_frame'], anchor='nw') + + self.layer['parameter_scroll_canvas'] = tk.Canvas(self.layer['parameter_frame'], style.canvas_frame_label_3, bd=0, ) + self.layer['parameter_scroll_canvas'].grid(row=1, column=1, sticky='NEWS', pady=0) + self.layer['parameter_scroll_canvas'].grid_rowconfigure(0, weight=1) + self.layer['parameter_scroll_canvas'].grid_columnconfigure(0, weight=1) + + self.static_widget['parameters_scrollbar'] = GE.Scrollbar_y(self.layer['parameter_scroll_canvas'], self.layer['parameters_canvas']) + + self.static_widget['30'] = GE.Separator_x(parameters_control_frame, 0, 41) + ### Layout ### + top_border_delta = 25 + bottom_border_delta = 5 + switch_delta = 25 + row_delta = 20 + row = 1 + column = 160 + + # Restore + self.widget['RestorerSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'RestorerSwitch', 'Restorer', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += switch_delta + self.widget['RestorerTypeTextSel'] = GE.TextSelection(self.layer['parameters_frame'], 'RestorerTypeTextSel', 'Restorer Type', 3, self.update_data, 'parameter', 'parameter', 398, 20, 1, row, 0.72) + row += row_delta + self.widget['RestorerDetTypeTextSel'] = GE.TextSelection(self.layer['parameters_frame'], 'RestorerDetTypeTextSel', 'Detection Alignment', 3, self.update_data, 'parameter', 'parameter', 398, 20, 1, row, 0.72) + row += row_delta + self.widget['RestorerSlider'] = GE.Slider2(self.layer['parameters_frame'], 'RestorerSlider', 'Blend', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.72) + row += top_border_delta + self.static_widget['9'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # Threshhold + self.widget['ThresholdSlider'] = GE.Slider2(self.layer['parameters_frame'], 'ThresholdSlider', 'Similarity Threshhold', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['3'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # Orientation + self.widget['OrientSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'OrientSwitch', 'Orientation', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += switch_delta + self.widget['OrientSlider'] = GE.Slider2(self.layer['parameters_frame'], 'OrientSlider', 'Angle', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['2'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # Strength + self.widget['StrengthSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'StrengthSwitch', 'Strength', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += switch_delta + self.widget['StrengthSlider'] = GE.Slider2(self.layer['parameters_frame'], 'StrengthSlider', 'Amount', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['5'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # Border + self.widget['BorderTopSlider'] = GE.Slider2(self.layer['parameters_frame'], 'BorderTopSlider', 'Top Border Distance', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['BorderSidesSlider'] = GE.Slider2(self.layer['parameters_frame'], 'BorderSidesSlider', 'Sides Border Distance', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['BorderBottomSlider'] = GE.Slider2(self.layer['parameters_frame'], 'BorderBottomSlider', 'Bottom Border Distance', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['BorderBlurSlider'] = GE.Slider2(self.layer['parameters_frame'], 'BorderBlurSlider', 'Border Blend', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['7'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # Diff + self.widget['DiffSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'DiffSwitch', 'Differencing', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += switch_delta + self.widget['DiffSlider'] = GE.Slider2(self.layer['parameters_frame'], 'DiffSlider', 'Amount', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['8'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # Occluder + self.widget['OccluderSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'OccluderSwitch', 'Occluder', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += switch_delta + self.widget['OccluderSlider'] = GE.Slider2(self.layer['parameters_frame'], 'OccluderSlider', 'Size', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['10'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # FaceParser - Face + self.widget['FaceParserSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'FaceParserSwitch', 'Face Parser', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += switch_delta + self.widget['FaceParserSlider'] = GE.Slider2(self.layer['parameters_frame'], 'FaceParserSlider', 'Background', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['MouthParserSlider'] = GE.Slider2(self.layer['parameters_frame'], 'MouthParserSlider', 'Mouth', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['12'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # CLIP + self.widget['CLIPSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'CLIPSwitch', 'Text-Based Masking', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += switch_delta + self.widget['CLIPTextEntry'] = GE.Text_Entry(self.layer['parameters_frame'], 'CLIPTextEntry', 'Text-Based Masking', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['CLIPSlider'] = GE.Slider2(self.layer['parameters_frame'], 'CLIPSlider', 'Amount', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['12'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # Blur + self.widget['BlendSlider'] = GE.Slider2(self.layer['parameters_frame'], 'BlendSlider', 'Overall Mask Blend', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['13'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # Color Adjustments + self.widget['ColorSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'ColorSwitch', 'Color Adjustments', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += switch_delta + self.widget['ColorRedSlider'] = GE.Slider2(self.layer['parameters_frame'], 'ColorRedSlider', 'Red', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['ColorGreenSlider'] = GE.Slider2(self.layer['parameters_frame'], 'ColorGreenSlider', 'Green', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['ColorBlueSlider'] = GE.Slider2(self.layer['parameters_frame'], 'ColorBlueSlider', 'Blue', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['ColorGammaSlider'] = GE.Slider2(self.layer['parameters_frame'], 'ColorGammaSlider', 'Gamma', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['6'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # KPS Adjustment and scaling + self.widget['FaceAdjSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'FaceAdjSwitch', 'Input Face Adjustments', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += switch_delta + self.widget['KPSXSlider'] = GE.Slider2(self.layer['parameters_frame'], 'KPSXSlider', 'KPS - X', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['KPSYSlider'] = GE.Slider2(self.layer['parameters_frame'], 'KPSYSlider', 'KPS - Y', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['KPSScaleSlider'] = GE.Slider2(self.layer['parameters_frame'], 'KPSScaleSlider', 'KPS - Scale', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['FaceScaleSlider'] = GE.Slider2(self.layer['parameters_frame'], 'FaceScaleSlider', 'Face Scale', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += top_border_delta + self.static_widget['4'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + + # Cats and Dogs + self.widget['ThreadsSlider'] = GE.Slider2(self.layer['parameters_frame'], 'ThreadsSlider', 'Threads', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + + row += row_delta + self.widget['DetectTypeTextSel'] = GE.TextSelection(self.layer['parameters_frame'], 'DetectTypeTextSel', 'Detection Type', 3, self.update_data, 'parameter', 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['DetectScoreSlider'] = GE.Slider2(self.layer['parameters_frame'], 'DetectScoreSlider', 'Detect Score', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + # Landmarks Detection + row += top_border_delta + self.static_widget['4'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + self.widget['LandmarksDetectionAdjSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'LandmarksDetectionAdjSwitch', 'Landmarks Detection Adjustments', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += switch_delta + self.widget['LandmarksAlignModeFromPointsSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'LandmarksAlignModeFromPointsSwitch', 'From Points', 3, self.update_data, 'parameter', 398, 20, 1, row, 30, 40) + row += switch_delta + self.widget['LandmarksDetectTypeTextSel'] = GE.TextSelection(self.layer['parameters_frame'], 'LandmarksDetectTypeTextSel', 'Landmarks Detection Type', 3, self.update_data, 'parameter', 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['LandmarksDetectScoreSlider'] = GE.Slider2(self.layer['parameters_frame'], 'LandmarksDetectScoreSlider', 'Landmarks Detect Score', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['ShowLandmarksSwitch'] = GE.Switch2(self.layer['parameters_frame'], 'ShowLandmarksSwitch', 'Show Landmarks', 3, self.update_data, 'parameter', 398, 20, 1, row) + row += top_border_delta + self.static_widget['4'] = GE.Separator_x(self.layer['parameters_frame'], 0, row) + row += bottom_border_delta + # + self.widget['RecordTypeTextSel'] = GE.TextSelection(self.layer['parameters_frame'], 'RecordTypeTextSel', 'Record Type', 3, self.update_data, 'parameter', 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['VideoQualSlider'] = GE.Slider2(self.layer['parameters_frame'], 'VideoQualSlider', 'FFMPEG Quality', 3, self.update_data, 'parameter', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['MergeTextSel'] = GE.TextSelection(self.layer['parameters_frame'], 'MergeTextSel', 'Merge Math', 3, self.select_input_faces, 'merge', '', 398, 20, 1, row, 0.62) + row += row_delta + self.widget['SwapperTypeTextSel'] = GE.TextSelection(self.layer['parameters_frame'], 'SwapperTypeTextSel', 'Swapper Resolution', 3, self.update_data, 'parameter', 'parameter', 398, 20, 1, row, 0.62) + + ### Other + self.layer['tooltip_frame'] = tk.Frame(self.layer['parameter_frame'], style.canvas_frame_label_3, height=80) + self.layer['tooltip_frame'].grid(row=2, column=0, columnspan=2, sticky='NEWS', padx=0, pady=0) + self.layer['tooltip_label'] = tk.Label(self.layer['tooltip_frame'], style.info_label, wraplength=width-10, image=self.blank, compound='left', height=80, width=width-10) + self.layer['tooltip_label'].place(x=5, y=5) + self.static_widget['13'] = GE.Separator_x(self.layer['tooltip_frame'], 0, 0) + ######### FaceLab + + self.layer['facelab_canvas'] = tk.Canvas(self.layer['parameter_frame'], style.canvas_frame_label_3, bd=0, width=width) + self.layer['facelab_canvas'].grid(row=1, column=0, sticky='NEWS', pady=0, padx=0) + # + self.layer['facelab_frame'] = tk.Frame(self.layer['facelab_canvas'], style.canvas_frame_label_3, bd=0, width=width, height=11000) + self.layer['facelab_frame'].grid(row=0, column=0, sticky='NEWS', pady=0, padx=0) + # + self.layer['facelab_canvas'].create_window(0, 0, window=self.layer['facelab_frame'], anchor='nw') + # + self.layer['facelab_scroll_canvas'] = tk.Canvas(self.layer['parameter_frame'], style.canvas_frame_label_3, bd=0, ) + self.layer['facelab_scroll_canvas'].grid(row=1, column=1, sticky='NEWS', pady=0) + self.layer['facelab_scroll_canvas'].grid_rowconfigure(0, weight=1) + self.layer['facelab_scroll_canvas'].grid_columnconfigure(0, weight=1) + + self.static_widget['facelab_scrollbar'] =GE.Scrollbar_y(self.layer['facelab_scroll_canvas'] , self.layer['facelab_canvas']) + # row_delta = 20 + # row = 1 + # for i in range(512): + # temp_str = 'emb_vec_'+str(i) + # self.widget[temp_str] = GE.Slider3(self.layer['facelab_frame'], 'emb_vec_'+str(i), str(i), 3, self.adjust_embedding, i, 398, 20, 1, row, 0.62) + # row += row_delta + + ### Layout ### + top_border_delta = 25 + bottom_border_delta = 5 + switch_delta = 25 + row_delta = 20 + row = 1 + column = 160 + ######### Options + + + + + self.status_left_label = tk.Label(bottom_frame, style.donate_1, cursor="hand2", text=" Questions/Help/Discussions (Discord)") + self.status_left_label.grid( row = 0, column = 0, sticky='NEWS') + self.status_left_label.bind("", lambda e: self.callback("https://discord.gg/EcdVAFJzqp")) + + + self.status_label = tk.Label(bottom_frame, style.donate_1, text="Rope Github") + self.status_label.grid( row = 0, column = 1, sticky='NEWS') + self.status_label.bind("", lambda e: self.callback("https://github.com/Hillobar/Rope")) + + self.donate_label = tk.Label(bottom_frame, style.donate_1, text="Enjoy Rope? Please Support! (Paypal) ", anchor='e') + self.donate_label.grid( row = 0, column = 2, sticky='NEWS') + self.donate_label.bind("", lambda e: self.callback("https://www.paypal.com/donate/?hosted_button_id=Y5SB9LSXFGRF2")) + + + + + + + # Update the parameters or controls dicts and get a new frame + def update_data(self, mode, name, use_markers=False): + # print(inspect.currentframe().f_back.f_code.co_name,) + if mode=='parameter': + self.parameters[name] = self.widget[name].get() + self.add_action('parameters', self.parameters) + + elif mode=='control': + self.control[name] = self.widget[name].get() + self.add_action('control', self.control) + + if use_markers: + self.add_action('get_requested_video_frame', self.video_slider.get()) + else: + self.add_action('get_requested_video_frame_without_markers', self.video_slider.get()) + + def callback(self, url): + webbrowser.open_new_tab(url) + + def target_faces_mouse_wheel(self, event): + self.found_faces_canvas.xview_scroll(1*int(event.delta/120.0), "units") + + + def source_faces_mouse_wheel(self, event): + self.source_faces_canvas.yview_scroll(-int(event.delta/120.0), "units") + + # Center of visible canvas as a percentage of the entire canvas + center = (self.source_faces_canvas.yview()[1]-self.source_faces_canvas.yview()[0])/2 + center = center+self.source_faces_canvas.yview()[0] + self.static_widget['input_faces_scrollbar'].set(center) + + + def target_videos_mouse_wheel(self, event): + self.target_media_canvas.yview_scroll(-int(event.delta/120.0), "units") + + # Center of visible canvas as a percentage of the entire canvas + center = (self.target_media_canvas.yview()[1]-self.target_media_canvas.yview()[0])/2 + center = center+self.target_media_canvas.yview()[0] + self.static_widget['input_videos_scrollbar'].set(center) + + + def parameters_mouse_wheel(self, event): + self.canvas.yview_scroll(1*int(event.delta/120.0), "units") + + + # focus_get() + # def preview_control(self, event): + # # print(event.char, event.keysym, event.keycode) + # # print(type(event)) + # if isinstance(event, str): + # event = event + # else: + # event = event.char + + + # if self.focus_get() != self.widget['CLIPTextEntry'] and self.focus_get() != self.merged_embeddings_text: + + # #asd + # if self.video_loaded: + # frame = self.video_slider.get() + # video_length = self.video_slider.get_length() + # if event == ' ': + # self.toggle_play_video() + # elif event == 'w': + # frame += 1 + # if frame > video_length: + # frame = video_length + # self.video_slider.set(frame) + # self.add_action("get_requested_video_frame", frame) + # elif event == 's': + # frame -= 1 + # if frame < 0: + # frame = 0 + # self.video_slider.set(frame) + # self.add_action("get_requested_video_frame", frame) + # elif event == 'd': + # frame += 30 + # if frame > video_length: + # frame = video_length + # self.video_slider.set(frame) + # self.add_action("get_requested_video_frame", frame) + # elif event == 'a': + # frame -= 30 + # if frame < 0: + # frame = 0 + # self.video_slider.set(frame) + # self.add_action("get_requested_video_frame", frame) + # elif event == 'q': + # frame = 0 + # self.video_slider.set(frame) + # self.add_action("get_requested_video_frame", frame) + + def forward_one_frame(self): + frame = self.video_slider.get() + video_length = self.video_slider.get_length() + frame += 1 + if frame > video_length: + frame = video_length + self.video_slider.set(frame) + self.add_action("get_requested_video_frame", frame) + + def back_one_frame(self): + frame = self.video_slider.get() + frame -= 1 + if frame < 0: + frame = 0 + self.video_slider.set(frame) + self.add_action("get_requested_video_frame", frame) + + def preview_control(self, event): + # print(event.char, event.keysym, event.keycode) + # print(type(event)) + if isinstance(event, str): + event = event + else: + event = event.char + + + # if self.focus_get() != self.CLIP_name and self.focus_get() != self.me_name and self.parameters['ImgVidMode'] == 0: + + if self.widget['PreviewModeTextSel'].get()=='Video' and self.video_loaded: + frame = self.video_slider.get() + video_length = self.video_slider.get_length() + if event == ' ': + self.toggle_play_video() + elif event == 'w': + frame += 1 + if frame > video_length: + frame = video_length + self.video_slider.set(frame) + self.add_action("get_requested_video_frame", frame) + # self.parameter_update_from_marker(frame) + elif event == 's': + frame -= 1 + if frame < 0: + frame = 0 + self.video_slider.set(frame) + self.add_action("get_requested_video_frame", frame) + # self.parameter_update_from_marker(frame) + elif event == 'd': + frame += 30 + if frame > video_length: + frame = video_length + self.video_slider.set(frame) + self.add_action("get_requested_video_frame", frame) + # self.parameter_update_from_marker(frame) + elif event == 'a': + frame -= 30 + if frame < 0: + frame = 0 + self.video_slider.set(frame) + self.add_action("get_requested_video_frame", frame) + # self.parameter_update_from_marker(frame) + elif event == 'q': + frame = 0 + self.video_slider.set(frame) + self.add_action("get_requested_video_frame", frame) + # self.parameter_update_from_marker(frame) + + +# refactor - make sure files are closed + + def initialize_gui( self ): + json_object = {} + # check if data.json exists, if not then create it, else load it + try: + data_json_file = open("data.json", "r") + except: + with open("data.json", "w") as outfile: + json.dump(self.json_dict, outfile) + else: + json_object = json.load(data_json_file) + data_json_file.close() + + # Window position and size + try: + self.json_dict['dock_win_geom'] = json_object['dock_win_geom'] + except: + self.json_dict['dock_win_geom'] = self.json_dict['dock_win_geom'] + + # Initialize the window sizes and positions + self.geometry('%dx%d+%d+%d' % (self.json_dict['dock_win_geom'][0], self.json_dict['dock_win_geom'][1] , self.json_dict['dock_win_geom'][2], self.json_dict['dock_win_geom'][3])) + self.window_last_change = self.winfo_geometry() + + # self.bind('', lambda event: self.preview_control(event)) + # self.bind('', lambda event: self.preview_control(event)) + + self.resizable(width=True, height=True) + + # Build UI, update ui with default data + self.create_gui() + + self.video_image = cv2.cvtColor(cv2.imread('./rope/media/splash.png'), cv2.COLOR_BGR2RGB) + self.resize_image() + + # Create parameters and controls and and selctively fill with UI data + for key, value in self.widget.items(): + self.widget[key].add_info_frame(self.layer['tooltip_label']) + if self.widget[key].get_data_type()=='parameter': + self.parameters[key] = self.widget[key].get() + + + elif self.widget[key].get_data_type()=='control': + self.control[key] = self.widget[key].get() + + try: + self.json_dict["source videos"] = json_object["source videos"] + except KeyError: + self.widget['VideoFolderButton'].error_button() + else: + if self.json_dict["source videos"] == None: + self.widget['VideoFolderButton'].error_button() + else: + path = self.create_path_string(self.json_dict["source videos"], 28) + self.input_videos_text.configure(text=path) + + try: + self.json_dict["source faces"] = json_object["source faces"] + except KeyError: + self.widget['FacesFolderButton'].error_button() + else: + if self.json_dict["source faces"] == None: + self.widget['FacesFolderButton'].error_button() + else: + path = self.create_path_string(self.json_dict["source faces"], 28) + self.input_faces_text.configure(text=path) + + try: + self.json_dict["saved videos"] = json_object["saved videos"] + except KeyError: + self.widget['OutputFolderButton'].error_button() + else: + if self.json_dict["saved videos"] == None: + self.widget['OutputFolderButton'].error_button() + else: + path = self.create_path_string(self.json_dict["saved videos"], 28) + self.output_videos_text.configure(text=path) + self.add_action("saved_video_path", self.json_dict["saved videos"]) + + # Check for a user parameters file and load if present + try: + parameters_json_file = open("saved_parameters.json", "r") + except: + pass + else: + temp = json.load(parameters_json_file) + parameters_json_file.close() + for key, value in self.parameters.items(): + try: + self.parameters[key] = temp[key] + except KeyError: + pass + + # Update the UI + for key, value in self.parameters.items(): + self.widget[key].set(value, request_frame=False) + + self.add_action('parameters', self.parameters) + self.add_action('control', self.control) + + + self.widget['StartButton'].error_button() + self.set_view(False, '') + + + def create_path_string(self, path, text_len): + if len(path)>text_len: + last_folder = os.path.basename(os.path.normpath(path)) + last_folder_len = len(last_folder) + if last_folder_len>text_len: + path = path[:3]+'...'+path[-last_folder_len+6:] + else: + path = path[:text_len-last_folder_len]+'.../'+path[-last_folder_len:] + + return path + + def load_all(self): + if not self.json_dict["source videos"] or not self.json_dict["source faces"]: + print("Please set faces and videos folders first!") + return + + self.populate_target_videos() + self.load_input_faces() + self.widget['StartButton'].enable_button() + + + def select_video_path(self): + temp = self.json_dict["source videos"] + self.json_dict["source videos"] = filedialog.askdirectory(title="Select Target Videos Folder", initialdir=temp) + + path = self.create_path_string(self.json_dict["source videos"], 28) + self.input_videos_text.configure(text=path) + + with open("data.json", "w") as outfile: + json.dump(self.json_dict, outfile) + outfile.close() + self.widget['VideoFolderButton'].set(False, request_frame=False) + self.populate_target_videos() + + def select_save_video_path(self): + temp = self.json_dict["saved videos"] + self.json_dict["saved videos"] = filedialog.askdirectory(title="Select Save Video Folder", initialdir=temp) + + path = self.create_path_string(self.json_dict["saved videos"], 28) + self.output_videos_text.configure(text=path) + + with open("data.json", "w") as outfile: + json.dump(self.json_dict, outfile) + outfile.close() + self.widget['OutputFolderButton'].set(False, request_frame=False) + self.add_action("saved_video_path",self.json_dict["saved videos"]) + + def select_faces_path(self): + temp = self.json_dict["source faces"] + self.json_dict["source faces"] = filedialog.askdirectory(title="Select Source Faces Folder", initialdir=temp) + + path = self.create_path_string(self.json_dict["source faces"], 28) + self.input_faces_text.configure(text=path) + + with open("data.json", "w") as outfile: + json.dump(self.json_dict, outfile) + outfile.close() + self.widget['FacesFolderButton'].set(False, request_frame=False) + self.load_input_faces() + + def load_input_faces(self): + self.source_faces = [] + self.merged_faces_canvas.delete("all") + self.source_faces_canvas.delete("all") + + # First load merged embeddings + try: + temp0 = [] + with open("merged_embeddings.txt", "r") as embedfile: + temp = embedfile.read().splitlines() + + for i in range(0, len(temp), 513): + to = [temp[i][6:], np.array(temp[i+1:i+513], dtype='float32')] + temp0.append(to) + + for j in range(len(temp0)): + new_source_face = self.source_face.copy() + self.source_faces.append(new_source_face) + + self.source_faces[j]["ButtonState"] = False + self.source_faces[j]["Embedding"] = temp0[j][1] + self.source_faces[j]["TKButton"] = tk.Button(self.merged_faces_canvas, style.media_button_off_3, image=self.blank, text=temp0[j][0], height=14, width=84, compound='left') + + self.source_faces[j]["TKButton"].bind("", lambda event, arg=j: self.select_input_faces(event, arg)) + self.source_faces[j]["TKButton"].bind("", lambda event: self.merged_faces_canvas.xview_scroll(-int(event.delta/120.0), "units")) + + self.merged_faces_canvas.create_window((j//4)*92,8+(22*(j%4)), window = self.source_faces[j]["TKButton"],anchor='nw') + + self.merged_faces_canvas.configure(scrollregion = self.merged_faces_canvas.bbox("all")) + self.merged_faces_canvas.xview_moveto(0) + + except: + pass + + self.shift_i_len = len(self.source_faces) + + # Next Load images + directory = self.json_dict["source faces"] + filenames = [os.path.join(dirpath,f) for (dirpath, dirnames, filenames) in os.walk(directory) for f in filenames] + + # torch.cuda.memory._record_memory_history(True, trace_alloc_max_entries=100000, trace_alloc_record_context=True) + i=0 + for file in filenames: # Does not include full path + # Find all faces and ad to faces[] + # Guess File type based on extension + try: + file_type = mimetypes.guess_type(file)[0][:5] + except: + print('Unrecognized file type:', file) + else: + # Its an image + if file_type == 'image': + img = cv2.imread(file) + + if img is not None: + # convert to RGB format + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + img = torch.from_numpy(img.astype('uint8')).to('cuda') + + pad_scale = 0.2 + padded_width = int(img.size()[1]*(1.+pad_scale)) + padded_height = int(img.size()[0]*(1.+pad_scale)) + + padding = torch.zeros((padded_height, padded_width, 3), dtype=torch.uint8, device='cuda:0') + + width_start = int(img.size()[1]*pad_scale/2) + width_end = width_start+int(img.size()[1]) + height_start = int(img.size()[0]*pad_scale/2) + height_end = height_start+int(img.size()[0]) + + padding[height_start:height_end, width_start:width_end, :] = img + img = padding + + img = img.permute(2,0,1) + try: + bboxes, kpss = self.models.run_detect(img, detect_mode=self.parameters["DetectTypeTextSel"], max_num=1, score=0.5, use_landmark_detection=self.parameters['LandmarksDetectionAdjSwitch'], landmark_detect_mode=self.parameters["LandmarksDetectTypeTextSel"], landmark_score=0.5, from_points=self.parameters["LandmarksAlignModeFromPointsSwitch"]) # Just one face here + kpss = kpss[0] + except IndexError: + print('Image cropped too close:', file) + else: + face_emb, cropped_image = self.models.run_recognize(img, kpss) + # PIL follows RGB color convention and cropped image come in RGB format + crop = torchvision.transforms.functional.to_pil_image(cropped_image) + crop = crop.resize((85, 85)) + new_source_face = self.source_face.copy() + self.source_faces.append(new_source_face) + + self.source_faces[-1]["Image"] = ImageTk.PhotoImage(image=crop) + self.source_faces[-1]["Embedding"] = face_emb + self.source_faces[-1]["TKButton"] = tk.Button(self.source_faces_canvas, style.media_button_off_3, image=self.source_faces[-1]["Image"], height=90, width=90) + self.source_faces[-1]["ButtonState"] = False + self.source_faces[-1]["file"] = file + + self.source_faces[-1]["TKButton"].bind("", lambda event, arg=len(self.source_faces)-1: self.select_input_faces(event, arg)) + self.source_faces[-1]["TKButton"].bind("", self.source_faces_mouse_wheel) + + self.source_faces_canvas.create_window((i % 2) * 100, (i // 2) * 100, window=self.source_faces[-1]["TKButton"], anchor='nw') + + self.static_widget['input_faces_scrollbar'].resize_scrollbar(None) + i = i + 1 + + else: + print('Bad file', file) + + + torch.cuda.empty_cache() + + def find_faces(self): + try: + img = torch.from_numpy(self.video_image).to('cuda') + img = img.permute(2,0,1) + bboxes, kpss = self.models.run_detect(img, detect_mode=self.parameters["DetectTypeTextSel"], max_num=50, score=self.parameters["DetectScoreSlider"]/100.0, use_landmark_detection=self.parameters['LandmarksDetectionAdjSwitch'], landmark_detect_mode=self.parameters["LandmarksDetectTypeTextSel"], landmark_score=self.parameters["LandmarksDetectScoreSlider"]/100.0, from_points=self.parameters["LandmarksAlignModeFromPointsSwitch"]) + + ret = [] + for face_kps in kpss: + + # if kpss is not None: + # face_kps = kpss[i] + + + face_emb, cropped_img = self.models.run_recognize(img, face_kps) + ret.append([face_kps, face_emb, cropped_img]) + + except Exception: + print(" No media selected") + + else: + # Find all faces and add to target_faces[] + if ret: + # Apply threshold tolerence + threshhold = self.parameters["ThresholdSlider"] + + # if self.parameters["ThresholdState"]: + # threshhold = 0.0 + + # Loop thgouh all faces in video frame + for face in ret: + found = False + + # Check if this face has already been found + for emb in self.target_faces: + if self.findCosineDistance(emb['Embedding'], face[1]) >= threshhold: + found = True + break + + # If we dont find any existing simularities, it means that this is a new face and should be added to our found faces + if not found: + crop = torchvision.transforms.functional.to_pil_image(face[2]) + crop = crop.resize((82, 82)) + + new_target_face = self.target_face.copy() + self.target_faces.append(new_target_face) + last_index = len(self.target_faces)-1 + + self.target_faces[last_index]["TKButton"] = tk.Button(self.found_faces_canvas, style.media_button_off_3, height = 86, width = 86) + self.target_faces[last_index]["TKButton"].bind("", self.target_faces_mouse_wheel) + self.target_faces[last_index]["ButtonState"] = False + self.target_faces[last_index]["Image"] = ImageTk.PhotoImage(image=crop) + self.target_faces[last_index]["Embedding"] = face[1] + self.target_faces[last_index]["EmbeddingNumber"] = 1 + + # Add image to button + self.target_faces[-1]["TKButton"].config( pady = 10, image = self.target_faces[last_index]["Image"], command=lambda k=last_index: self.toggle_found_faces_buttons_state(k)) + + # Add button to canvas + self.found_faces_canvas.create_window((last_index)*92, 8, window=self.target_faces[last_index]["TKButton"], anchor='nw') + + self.found_faces_canvas.configure(scrollregion = self.found_faces_canvas.bbox("all")) + + def clear_faces(self): + self.target_faces = [] + self.found_faces_canvas.delete("all") + + # toggle the target faces button and make assignments + def toggle_found_faces_buttons_state(self, button): + # Turn all Target faces off + for i in range(len(self.target_faces)): + self.target_faces[i]["ButtonState"] = False + self.target_faces[i]["TKButton"].config(style.media_button_off_3) + + # Set only the selected target face to on + self.target_faces[button]["ButtonState"] = True + self.target_faces[button]["TKButton"].config(style.media_button_on_3) + + # set all source face buttons to off + for i in range(len(self.source_faces)): + self.source_faces[i]["ButtonState"] = False + self.source_faces[i]["TKButton"].config(style.media_button_off_3) + + # turn back on the ones that are assigned to the curent target face + for i in range(len(self.target_faces[button]["SourceFaceAssignments"])): + self.source_faces[self.target_faces[button]["SourceFaceAssignments"][i]]["ButtonState"] = True + self.source_faces[self.target_faces[button]["SourceFaceAssignments"][i]]["TKButton"].config(style.media_button_on_3) + + def select_input_faces(self, event, button): + + try: + if event.state & 0x4 != 0: + modifier = 'ctrl' + elif event.state & 0x1 != 0: + modifier = 'shift' + else: + modifier = 'none' + except: + modifier = event + + + # If autoswap isnt on + # Clear all the highlights. Clear all states, excpet if a modifier is being used + # Start by turning off all the highlights on the input faces buttons + if modifier != 'auto': + for face in self.source_faces: + face["TKButton"].config(style.media_button_off_3) + + # and also clear the states if not selecting multiples + if modifier == 'none': + face["ButtonState"] = False + + # Toggle the state of the selected Input Face + if modifier != 'merge': + self.source_faces[button]["ButtonState"] = not self.source_faces[button]["ButtonState"] + + # if shift find any other input faces and activate the state of all faces in between + if modifier == 'shift': + for i in range(button-1, self.shift_i_len-1, -1): + if self.source_faces[i]["ButtonState"]: + for j in range(i, button, 1): + self.source_faces[j]["ButtonState"] = True + break + for i in range(button+1, len(self.source_faces), 1): + if self.source_faces[i]["ButtonState"]: + for j in range(button, i, 1): + self.source_faces[j]["ButtonState"] = True + break + + # Highlight all of input faces buttons that have a true state + for face in self.source_faces: + if face["ButtonState"]: + face["TKButton"].config(style.media_button_on_3) + + if self.widget['PreviewModeTextSel'].get() == 'FaceLab': + self.add_action("load_target_image", face["file"]) + self.image_loaded = True + + # Assign all active input faces to the active target face + for tface in self.target_faces: + if tface["ButtonState"]: + + # Clear all of the assignments + tface["SourceFaceAssignments"] = [] + + # Iterate through all Input faces + temp_holder = [] + for j in range(len(self.source_faces)): + + # If the source face is active + if self.source_faces[j]["ButtonState"]: + tface["SourceFaceAssignments"].append(j) + temp_holder.append(self.source_faces[j]['Embedding']) + + # do averaging + if temp_holder: + if self.widget['MergeTextSel'].get() == 'Median': + tface['AssignedEmbedding'] = np.median(temp_holder, 0) + elif self.widget['MergeTextSel'].get() == 'Mean': + tface['AssignedEmbedding'] = np.mean(temp_holder, 0) + + self.temp_emb = tface['AssignedEmbedding'] + + # for k in range(512): + # self.widget['emb_vec_' + str(k)].set(tface['AssignedEmbedding'][k], False) + break + + self.add_action("target_faces", self.target_faces) + self.add_action('get_requested_video_frame', self.video_slider.get()) + + # latent = torch.from_numpy(self.models.calc_swapper_latent(self.source_faces[button]['Embedding'])).float().to('cuda') + # face['ptrdata'] = self.models.run_swap_stg1(latent) + + + + def populate_target_videos(self): + # Recursively read all media files from directory + directory = self.json_dict["source videos"] + filenames = [os.path.join(dirpath,f) for (dirpath, dirnames, filenames) in os.walk(directory) for f in filenames] + + videos = [] + images = [] + self.target_media = [] + self.target_media_buttons = [] + self.target_media_canvas.delete("all") + + for file in filenames: # Does not include full path + # Guess File type based on extension + try: + file_type = mimetypes.guess_type(file)[0][:5] + except: + print('Unrecognized file type:', file) + else: + # Its an image + if file_type == 'image': + try: + image = cv2.imread(file) + image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + except: + print('Trouble reading file:', file) + else: + ratio = float(image.shape[0]) / image.shape[1] + + new_height = 50 + new_width = int(new_height / ratio) + image = cv2.resize(image, (new_width, new_height)) + image[:new_height, :new_width, :] = image + images.append([image, file]) + + # Its a video + elif file_type == 'video': + try: + video = cv2.VideoCapture(file) + except: + print('Trouble reading file:', file) + else: + if video.isOpened(): + + # Grab a frame from the middle for a thumbnail + video.set(cv2.CAP_PROP_POS_FRAMES, int(video.get(cv2.CAP_PROP_FRAME_COUNT)/2)) + success, video_frame = video.read() + + if success: + video_frame = cv2.cvtColor(video_frame, cv2.COLOR_BGR2RGB) + ratio = float(video_frame.shape[0]) / video_frame.shape[1] + + new_height = 50 + new_width = int(new_height / ratio) + video_frame = cv2.resize(video_frame, (new_width, new_height)) + video_frame[:new_height, :new_width, :] = video_frame + + videos.append([video_frame, file]) + video.release() + + else: + print('Trouble reading file:', file) + else: + print('Trouble opening file:', file) + delx, dely = 100, 79 + if self.widget['PreviewModeTextSel'].get()== 'Image':#images + for i in range(len(images)): + self.target_media_buttons.append(tk.Button(self.target_media_canvas, style.media_button_off_3, height = 86, width = 86)) + + rgb_video = Image.fromarray(images[i][0]) + self.target_media.append(ImageTk.PhotoImage(image=rgb_video)) + self.target_media_buttons[i].config( image = self.target_media[i], command=lambda i=i: self.load_target(i, images[i][1], self.widget['PreviewModeTextSel'].get())) + self.target_media_buttons[i].bind("", self.target_videos_mouse_wheel) + self.target_media_canvas.create_window((i%2)*delx, (i//2)*dely, window = self.target_media_buttons[i], anchor='nw') + + self.target_media_canvas.configure(scrollregion = self.target_media_canvas.bbox("all")) + + elif self.widget['PreviewModeTextSel'].get()=='Video':#videos + + for i in range(len(videos)): + self.target_media_buttons.append(tk.Button(self.target_media_canvas, style.media_button_off_3, height = 65, width = 90)) + self.target_media.append(ImageTk.PhotoImage(image=Image.fromarray(videos[i][0]))) + + filename = os.path.basename(videos[i][1]) + if len(filename)>14: + filename = filename[:11]+'...' + + self.target_media_buttons[i].bind("", self.target_videos_mouse_wheel) + self.target_media_buttons[i].config(image = self.target_media[i], text=filename, compound='top', anchor='n',command=lambda i=i: self.load_target(i, videos[i][1], self.widget['PreviewModeTextSel'].get())) + self.target_media_canvas.create_window((i%2)*delx, (i//2)*dely, window = self.target_media_buttons[i], anchor='nw') + + self.static_widget['input_videos_scrollbar'].resize_scrollbar(None) + + def auto_swap(self): + # Reselect Target Image + # try: + self.find_faces() + self.target_faces[0]["ButtonState"] = True + self.target_faces[0]["TKButton"].config(style.media_button_on_3) + + # Reselect Source images + self.select_input_faces('auto', '') + self.toggle_swapper(True) + # except: + # pass + def toggle_auto_swap(self): + self.widget['AutoSwapButton'].toggle_button() + + + def load_target(self, button, media_file, media_type): + # Make sure the video stops playing + self.toggle_play_video('stop') + self.image_loaded = False + self.video_loaded = False + self.clear_faces() + + if media_type == 'Video': + self.video_slider.set(0) + self.add_action("load_target_video", media_file) + self.media_file_name = os.path.splitext(os.path.basename(media_file)) + self.video_loaded = True + + + elif media_type == 'Image': + self.add_action("load_target_image", media_file) + self.media_file_name = os.path.splitext(os.path.basename(media_file)) + self.image_loaded = True + + # # find faces + if self.widget['AutoSwapButton'].get(): + self.add_action('function', "gui.auto_swap()") + + + + + for i in range(len(self.target_media_buttons)): + self.target_media_buttons[i].config(style.media_button_off_3) + + self.target_media_buttons[button].config(style.media_button_on_3) + + # delete all markers + self.layer['markers_canvas'].delete('all') + self.markers = [] + self.stop_marker = [] + + #region [#111111b4] + + self.load_markers_json() + self.add_action("update_markers_canvas", self.markers) + + #endregion + + self.add_action("markers", self.markers) + + + + # @profile + def set_image(self, image, requested): + self.video_image = image[0] + frame = image[1] + + if not requested: + self.video_slider.set(frame) + self.parameter_update_from_marker(frame) + + self.resize_image() + + # @profile + def resize_image(self): + image = self.video_image + + if len(image) != 0: + + x1 = float(self.video.winfo_width()) + y1 = float(self.video.winfo_height()) + + + x2 = float(image.shape[1]) + y2 = float(image.shape[0]) + + + m1 = x1/y1 + m2 = x2/y2 + + if m2>m1: + x2 = x1 + y2 = x1/m2 + image = cv2.resize(image, (int(x2), int(y2))) + padding = int((y1-y2)/2.0) + image = cv2.copyMakeBorder( image, padding, padding, 0, 0, cv2.BORDER_CONSTANT) + else: + y2=y1 + x2=y2*m2 + image = cv2.resize(image, (int(x2), int(y2))) + padding=int((x1-x2)/2.0) + image = cv2.copyMakeBorder( image, 0, 0, padding, padding, cv2.BORDER_CONSTANT) + + image = Image.fromarray(image) + image = ImageTk.PhotoImage(image) + self.video.image = image + self.video.configure(image=self.video.image) + + + + + + def check_for_video_resize(self): + + # Read the geometry from the last time json was updated. json only updates once the window ahs stopped changing + win_geom = '%dx%d+%d+%d' % (self.json_dict['dock_win_geom'][0], self.json_dict['dock_win_geom'][1] , self.json_dict['dock_win_geom'][2], self.json_dict['dock_win_geom'][3]) + + # # window has started changing + if self.winfo_geometry() != win_geom: + # Resize image in video window + self.resize_image() + for k, v in self.widget.items(): + v.hide() + for k, v in self.static_widget.items(): + v.hide() + + + # Check if window has stopped changing + if self.winfo_geometry() != self.window_last_change: + self.window_last_change = self.winfo_geometry() + + # The window has stopped changing + else: + for k, v in self.widget.items(): + v.unhide() + for k, v in self.static_widget.items(): + v.unhide() + # Update json + str1 = self.winfo_geometry().split('x') + str2 = str1[1].split('+') + win_geom = [str1[0], str2[0], str2[1], str2[2]] + win_geom = [int(strings) for strings in win_geom] + self.json_dict['dock_win_geom'] = win_geom + with open("data.json", "w") as outfile: + json.dump(self.json_dict, outfile) + + + + + + def get_action(self): + action = self.action_q[0] + self.action_q.pop(0) + return action + + def get_action_length(self): + return len(self.action_q) + + + + def set_video_slider_length(self, video_length): + self.video_slider.set_length(video_length) + + + + def findCosineDistance(self, vector1, vector2): + vector1 = vector1.ravel() + vector2 = vector2.ravel() + cos_dist = 1 - np.dot(vector1, vector2)/(np.linalg.norm(vector1)*np.linalg.norm(vector2)) # 2..0 + return 100-cos_dist*50 + ''' + vector1 = vector1.ravel() + vector2 = vector2.ravel() + + return 1 - np.dot(vector1, vector2)/(np.linalg.norm(vector1)*np.linalg.norm(vector2)) + ''' + + + def toggle_play_video(self, set_value='toggle'): + if self.video_loaded: + + # Update button + if set_value == 'toggle': + self.widget['TLPlayButton'].toggle_button() + if set_value == 'stop': + self.widget['TLPlayButton'].disable_button() + if set_value == 'play': + self.widget['TLPlayButton'].enable_button() + + # If play + if self.widget['TLPlayButton'].get(): + if not self.video_loaded: + print("Please select video first!") + return + else: + # and record + if self.widget['TLRecButton'].get(): + if not self.json_dict["saved videos"]: + print("Set saved video folder first!") + self.add_action("play_video", "stop_from_gui") + + else: + self.add_action("play_video", "record") + + # only play + else: + self.add_action("play_video", "play") + + else: + self.add_action("play_video", "stop_from_gui") + + + def set_player_buttons_to_inactive(self): + self.widget['TLRecButton'].disable_button() + self.widget['TLPlayButton'].disable_button() + + + def toggle_swapper(self, toggle_value=-1): + # print(inspect.currentframe().f_back.f_code.co_name, 'toggle_swapper: '+'toggle_value='+str(toggle_value)) + + if toggle_value == -1: + self.widget['SwapFacesButton'].toggle_button() + + else: + if toggle_value: + self.widget['SwapFacesButton'].enable_button() + else: + self.widget['SwapFacesButton'].disable_button() + + if self.widget['PreviewModeTextSel'].get()=='Video' or self.widget['PreviewModeTextSel'].get()=='Theater': + self.update_data('control', 'SwapFacesButton', use_markers=True) + elif self.widget['PreviewModeTextSel'].get()=='Image': + self.update_data('control', 'SwapFacesButton', use_markers=False) + elif self.widget['PreviewModeTextSel'].get() == 'FaceLab': + self.update_data('control', 'SwapFacesButton', use_markers=False) + + + def temp_toggle_swapper(self, state): + if state=='off': + self.widget['SwapFacesButton'].temp_disable_button() + elif state=='on': + self.widget['SwapFacesButton'].temp_enable_button() + + self.update_data('control', 'SwapFacesButton', use_markers=True) + + def toggle_rec_video(self): + # Play button must be off to enable record button + + #region [#111111b4] + + self.save_markers_json() + + #endregion + + if not self.widget['TLPlayButton'].get(): + self.widget['TLRecButton'].toggle_button() + + if self.widget['TLRecButton'].get(): + self.widget['TLRecButton'].enable_button() + + else: + self.widget['TLRecButton'].disable_button() + + + # this makes no sense + def add_action(self, action, parameter=None): # + # print(inspect.currentframe().f_back.f_code.co_name, '->add_action: '+action) + + if action != 'get_requested_video_frame' and action != 'get_requested_video_frame_without_markers': + self.action_q.append([action, parameter]) + + # Only do requests when the video is not playing - (moving the timeline or changing parameters) + elif self.video_loaded and not self.widget['TLPlayButton'].get(): + self.action_q.append([action, parameter]) + + elif self.image_loaded: + self.action_q.append([action, parameter]) + + def update_vram_indicator(self): + try: + used, total = self.models.get_gpu_memory() + except: + pass + else: + self.static_widget['vram_indicator'].set(used, total) + + + +# refactor and thread i/o + def save_selected_source_faces(self, text): + # get name from text field + text = text.get() + # get embeddings from all highlightebuttons + # iterate through the buttons + + temp_holder = [] + + for button in self.source_faces: + if button["ButtonState"]: + temp_holder.append(button['Embedding']) + + if temp_holder: + if self.widget['MergeTextSel'].get()=='Median': + ave_embedding = np.median(temp_holder,0) + elif self.widget['MergeTextSel'].get()=='Mean': + ave_embedding = np.mean(temp_holder,0) + + for tface in self.target_faces: + if tface["ButtonState"]: + ave_embedding = tface['AssignedEmbedding'] + + if text != "": + with open("merged_embeddings.txt", "a") as embedfile: + identifier = "Name: "+text + embedfile.write("%s\n" % identifier) + for number in ave_embedding: + embedfile.write("%s\n" % number) + else: + print('No embedding name specified') + else: + print('No Source Images selected') + + self.focus() + self.load_input_faces() + +# refactor and thread i/o + def delete_merged_embedding(self): #add multi select + + # get selected button + sel = [] + for j in range(len(self.source_faces)): + if self.source_faces[j]["ButtonState"]: + sel = j + break + + # check if it is a merged embedding + # if so, read txt embedding into list + temp0 = [] + if os.path.exists("merged_embeddings.txt"): + + with open("merged_embeddings.txt", "r") as embedfile: + temp = embedfile.read().splitlines() + + for i in range(0, len(temp), 513): + to = [temp[i], np.array(temp[i+1:i+513], dtype='float32')] + temp0.append(to) + + if j < len(temp0): + temp0.pop(j) + + with open("merged_embeddings.txt", "w") as embedfile: + for line in temp0: + embedfile.write("%s\n" % line[0]) + for i in range(512): + embedfile.write("%s\n" % line[1][i]) + + self.load_input_faces() + + def iterate_through_merged_embeddings(self, event): + if event.delta>0: + for i in range(len(self.source_faces)): + if self.source_faces[i]["ButtonState"] and i0: + self.select_input_faces('none', i-1) + break + + def set_view(self, load_target_videos,b): + # self.clear_faces() + # self.video_loaded = False + # self.image_loaded = False + if load_target_videos and self.widget['PreviewModeTextSel'].get() != 'Theater': + self.populate_target_videos() + + self.layer['slider_frame'].grid_forget() + self.layer['preview_frame'].grid_forget() + self.layer['markers_canvas'].grid_forget() + self.layer['image_controls'].grid_forget() + self.layer['FaceLab_controls'].grid_forget() + self.layer['InputVideoFrame'].grid_forget() + self.layer['parameter_frame'].grid_forget() + + self.layer['parameters_canvas'].grid_forget() + self.layer['parameter_scroll_canvas'].grid_forget() + + self.layer['facelab_canvas'].grid_forget() + self.layer['facelab_scroll_canvas'].grid_forget() + + if self.widget['PreviewModeTextSel'].get()=='Video': + self.image_loaded = False + self.layer['slider_frame'].grid(row=2, column=0, sticky='NEWS', pady=0) + self.layer['preview_frame'].grid(row=4, column=0, sticky='NEWS') + self.layer['markers_canvas'].grid(row=3, column=0, sticky='NEWS') + self.layer['parameter_frame'].grid(row=0, column=2, sticky='NEWS', pady=0, padx=1) + + self.layer['parameters_canvas'].grid(row=1, column=0, sticky='NEWS', pady=0, padx=0) + self.layer['parameter_scroll_canvas'].grid(row=1, column=1, sticky='NEWS', pady=0) + self.layer['InputVideoFrame'].grid(row=0, column=0, sticky='NEWS', padx=1, pady=0) + + + elif self.widget['PreviewModeTextSel'].get()=='Image': + self.video_loaded = False + self.layer['image_controls'].grid(row=2, column=0, rowspan=2, sticky='NEWS', pady=0) + + self.layer['parameters_canvas'].grid(row=1, column=0, sticky='NEWS', pady=0, padx=0) + self.layer['parameter_scroll_canvas'].grid(row=1, column=1, sticky='NEWS', pady=0) + self.layer['InputVideoFrame'].grid(row=0, column=0, sticky='NEWS', padx=1, pady=0) + self.layer['parameter_frame'].grid(row=0, column=2, sticky='NEWS', pady=0, padx=1) + + + elif self.widget['PreviewModeTextSel'].get() == 'FaceLab': + self.video_loaded = False + self.layer['FaceLab_controls'].grid(row=2, column=0, rowspan=2, sticky='NEWS', pady=0) + self.layer['facelab_canvas'].grid(row=1, column=0, sticky='NEWS', pady=0, padx=0) + self.layer['facelab_scroll_canvas'].grid(row=1, column=1, sticky='NEWS', pady=0) + self.layer['InputVideoFrame'].grid(row=0, column=0, sticky='NEWS', padx=1, pady=0) + self.layer['parameter_frame'].grid(row=0, column=2, sticky='NEWS', pady=0, padx=1) + + # # find the input image with the lowest value + # for face in self.source_faces: + # if face["ButtonState"]: + # self.image_loaded = True + # self.add_action("load_target_image", face["file"]) + # break + + + elif self.widget['PreviewModeTextSel'].get() == 'Theater': + self.image_loaded = False + self.layer['slider_frame'].grid(row=2, column=0, sticky='NEWS', pady=0) + self.layer['preview_frame'].grid(row=4, column=0, sticky='NEWS') + self.layer['markers_canvas'].grid(row=3, column=0, sticky='NEWS') + + + + + + + def update_marker(self, action): + + if action=='add': + # Delete existing marker at current frame and replace with new data + for i in range(len(self.markers)): + if self.markers[i]['frame'] == self.video_slider.get(): + self.layer['markers_canvas'].delete(self.markers[i]['icon_ref']) + self.markers.pop(i) + break + + width = self.layer['markers_canvas'].winfo_width()-20-40-20 + position = 20+int(width*self.video_slider.get()/self.video_slider.get_length()) + + temp_param = copy.deepcopy(self.parameters) + temp = { + 'frame': self.video_slider.get(), + 'parameters': temp_param, + 'icon_ref': self.layer['markers_canvas'].create_line(position,0, position, 15, fill='light goldenrod'), + } + + self.markers.append(temp) + def sort(e): + return e['frame'] + + self.markers.sort(key=sort) + self.add_action("markers", self.markers) + + # elif action=='stop': + # if self.stop_marker == self.video_slider.get(): + # self.stop_marker = [] + # self.add_action('set_stop', -1) + # self.video_slider_canvas.delete(self.stop_image) + # else: + # self.video_slider_canvas.delete(self.stop_image) + # self.stop_marker = self.video_slider.self.timeline_position + # self.add_action('set_stop', self.stop_marker) + # + # width = self.video_slider_canvas.winfo_width() - 30 + # position = 15 + int(width * self.video_slider.self.timeline_position / self.video_slider.configure('to')[4]) + # self.stop_image = self.video_slider_canvas.create_image(position, 30, image=self.stop_marker_icon) + + elif action=='delete': + for i in range(len(self.markers)): + if self.markers[i]['frame'] == self.video_slider.get(): + self.layer['markers_canvas'].delete(self.markers[i]['icon_ref']) + self.markers.pop(i) + break + + elif action=='prev': + + temp=[] + for i in range(len(self.markers)): + temp.append(self.markers[i]['frame']) + idx = bisect.bisect_left(temp, self.video_slider.get()) + + if idx > 0: + self.video_slider.set(self.markers[idx-1]['frame']) + + self.add_action('get_requested_video_frame', self.markers[idx-1]['frame']) + self.parameter_update_from_marker(self.markers[idx-1]['frame']) + + elif action=='next': + temp=[] + for i in range(len(self.markers)): + temp.append(self.markers[i]['frame']) + idx = bisect.bisect(temp, self.video_slider.get()) + + if idx < len(self.markers): + self.video_slider.set(self.markers[idx]['frame']) + + self.add_action('get_requested_video_frame', self.markers[idx]['frame']) + self.parameter_update_from_marker(self.markers[idx]['frame']) + + # resize canvas + else : + + self.layer['markers_canvas'].delete('all') + width = self.layer['markers_canvas'].winfo_width()-20-40-20 + + for marker in self.markers: + position = 20+int(width*marker['frame']/self.video_slider.get_length()) + marker['icon_ref'] = self.layer['markers_canvas'].create_line(position,0, position, 15, fill='light goldenrod') + + + #region [#111111b4] + + def save_markers_json(self): + + if len(self.markers) == 0 or len(self.media_file_name) == 0: + return + json_file_path = os.path.join(self.json_dict["source videos"], self.media_file_name[0] + "_markers.json") + # Save the markers to the JSON file + with open(json_file_path, 'w') as json_file: + json.dump(self.markers, json_file) + print('Markers saved') + + def load_markers_json(self): + if len(self.media_file_name) == 0: + return + json_file_path = os.path.join(self.json_dict["source videos"], self.media_file_name[0] + "_markers.json") + if os.path.exists(json_file_path): + # Load the markers from the JSON file + with open(json_file_path, 'r') as json_file: + self.markers = json.load(json_file) + self.add_action("update_markers_canvas", self.markers) + + def update_markers_canvas(self): + self.layer['markers_canvas'].delete('all') + width = self.layer['markers_canvas'].winfo_width()-20-40-20 + for marker in self.markers: + position = 20+int(width*marker['frame']/self.video_slider.get_length()) + marker['icon_ref'] = self.layer['markers_canvas'].create_line(position,0, position, 15, fill='light goldenrod') + + #endregion + + def toggle_stop(self): + if self.stop_marker == self.video_slider.self.timeline_position: + self.stop_marker = [] + self.add_action('set_stop', -1) + self.video_slider_canvas.delete(self.stop_image) + else: + self.video_slider_canvas.delete(self.stop_image) + self.stop_marker = self.video_slider.self.timeline_position + self.add_action('set_stop', self.stop_marker) + + width = self.video_slider_canvas.winfo_width()-30 + position = 15+int(width*self.video_slider.self.timeline_position/self.video_slider.configure('to')[4]) + self.stop_image = self.video_slider_canvas.create_image(position, 30, image=self.stop_marker_icon) + + + def save_image(self): + filename = self.media_file_name[0]+"_"+str(time.time())[:10] + filename = os.path.join(self.json_dict["saved videos"], filename) + cv2.imwrite(filename+'.png', cv2.cvtColor(self.video_image, cv2.COLOR_BGR2RGB)) + print('Image saved as:', filename+'.png') + + def clear_mem(self): + self.widget['RestorerSwitch'].set(False) + self.widget['OccluderSwitch'].set(False) + self.widget['FaceParserSwitch'].set(False) + self.widget['CLIPSwitch'].set(False) + self.widget['SwapFacesButton'].set(False) + + self.models.delete_models() + torch.cuda.empty_cache() + + + +# Refactor this, doesn't seem very efficient + def parameter_update_from_marker(self, frame): + + # sync marker data + temp=[] + # create a separate list with the list of frame numbers with markers + for i in range(len(self.markers)): + temp.append(self.markers[i]['frame']) + # find the marker frame to the left of the current frame + idx = bisect.bisect(temp, frame) + # update UI with current marker state data + if idx>0: + # update paramter dict with marker entry + self.parameters = copy.deepcopy(self.markers[idx-1]['parameters']) + + # Update ui + for key, value in self.parameters.items(): + self.widget[key].set(self.parameters[key], request_frame=False) + + + # self.CLIP_text.delete(0, tk.END) + # self.CLIP_text.insert(0, self.parameters['CLIPText']) + + def toggle_audio(self): + self.widget['AudioButton'].toggle_button() + self.control['AudioButton'] = self.widget['AudioButton'].get() + self.add_action('control', self.control) + + def toggle_maskview(self): + self.widget['MaskViewButton'].toggle_button() + self.control['MaskViewButton'] = self.widget['MaskViewButton'].get() + self.add_action('control', self.control) + self.add_action('get_requested_video_frame', self.video_slider.get()) + + def parameter_io(self, task): + if task=='save': + with open("saved_parameters.json", "w") as save_file: + json.dump(self.parameters, save_file) + + elif task=='load': + try: + load_file = open("saved_parameters.json", "r") + except FileNotFoundError: + print('No save file created yet!') + else: + # Load the file and save it to parameters + self.parameters = json.load(load_file) + load_file.close() + + # Update the UI + for key, value in self.parameters.items(): + self.widget[key].set(value, request_frame=False) + + self.add_action('parameters', self.parameters) + self.add_action('control', self.control) + self.add_action('get_requested_video_frame', self.video_slider.get()) + + elif task=='default': + # Update the UI + for key, value in self.parameters.items(): + self.widget[key].load_default() + + self.add_action('parameters', self.parameters) + self.add_action('control', self.control) + self.add_action('get_requested_video_frame', self.video_slider.get()) + + + + def findCosineDistance2(self, vector1, vector2): + cos_dist = 1.0 - np.dot(vector1, vector2)/(np.linalg.norm(vector1)*np.linalg.norm(vector2)) # 2..0 + + print(np.dot(vector1, vector2)) + + return cos_dist \ No newline at end of file