Spaces:
Runtime error
Runtime error
| 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 | |