roop_unleashed01 / ui /tabs /facemgr_tab.py
Boka73's picture
upload 58 files
e20a9b5 verified
import os
import shutil
import cv2
import gradio as gr
import roop.utilities as util
import roop.globals
from roop.face_util import extract_face_images
from roop.capturer import get_video_frame, get_video_frame_total
from typing import List, Tuple, Optional
from roop.typing import Frame, Face, FaceSet
selected_face_index = -1
thumbs = []
images = []
def facemgr_tab() -> None:
with gr.Tab("πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦ Face Management"):
with gr.Row():
gr.Markdown("""
# Create blending facesets
Add multiple reference images into a faceset file.
""")
with gr.Row():
videoimagefst = gr.Image(
label="Cut face from video frame",
height=576,
interactive=False,
visible=True,
format="jpeg",
)
with gr.Row():
frame_num_fst = gr.Slider(
1,
1,
value=1,
label="Frame Number",
info="0:00:00",
step=1.0,
interactive=False,
)
fb_cutfromframe = gr.Button(
"Use faces from this frame", variant="secondary", interactive=False
)
with gr.Row():
fb_facesetfile = gr.Files(
label="Faceset",
file_count="single",
file_types=[".fsz"],
interactive=True,
)
fb_files = gr.Files(
label="Input Files",
file_count="multiple",
file_types=["image", "video"],
interactive=True,
)
with gr.Row():
with gr.Column():
gr.Button("πŸ‘€ Open Output Folder", size="sm").click(
fn=lambda: util.open_folder(roop.globals.output_path)
)
with gr.Column():
gr.Markdown(" ")
with gr.Row():
faces = gr.Gallery(
label="Faces in this Faceset",
allow_preview=True,
preview=True,
height=128,
object_fit="scale-down",
)
with gr.Row():
fb_remove = gr.Button("Remove selected", variant="secondary")
fb_update = gr.Button("Create/Update Faceset file", variant="primary")
fb_clear = gr.Button("Clear all", variant="stop")
fb_facesetfile.change(
fn=on_faceset_changed, inputs=[fb_facesetfile], outputs=[faces]
)
fb_files.change(
fn=on_fb_files_changed,
inputs=[fb_files],
outputs=[faces, videoimagefst, frame_num_fst, fb_cutfromframe],
)
fb_update.click(fn=on_update_clicked, outputs=[fb_facesetfile])
fb_remove.click(fn=on_remove_clicked, outputs=[faces])
fb_clear.click(fn=on_clear_clicked, outputs=[faces, fb_files, fb_facesetfile])
fb_cutfromframe.click(
fn=on_cutfromframe_clicked, inputs=[fb_files, frame_num_fst], outputs=[faces]
)
frame_num_fst.release(
fn=on_frame_num_fst_changed,
inputs=[fb_files, frame_num_fst],
outputs=[videoimagefst],
)
faces.select(fn=on_face_selected)
def on_faceset_changed(faceset, progress=gr.Progress()) -> List[Frame]:
global thumbs, images
if faceset is None:
return thumbs
thumbs.clear()
filename = faceset.name
if filename.lower().endswith("fsz"):
progress(
0,
desc="Retrieving faces from Faceset File",
)
unzipfolder = os.path.join(os.environ["TEMP"], "faceset")
if os.path.isdir(unzipfolder):
shutil.rmtree(unzipfolder)
util.mkdir_with_umask(unzipfolder)
util.unzip(filename, unzipfolder)
for file in os.listdir(unzipfolder):
if file.endswith(".png"):
SELECTION_FACES_DATA = extract_face_images(
os.path.join(unzipfolder, file), (False, 0), 0.5
)
if len(SELECTION_FACES_DATA) < 1:
gr.Warning(f"No face detected in {file}!")
for f in SELECTION_FACES_DATA:
image = f[1]
images.append(image)
thumbs.append(util.convert_to_gradio(image))
return thumbs
def on_fb_files_changed(
inputfiles, progress=gr.Progress()
) -> Tuple[List[Frame], Optional[gr.Image], Optional[gr.Slider], Optional[gr.Button]]:
global thumbs, images, total_frames, current_video_fps
if inputfiles is None or len(inputfiles) < 1:
return thumbs, None, None, None
progress(
0,
desc="Retrieving faces from images",
)
slider = None
video_image = None
cut_button = None
for f in inputfiles:
source_path = f.name
if util.has_image_extension(source_path):
slider = gr.Slider(interactive=False)
video_image = gr.Image(interactive=False)
cut_button = gr.Button(interactive=False)
roop.globals.source_path = source_path
SELECTION_FACES_DATA = extract_face_images(
roop.globals.source_path, (False, 0), 0.5
)
for f in SELECTION_FACES_DATA:
image = f[1]
images.append(image)
thumbs.append(util.convert_to_gradio(image))
elif util.is_video(source_path) or source_path.lower().endswith("gif"):
total_frames = get_video_frame_total(source_path)
current_video_fps = util.detect_fps(source_path)
cut_button = gr.Button(interactive=True)
video_image, slider = display_video_frame(source_path, 1, total_frames)
return thumbs, video_image, slider, cut_button
def display_video_frame(
filename: str, frame_num: int, total: int = 0
) -> Tuple[gr.Image, gr.Slider]:
global current_video_fps
current_frame = get_video_frame(filename, frame_num)
if current_video_fps == 0:
current_video_fps = 1
secs = (frame_num - 1) / current_video_fps
minutes = secs / 60
secs = secs % 60
hours = minutes / 60
minutes = minutes % 60
milliseconds = (secs - int(secs)) * 1000
timeinfo = (
f"{int(hours):0>2}:{int(minutes):0>2}:{int(secs):0>2}.{int(milliseconds):0>3}"
)
if total > 0:
return gr.Image(
value=util.convert_to_gradio(current_frame), interactive=True
), gr.Slider(info=timeinfo, minimum=1, maximum=total, interactive=True)
return gr.Image(
value=util.convert_to_gradio(current_frame), interactive=True
), gr.Slider(info=timeinfo, interactive=True)
def on_face_selected(evt: gr.SelectData) -> None:
global selected_face_index
if evt is not None:
selected_face_index = evt.index
def on_frame_num_fst_changed(inputfiles: List[gr.Files], frame_num: int) -> Frame:
filename = inputfiles[0].name
video_image, _ = display_video_frame(filename, frame_num, 0)
return video_image
def on_cutfromframe_clicked(inputfiles: List[gr.Files], frame_num: int) -> List[Frame]:
global thumbs
filename = inputfiles[0].name
SELECTION_FACES_DATA = extract_face_images(filename, (True, frame_num), 0.5)
for f in SELECTION_FACES_DATA:
image = f[1]
images.append(image)
thumbs.append(util.convert_to_gradio(image))
return thumbs
def on_remove_clicked() -> List[Frame]:
global thumbs, images, selected_face_index
if len(thumbs) > selected_face_index:
f = thumbs.pop(selected_face_index)
del f
f = images.pop(selected_face_index)
del f
return thumbs
def on_clear_clicked() -> Tuple[List[Frame], None, None]:
global thumbs, images
thumbs.clear()
images.clear()
return thumbs, None, None
def on_update_clicked() -> Optional[str]:
if len(images) < 1:
gr.Warning(f"No faces to create faceset from!")
return None
imgnames = []
for index, img in enumerate(images):
filename = os.path.join(roop.globals.output_path, f"{index}.png")
cv2.imwrite(filename, img)
imgnames.append(filename)
finalzip = os.path.join(roop.globals.output_path, "faceset.fsz")
util.zip(imgnames, finalzip)
return finalzip