|
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
|
|
|
|
|
|
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,
|
|
'AssignedEmbedding': [],
|
|
}
|
|
self.target_faces = []
|
|
|
|
self.source_face = {
|
|
"TKButton": [],
|
|
"ButtonState": "off",
|
|
"Image": [],
|
|
"Embedding": []
|
|
}
|
|
self.source_faces = []
|
|
|
|
|
|
|
|
script_dir = os.path.dirname(__file__)
|
|
icon_path = os.path.join(script_dir, 'media', 'rope.ico')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
text_vars = {}
|
|
for shortcut_name, default_value in shortcuts.items():
|
|
text_vars[shortcut_name] = tk.StringVar(value=default_value)
|
|
|
|
|
|
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('<Key>', self.handle_key_press)
|
|
self.bind("<Return>", 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())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_gui(self):
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def vidupdate():
|
|
self.resize_image()
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
|
|
|
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 = 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 = 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)
|
|
|
|
middle_frame.grid_columnconfigure(0, weight=0)
|
|
|
|
middle_frame.grid_columnconfigure(1, weight=1)
|
|
|
|
middle_frame.grid_columnconfigure(2, weight=0)
|
|
|
|
middle_frame.grid_columnconfigure(3, weight=0)
|
|
|
|
|
|
|
|
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(),
|
|
}
|
|
|
|
|
|
shortcuts = load_shortcuts_from_json()
|
|
|
|
|
|
text_vars = {}
|
|
for shortcut_name, default_value in shortcuts.items():
|
|
text_vars[shortcut_name] = tk.StringVar(value=default_value)
|
|
|
|
|
|
def save_shortcuts():
|
|
|
|
for shortcut_name, text_var in text_vars.items():
|
|
shortcuts[shortcut_name] = text_var.get()
|
|
|
|
|
|
save_shortcuts_to_json(shortcuts)
|
|
update_key_actions()
|
|
|
|
|
|
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)
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
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()
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
self.layer['InputVideoFrame'].grid_rowconfigure(0, weight=0)
|
|
|
|
self.layer['InputVideoFrame'].grid_rowconfigure(1, weight=1)
|
|
|
|
|
|
self.layer['InputVideoFrame'].grid_columnconfigure(0, weight=0)
|
|
|
|
self.layer['InputVideoFrame'].grid_columnconfigure(1, weight=0)
|
|
|
|
self.layer['InputVideoFrame'].grid_columnconfigure(0, weight=0)
|
|
|
|
self.layer['InputVideoFrame'].grid_columnconfigure(1, weight=0)
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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("<MouseWheel>", 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 = 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)
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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("<MouseWheel>", 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(self.layer['InputVideoFrame'], 229, 0)
|
|
GE.Separator_x(self.layer['InputVideoFrame'], 0, 41)
|
|
|
|
|
|
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)
|
|
|
|
self.layer['preview_column'].grid_rowconfigure(0, weight=0)
|
|
|
|
self.layer['preview_column'].grid_rowconfigure(1, weight=1)
|
|
|
|
self.layer['preview_column'].grid_rowconfigure(2, weight=0)
|
|
|
|
self.layer['preview_column'].grid_rowconfigure(3, weight=0)
|
|
|
|
self.layer['preview_column'].grid_rowconfigure(4, weight=0)
|
|
|
|
self.layer['preview_column'].grid_rowconfigure(5, weight=0)
|
|
|
|
self.layer['preview_column'].grid_rowconfigure(6, weight=0)
|
|
|
|
|
|
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_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)
|
|
|
|
|
|
|
|
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("<MouseWheel>", self.iterate_through_merged_embeddings)
|
|
self.video.bind("<ButtonRelease-1>", lambda event: self.toggle_play_video())
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
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('<Configure>', lambda e:self.update_marker(e.width))
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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_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['SaveMarkerButton'] = GE.Button(right_playframe, 'SaveMarkerButton', 2, self.save_markers_json, None, 'control', x=95, y=5, width=20)
|
|
|
|
|
|
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()
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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("<MouseWheel>", 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)
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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("<Return>", lambda event: self.save_selected_source_faces(self.merged_embedding_name))
|
|
self.me_name = self.nametowidget(self.merged_embeddings_text)
|
|
|
|
|
|
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("<MouseWheel>", 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)
|
|
|
|
|
|
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)
|
|
|
|
top_border_delta = 25
|
|
bottom_border_delta = 5
|
|
switch_delta = 25
|
|
row_delta = 20
|
|
row = 1
|
|
column = 160
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
top_border_delta = 25
|
|
bottom_border_delta = 5
|
|
switch_delta = 25
|
|
row_delta = 20
|
|
row = 1
|
|
column = 160
|
|
|
|
|
|
|
|
|
|
|
|
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("<Button-1>", 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("<Button-1>", 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("<Button-1>", lambda e: self.callback("https://www.paypal.com/donate/?hosted_button_id=Y5SB9LSXFGRF2"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update_data(self, mode, name, use_markers=False):
|
|
|
|
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 = (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 = (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")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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):
|
|
|
|
|
|
if isinstance(event, str):
|
|
event = event
|
|
else:
|
|
event = event.char
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
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 initialize_gui( self ):
|
|
json_object = {}
|
|
|
|
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()
|
|
|
|
|
|
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']
|
|
|
|
|
|
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.resizable(width=True, height=True)
|
|
|
|
|
|
self.create_gui()
|
|
|
|
self.video_image = cv2.cvtColor(cv2.imread('./rope/media/splash.png'), cv2.COLOR_BGR2RGB)
|
|
self.resize_image()
|
|
|
|
|
|
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"])
|
|
|
|
|
|
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
|
|
|
|
|
|
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")
|
|
|
|
|
|
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("<ButtonRelease-1>", lambda event, arg=j: self.select_input_faces(event, arg))
|
|
self.source_faces[j]["TKButton"].bind("<MouseWheel>", 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)
|
|
|
|
|
|
directory = self.json_dict["source faces"]
|
|
filenames = [os.path.join(dirpath,f) for (dirpath, dirnames, filenames) in os.walk(directory) for f in filenames]
|
|
|
|
|
|
i=0
|
|
for file in filenames:
|
|
|
|
|
|
try:
|
|
file_type = mimetypes.guess_type(file)[0][:5]
|
|
except:
|
|
print('Unrecognized file type:', file)
|
|
else:
|
|
|
|
if file_type == 'image':
|
|
img = cv2.imread(file)
|
|
|
|
if img is not None:
|
|
|
|
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"])
|
|
kpss = kpss[0]
|
|
except IndexError:
|
|
print('Image cropped too close:', file)
|
|
else:
|
|
face_emb, cropped_image = self.models.run_recognize(img, kpss)
|
|
|
|
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("<ButtonRelease-1>", lambda event, arg=len(self.source_faces)-1: self.select_input_faces(event, arg))
|
|
self.source_faces[-1]["TKButton"].bind("<MouseWheel>", 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:
|
|
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
if ret:
|
|
|
|
threshhold = self.parameters["ThresholdSlider"]
|
|
|
|
|
|
|
|
|
|
|
|
for face in ret:
|
|
found = False
|
|
|
|
|
|
for emb in self.target_faces:
|
|
if self.findCosineDistance(emb['Embedding'], face[1]) >= threshhold:
|
|
found = True
|
|
break
|
|
|
|
|
|
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("<MouseWheel>", 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
|
|
|
|
|
|
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))
|
|
|
|
|
|
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")
|
|
|
|
|
|
def toggle_found_faces_buttons_state(self, button):
|
|
|
|
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)
|
|
|
|
|
|
self.target_faces[button]["ButtonState"] = True
|
|
self.target_faces[button]["TKButton"].config(style.media_button_on_3)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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 modifier != 'auto':
|
|
for face in self.source_faces:
|
|
face["TKButton"].config(style.media_button_off_3)
|
|
|
|
|
|
if modifier == 'none':
|
|
face["ButtonState"] = False
|
|
|
|
|
|
if modifier != 'merge':
|
|
self.source_faces[button]["ButtonState"] = not self.source_faces[button]["ButtonState"]
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
for tface in self.target_faces:
|
|
if tface["ButtonState"]:
|
|
|
|
|
|
tface["SourceFaceAssignments"] = []
|
|
|
|
|
|
temp_holder = []
|
|
for j in range(len(self.source_faces)):
|
|
|
|
|
|
if self.source_faces[j]["ButtonState"]:
|
|
tface["SourceFaceAssignments"].append(j)
|
|
temp_holder.append(self.source_faces[j]['Embedding'])
|
|
|
|
|
|
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']
|
|
|
|
|
|
|
|
break
|
|
|
|
self.add_action("target_faces", self.target_faces)
|
|
self.add_action('get_requested_video_frame', self.video_slider.get())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def populate_target_videos(self):
|
|
|
|
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:
|
|
|
|
try:
|
|
file_type = mimetypes.guess_type(file)[0][:5]
|
|
except:
|
|
print('Unrecognized file type:', file)
|
|
else:
|
|
|
|
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])
|
|
|
|
|
|
elif file_type == 'video':
|
|
try:
|
|
video = cv2.VideoCapture(file)
|
|
except:
|
|
print('Trouble reading file:', file)
|
|
else:
|
|
if video.isOpened():
|
|
|
|
|
|
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':
|
|
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("<MouseWheel>", 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':
|
|
|
|
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("<MouseWheel>", 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):
|
|
|
|
|
|
self.find_faces()
|
|
self.target_faces[0]["ButtonState"] = True
|
|
self.target_faces[0]["TKButton"].config(style.media_button_on_3)
|
|
|
|
|
|
self.select_input_faces('auto', '')
|
|
self.toggle_swapper(True)
|
|
|
|
|
|
def toggle_auto_swap(self):
|
|
self.widget['AutoSwapButton'].toggle_button()
|
|
|
|
|
|
def load_target(self, button, media_file, media_type):
|
|
|
|
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
|
|
|
|
|
|
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)
|
|
|
|
|
|
self.layer['markers_canvas'].delete('all')
|
|
self.markers = []
|
|
self.stop_marker = []
|
|
|
|
|
|
|
|
self.load_markers_json()
|
|
self.add_action("update_markers_canvas", self.markers)
|
|
|
|
|
|
|
|
self.add_action("markers", self.markers)
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
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):
|
|
|
|
|
|
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])
|
|
|
|
|
|
if self.winfo_geometry() != win_geom:
|
|
|
|
self.resize_image()
|
|
for k, v in self.widget.items():
|
|
v.hide()
|
|
for k, v in self.static_widget.items():
|
|
v.hide()
|
|
|
|
|
|
|
|
if self.winfo_geometry() != self.window_last_change:
|
|
self.window_last_change = self.winfo_geometry()
|
|
|
|
|
|
else:
|
|
for k, v in self.widget.items():
|
|
v.unhide()
|
|
for k, v in self.static_widget.items():
|
|
v.unhide()
|
|
|
|
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))
|
|
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:
|
|
|
|
|
|
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 self.widget['TLPlayButton'].get():
|
|
if not self.video_loaded:
|
|
print("Please select video first!")
|
|
return
|
|
else:
|
|
|
|
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")
|
|
|
|
|
|
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):
|
|
|
|
|
|
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):
|
|
|
|
|
|
|
|
|
|
self.save_markers_json()
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
def add_action(self, action, parameter=None):
|
|
|
|
|
|
if action != 'get_requested_video_frame' and action != 'get_requested_video_frame_without_markers':
|
|
self.action_q.append([action, parameter])
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
def save_selected_source_faces(self, text):
|
|
|
|
text = text.get()
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
def delete_merged_embedding(self):
|
|
|
|
|
|
sel = []
|
|
for j in range(len(self.source_faces)):
|
|
if self.source_faces[j]["ButtonState"]:
|
|
sel = j
|
|
break
|
|
|
|
|
|
|
|
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 i<len(self.source_faces)-1:
|
|
self.select_input_faces('none', i+1)
|
|
break
|
|
elif event.delta<0:
|
|
for i in range(len(self.source_faces)):
|
|
if self.source_faces[i]["ButtonState"]and i>0:
|
|
self.select_input_faces('none', i-1)
|
|
break
|
|
|
|
def set_view(self, load_target_videos,b):
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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':
|
|
|
|
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=='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'])
|
|
|
|
|
|
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')
|
|
|
|
|
|
|
|
|
|
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")
|
|
|
|
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):
|
|
|
|
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')
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
|
def parameter_update_from_marker(self, frame):
|
|
|
|
|
|
temp=[]
|
|
|
|
for i in range(len(self.markers)):
|
|
temp.append(self.markers[i]['frame'])
|
|
|
|
idx = bisect.bisect(temp, frame)
|
|
|
|
if idx>0:
|
|
|
|
self.parameters = copy.deepcopy(self.markers[idx-1]['parameters'])
|
|
|
|
|
|
for key, value in self.parameters.items():
|
|
self.widget[key].set(self.parameters[key], request_frame=False)
|
|
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
self.parameters = json.load(load_file)
|
|
load_file.close()
|
|
|
|
|
|
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':
|
|
|
|
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))
|
|
|
|
print(np.dot(vector1, vector2))
|
|
|
|
return cos_dist |