1
0
Fork 0
mirror of https://github.com/deepfakes/faceswap synced 2025-06-07 19:05:02 -04:00
faceswap/lib/gui/command.py
torzdf e76ab16bfe
Effmpeg preview, MTCNN Extractor. HiRes model fixes (#458)
* Add preview functionality to effmpeg.  (#435)

* Add preview functionality to effmpeg.

effmpeg tool:
Preview for actions that have a video output now available.
Preview does not work when muxing audio.

* Model json unicode fix1 (#443)

* fixed Windows 10 path error while loading weights

* - fixed TypeError: the JSON object must be str, not 'bytes' with OriginalHighRes Model

* MTCNN Extractor and Extraction refactor (#453)

* implement mtcnn extractor

* mtcnn refactor and vram management changes

* cli arguments update for mtcnn/dlib split

* Add mtcnn models to gitignore

* Change multiprocessing on extract

* GUI changes to handle nargs defaults

* Early exit bugfix (#455)

* Fix extract early termination bug

* Fix extract early exit bug

* Multi face detection bugfix (#456)

* Multi face extraction fix

* Original high res cleanup 1 (#457)

* slight model re-factoring
  - removed excess threading code
  - added random kernel initialization to dense layer

* Slight OriginalHighRes re-factoring an code cleanup
2018-07-03 10:42:58 +02:00

363 lines
14 KiB
Python

#!/usr/bin python3
""" The command frame for Faceswap GUI """
import tkinter as tk
from tkinter import ttk
from .options import Config
from .tooltip import Tooltip
from .utils import Images, FileHandler
class CommandNotebook(ttk.Notebook):
""" Frame to hold each individual tab of the command notebook """
def __init__(self, parent, cli_options, tk_vars, scaling_factor):
width = int(420 * scaling_factor)
height = int(500 * scaling_factor)
ttk.Notebook.__init__(self, parent, width=width, height=height)
parent.add(self)
self.cli_opts = cli_options
self.tk_vars = tk_vars
self.actionbtns = dict()
self.set_running_task_trace()
self.build_tabs()
def set_running_task_trace(self):
""" Set trigger action for the running task
to change the action buttons text and command """
self.tk_vars["runningtask"].trace("w", self.change_action_button)
def build_tabs(self):
""" Build the tabs for the relevant command """
for category in self.cli_opts.categories:
cmdlist = self.cli_opts.commands[category]
for command in cmdlist:
title = command.title()
commandtab = CommandTab(self, category, command)
self.add(commandtab, text=title)
def change_action_button(self, *args):
""" Change the action button to relevant control """
for cmd in self.actionbtns.keys():
btnact = self.actionbtns[cmd]
if self.tk_vars["runningtask"].get():
ttl = "Terminate"
hlp = "Exit the running process"
else:
ttl = cmd.title()
hlp = "Run the {} script".format(cmd.title())
btnact.config(text=ttl)
Tooltip(btnact, text=hlp, wraplength=200)
class CommandTab(ttk.Frame):
""" Frame to hold each individual tab of the command notebook """
def __init__(self, parent, category, command):
ttk.Frame.__init__(self, parent)
self.category = category
self.cli_opts = parent.cli_opts
self.actionbtns = parent.actionbtns
self.tk_vars = parent.tk_vars
self.command = command
self.build_tab()
def build_tab(self):
""" Build the tab """
OptionsFrame(self)
self.add_frame_separator()
ActionFrame(self)
def add_frame_separator(self):
""" Add a separator between top and bottom frames """
sep = ttk.Frame(self, height=2, relief=tk.RIDGE)
sep.pack(fill=tk.X, pady=(5, 0), side=tk.TOP)
class OptionsFrame(ttk.Frame):
""" Options Frame - Holds the Options for each command """
def __init__(self, parent):
ttk.Frame.__init__(self, parent)
self.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
self.opts = parent.cli_opts
self.command = parent.command
self.canvas = tk.Canvas(self, bd=0, highlightthickness=0)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.optsframe = ttk.Frame(self.canvas)
self.optscanvas = self.canvas.create_window((0, 0),
window=self.optsframe,
anchor=tk.NW)
self.chkbtns = self.checkbuttons_frame()
self.build_frame()
self.opts.set_context_option(self.command)
def checkbuttons_frame(self):
""" Build and format frame for holding the check buttons """
container = ttk.Frame(self.optsframe)
lbl = ttk.Label(container, text="Options", width=16, anchor=tk.W)
lbl.pack(padx=5, pady=5, side=tk.LEFT, anchor=tk.N)
chkframe = ttk.Frame(container)
chkframe.pack(side=tk.BOTTOM, expand=True)
chkleft = ttk.Frame(chkframe, name="leftFrame")
chkleft.pack(side=tk.LEFT, anchor=tk.N, expand=True)
chkright = ttk.Frame(chkframe, name="rightFrame")
chkright.pack(side=tk.RIGHT, anchor=tk.N, expand=True)
return container, chkframe
def build_frame(self):
""" Build the options frame for this command """
self.add_scrollbar()
self.canvas.bind("<Configure>", self.resize_frame)
for option in self.opts.gen_command_options(self.command):
optioncontrol = OptionControl(self.command,
option,
self.optsframe,
self.chkbtns[1])
optioncontrol.build_full_control()
if self.chkbtns[1].winfo_children():
self.chkbtns[0].pack(side=tk.BOTTOM, fill=tk.X, expand=True)
def add_scrollbar(self):
""" Add a scrollbar to the options frame """
scrollbar = ttk.Scrollbar(self, command=self.canvas.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.canvas.config(yscrollcommand=scrollbar.set)
self.optsframe.bind("<Configure>", self.update_scrollbar)
def update_scrollbar(self, event):
""" Update the options frame scrollbar """
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def resize_frame(self, event):
""" Resize the options frame to fit the canvas """
canvas_width = event.width
self.canvas.itemconfig(self.optscanvas, width=canvas_width)
class OptionControl(object):
""" Build the correct control for the option parsed and place it on the
frame """
def __init__(self, command, option, option_frame, checkbuttons_frame):
self.command = command
self.option = option
self.option_frame = option_frame
self.chkbtns = checkbuttons_frame
def build_full_control(self):
""" Build the correct control type for the option passed through """
ctl = self.option["control"]
ctltitle = self.option["control_title"]
sysbrowser = self.option["filesystem_browser"]
ctlhelp = " ".join(self.option.get("help", "").split())
ctlhelp = ". ".join(i.capitalize() for i in ctlhelp.split(". "))
ctlhelp = ctltitle + " - " + ctlhelp
dflt = self.option.get("default", "")
if self.option.get("nargs", None) and isinstance(dflt, (list, tuple)):
dflt = ' '.join(str(val) for val in dflt)
if ctl == ttk.Checkbutton:
dflt = self.option.get("default", False)
choices = self.option["choices"] if ctl == ttk.Combobox else None
ctlframe = self.build_one_control_frame()
if ctl != ttk.Checkbutton:
self.build_one_control_label(ctlframe, ctltitle)
ctlvars = (ctl, ctltitle, dflt, ctlhelp)
self.option["value"] = self.build_one_control(ctlframe,
ctlvars,
choices,
sysbrowser)
def build_one_control_frame(self):
""" Build the frame to hold the control """
frame = ttk.Frame(self.option_frame)
frame.pack(fill=tk.X, expand=True)
return frame
@staticmethod
def build_one_control_label(frame, control_title):
""" Build and place the control label """
lbl = ttk.Label(frame, text=control_title, width=16, anchor=tk.W)
lbl.pack(padx=5, pady=5, side=tk.LEFT, anchor=tk.N)
def build_one_control(self, frame, controlvars, choices, sysbrowser):
""" Build and place the option controls """
control, control_title, default, helptext = controlvars
default = default if default is not None else ""
var = tk.BooleanVar(
frame) if control == ttk.Checkbutton else tk.StringVar(frame)
var.set(default)
if sysbrowser is not None:
self.add_browser_buttons(frame, sysbrowser, var)
if control == ttk.Checkbutton:
self.checkbutton_to_checkframe(control,
control_title,
var,
helptext)
else:
self.control_to_optionsframe(control,
frame,
var,
choices,
helptext)
return var
def checkbutton_to_checkframe(self, control, control_title, var, helptext):
""" Add checkbuttons to the checkbutton frame """
leftframe = self.chkbtns.children["leftFrame"]
rightframe = self.chkbtns.children["rightFrame"]
chkbtn_count = len({**leftframe.children, **rightframe.children})
frame = leftframe if chkbtn_count % 2 == 0 else rightframe
ctl = control(frame, variable=var, text=control_title)
ctl.pack(side=tk.TOP, padx=5, pady=5, anchor=tk.W)
Tooltip(ctl, text=helptext, wraplength=200)
@staticmethod
def control_to_optionsframe(control, frame, var, choices, helptext):
""" Standard non-check buttons sit in the main options frame """
ctl = control(frame, textvariable=var)
ctl.pack(padx=5, pady=5, fill=tk.X, expand=True)
if control == ttk.Combobox:
ctl["values"] = [choice for choice in choices]
Tooltip(ctl, text=helptext, wraplength=200)
def add_browser_buttons(self, frame, sysbrowser, filepath):
""" Add correct file browser button for control """
img = Images().icons[sysbrowser]
action = getattr(self, "ask_" + sysbrowser)
filetypes = self.option.get("filetypes", "default")
fileopn = ttk.Button(frame, image=img,
command=lambda cmd=action: cmd(filepath,
filetypes))
fileopn.pack(padx=(0, 5), side=tk.RIGHT)
@staticmethod
def ask_folder(filepath, filetypes=None):
""" Pop-up to get path to a directory
:param filepath: tkinter StringVar object
that will store the path to a directory.
:param filetypes: Unused argument to allow
filetypes to be given in ask_load(). """
dirname = FileHandler("dir", filetypes).retfile
if dirname:
filepath.set(dirname)
@staticmethod
def ask_load(filepath, filetypes):
""" Pop-up to get path to a file """
filename = FileHandler("filename", filetypes).retfile
if filename:
filepath.set(filename)
@staticmethod
def ask_save(filepath, filetypes=None):
""" Pop-up to get path to save a new file """
filename = FileHandler("savefilename", filetypes).retfile
if filename:
filepath.set(filename)
@staticmethod
def ask_nothing(filepath, filetypes=None):
""" Method that does nothing, used for disabling open/save pop up """
return
def ask_context(self, filepath, filetypes):
""" Method to pop the correct dialog depending on context """
selected_action = self.option["action_option"].get()
selected_variable = self.option["dest"]
filename = FileHandler("context",
filetypes,
command=self.command,
action=selected_action,
variable=selected_variable).retfile
if filename:
filepath.set(filename)
class ActionFrame(ttk.Frame):
"""Action Frame - Displays action controls for the command tab """
def __init__(self, parent):
ttk.Frame.__init__(self, parent)
self.pack(fill=tk.BOTH, padx=5, pady=5, side=tk.BOTTOM, anchor=tk.N)
self.command = parent.command
self.title = self.command.title()
self.add_action_button(parent.category,
parent.actionbtns,
parent.tk_vars)
self.add_util_buttons(parent.cli_opts, parent.tk_vars)
def add_action_button(self, category, actionbtns, tk_vars):
""" Add the action buttons for page """
actframe = ttk.Frame(self)
actframe.pack(fill=tk.X, side=tk.LEFT)
var_value = "{},{}".format(category, self.command)
btnact = ttk.Button(actframe,
text=self.title,
width=10,
command=lambda: tk_vars["action"].set(var_value))
btnact.pack(side=tk.LEFT)
Tooltip(btnact,
text="Run the {} script".format(self.title),
wraplength=200)
actionbtns[self.command] = btnact
btngen = ttk.Button(actframe,
text="Generate",
width=10,
command=lambda: tk_vars["generate"].set(var_value))
btngen.pack(side=tk.RIGHT, padx=5)
Tooltip(btngen,
text="Output command line options to the console",
wraplength=200)
def add_util_buttons(self, cli_options, tk_vars):
""" Add the section utility buttons """
utlframe = ttk.Frame(self)
utlframe.pack(side=tk.RIGHT)
config = Config(cli_options, tk_vars)
for utl in ("load", "save", "clear", "reset"):
img = Images().icons[utl]
action_cls = config if utl in (("save", "load")) else cli_options
action = getattr(action_cls, utl)
btnutl = ttk.Button(utlframe,
image=img,
command=lambda cmd=action: cmd(self.command))
btnutl.pack(padx=2, side=tk.LEFT)
Tooltip(btnutl,
text=utl.capitalize() + " " + self.title + " config",
wraplength=200)