@ -20,13 +20,16 @@ from scripts.faceswaplab_utils.imgutils import pil_to_cv2
from scripts . faceswaplab_utils . models_utils import get_models
from scripts . faceswaplab_utils . models_utils import get_models
from scripts . faceswaplab_utils . faceswaplab_logging import logger
from scripts . faceswaplab_utils . faceswaplab_logging import logger
import scripts . faceswaplab_swapping . swapper as swapper
import scripts . faceswaplab_swapping . swapper as swapper
from scripts . faceswaplab_postprocessing . postprocessing_options import PostProcessingOptions
from scripts . faceswaplab_postprocessing . postprocessing_options import (
PostProcessingOptions ,
)
from scripts . faceswaplab_postprocessing . postprocessing import enhance_image
from scripts . faceswaplab_postprocessing . postprocessing import enhance_image
from dataclasses import fields
from dataclasses import fields
from typing import List
from typing import List
from scripts . faceswaplab_ui . faceswaplab_unit_settings import FaceSwapUnitSettings
from scripts . faceswaplab_ui . faceswaplab_unit_settings import FaceSwapUnitSettings
from scripts . faceswaplab_utils . models_utils import get_current_model
from scripts . faceswaplab_utils . models_utils import get_current_model
def compare ( img1 , img2 ) :
def compare ( img1 , img2 ) :
if img1 is not None and img2 is not None :
if img1 is not None and img2 is not None :
return swapper . compare_faces ( img1 , img2 )
return swapper . compare_faces ( img1 , img2 )
@ -34,8 +37,22 @@ def compare(img1, img2):
return " You need 2 images to compare "
return " You need 2 images to compare "
def extract_faces (
def extract_faces ( files , extract_path , face_restorer_name , face_restorer_visibility , codeformer_weight , upscaler_name , upscaler_scale , upscaler_visibility , inpainting_denoising_strengh , inpainting_prompt , inpainting_negative_prompt , inpainting_steps , inpainting_sampler , inpainting_when ) :
files ,
extract_path ,
face_restorer_name ,
face_restorer_visibility ,
codeformer_weight ,
upscaler_name ,
upscaler_scale ,
upscaler_visibility ,
inpainting_denoising_strengh ,
inpainting_prompt ,
inpainting_negative_prompt ,
inpainting_steps ,
inpainting_sampler ,
inpainting_when ,
) :
if not extract_path :
if not extract_path :
tempfile . mkdtemp ( )
tempfile . mkdtemp ( )
if files is not None :
if files is not None :
@ -51,7 +68,10 @@ def extract_faces(files, extract_path, face_restorer_name, face_restorer_visibi
face_image = img . crop ( ( x_min , y_min , x_max , y_max ) )
face_image = img . crop ( ( x_min , y_min , x_max , y_max ) )
if face_restorer_name or face_restorer_visibility :
if face_restorer_name or face_restorer_visibility :
scale = 1 if face_image . width > 512 else 512 / / face_image . width
scale = 1 if face_image . width > 512 else 512 / / face_image . width
face_image = enhance_image ( face_image , PostProcessingOptions ( face_restorer_name = face_restorer_name ,
face_image = enhance_image (
face_image ,
PostProcessingOptions (
face_restorer_name = face_restorer_name ,
restorer_visibility = face_restorer_visibility ,
restorer_visibility = face_restorer_visibility ,
codeformer_weight = codeformer_weight ,
codeformer_weight = codeformer_weight ,
upscaler_name = upscaler_name ,
upscaler_name = upscaler_name ,
@ -62,14 +82,19 @@ def extract_faces(files, extract_path, face_restorer_name, face_restorer_visibi
inpainting_steps = inpainting_steps ,
inpainting_steps = inpainting_steps ,
inpainting_negative_prompt = inpainting_negative_prompt ,
inpainting_negative_prompt = inpainting_negative_prompt ,
inpainting_when = inpainting_when ,
inpainting_when = inpainting_when ,
inpainting_sampler = inpainting_sampler ) )
inpainting_sampler = inpainting_sampler ,
path = tempfile . NamedTemporaryFile ( delete = False , suffix = " .png " , dir = extract_path ) . name
) ,
)
path = tempfile . NamedTemporaryFile (
delete = False , suffix = " .png " , dir = extract_path
) . name
face_image . save ( path )
face_image . save ( path )
face_images . append ( path )
face_images . append ( path )
images + = face_images
images + = face_images
return images
return images
return None
return None
def analyse_faces ( image , det_threshold = 0.5 ) :
def analyse_faces ( image , det_threshold = 0.5 ) :
try :
try :
faces = swapper . get_faces ( imgutils . pil_to_cv2 ( image ) , det_thresh = det_threshold )
faces = swapper . get_faces ( imgutils . pil_to_cv2 ( image ) , det_thresh = det_threshold )
@ -84,6 +109,7 @@ def analyse_faces(image, det_threshold = 0.5) :
logger . error ( " Analysis Failed : %s " , e )
logger . error ( " Analysis Failed : %s " , e )
return " Analysis Failed "
return " Analysis Failed "
def build_face_checkpoint_and_save ( batch_files , name ) :
def build_face_checkpoint_and_save ( batch_files , name ) :
"""
"""
Builds a face checkpoint , swaps faces , and saves the result to a file .
Builds a face checkpoint , swaps faces , and saves the result to a file .
@ -116,8 +142,15 @@ def build_face_checkpoint_and_save(batch_files, name):
if name == " " :
if name == " " :
name = " default_name "
name = " default_name "
pprint ( blended_face )
pprint ( blended_face )
result = swapper . swap_face ( blended_face , blended_face , target_img , get_models ( ) [ 0 ] )
result = swapper . swap_face (
result_image = enhance_image ( result . image , PostProcessingOptions ( face_restorer_name = " CodeFormer " , restorer_visibility = 1 ) )
blended_face , blended_face , target_img , get_models ( ) [ 0 ]
)
result_image = enhance_image (
result . image ,
PostProcessingOptions (
face_restorer_name = " CodeFormer " , restorer_visibility = 1
) ,
)
file_path = os . path . join ( faces_path , f " { name } .pkl " )
file_path = os . path . join ( faces_path , f " { name } .pkl " )
file_number = 1
file_number = 1
@ -126,7 +159,14 @@ def build_face_checkpoint_and_save(batch_files, name):
file_number + = 1
file_number + = 1
result_image . save ( file_path + " .png " )
result_image . save ( file_path + " .png " )
with open ( file_path , " wb " ) as file :
with open ( file_path , " wb " ) as file :
pickle . dump ( { " embedding " : blended_face . embedding , " gender " : blended_face . gender , " age " : blended_face . age } , file )
pickle . dump (
{
" embedding " : blended_face . embedding ,
" gender " : blended_face . gender ,
" age " : blended_face . age ,
} ,
file ,
)
try :
try :
with open ( file_path , " rb " ) as file :
with open ( file_path , " rb " ) as file :
data = Face ( pickle . load ( file ) )
data = Face ( pickle . load ( file ) )
@ -139,31 +179,35 @@ def build_face_checkpoint_and_save(batch_files, name):
return target_img
return target_img
def explore_onnx_faceswap_model ( model_path ) :
def explore_onnx_faceswap_model ( model_path ) :
data = {
data = {
' Node Name ' : [ ] ,
" Node Name " : [ ] ,
' Op Type ' : [ ] ,
" Op Type " : [ ] ,
' Inputs ' : [ ] ,
" Inputs " : [ ] ,
' Outputs ' : [ ] ,
" Outputs " : [ ] ,
' Attributes ' : [ ]
" Attributes " : [ ] ,
}
}
if model_path :
if model_path :
model = onnx . load ( model_path )
model = onnx . load ( model_path )
for node in model . graph . node :
for node in model . graph . node :
data [ ' Node Name ' ] . append ( pformat ( node . name ) )
data [ " Node Name " ] . append ( pformat ( node . name ) )
data [ ' Op Type ' ] . append ( pformat ( node . op_type ) )
data [ " Op Type " ] . append ( pformat ( node . op_type ) )
data [ ' Inputs ' ] . append ( pformat ( node . input ) )
data [ " Inputs " ] . append ( pformat ( node . input ) )
data [ ' Outputs ' ] . append ( pformat ( node . output ) )
data [ " Outputs " ] . append ( pformat ( node . output ) )
attributes = [ ]
attributes = [ ]
for attr in node . attribute :
for attr in node . attribute :
attr_name = attr . name
attr_name = attr . name
attr_value = attr . t
attr_value = attr . t
attributes . append ( " {} = {} " . format ( pformat ( attr_name ) , pformat ( attr_value ) ) )
attributes . append (
data [ ' Attributes ' ] . append ( attributes )
" {} = {} " . format ( pformat ( attr_name ) , pformat ( attr_value ) )
)
data [ " Attributes " ] . append ( attributes )
df = pd . DataFrame ( data )
df = pd . DataFrame ( data )
return df
return df
def batch_process ( files , save_path , * components ) :
def batch_process ( files , save_path , * components ) :
try :
try :
if save_path is not None :
if save_path is not None :
@ -194,7 +238,14 @@ def batch_process(files, save_path, *components):
for file in files :
for file in files :
current_images = [ ]
current_images = [ ]
src_image = Image . open ( file . name ) . convert ( " RGB " )
src_image = Image . open ( file . name ) . convert ( " RGB " )
swapped_images = swapper . process_images_units ( get_current_model ( ) , images = [ ( src_image , None ) ] , units = units , upscaled_swapper = opts . data . get ( " faceswaplab_upscaled_swapper " , False ) )
swapped_images = swapper . process_images_units (
get_current_model ( ) ,
images = [ ( src_image , None ) ] ,
units = units ,
upscaled_swapper = opts . data . get (
" faceswaplab_upscaled_swapper " , False
) ,
)
if len ( swapped_images ) > 0 :
if len ( swapped_images ) > 0 :
current_images + = [ img for img , info in swapped_images ]
current_images + = [ img for img , info in swapped_images ]
@ -203,7 +254,9 @@ def batch_process(files, save_path, *components):
current_images [ i ] = enhance_image ( img , postprocess_options )
current_images [ i ] = enhance_image ( img , postprocess_options )
for img in current_images :
for img in current_images :
path = tempfile . NamedTemporaryFile ( delete = False , suffix = " .png " , dir = save_path ) . name
path = tempfile . NamedTemporaryFile (
delete = False , suffix = " .png " , dir = save_path
) . name
img . save ( path )
img . save ( path )
images + = current_images
images + = current_images
@ -211,6 +264,7 @@ def batch_process(files, save_path, *components):
except Exception as e :
except Exception as e :
logger . error ( " Batch Process error : %s " , e )
logger . error ( " Batch Process error : %s " , e )
import traceback
import traceback
traceback . print_exc ( )
traceback . print_exc ( )
return None
return None
@ -220,107 +274,164 @@ def tools_ui():
with gr . Tab ( " Tools " ) :
with gr . Tab ( " Tools " ) :
with gr . Tab ( " Build " ) :
with gr . Tab ( " Build " ) :
gr . Markdown (
gr . Markdown (
""" Build a face based on a batch list of images. Will blend the resulting face and store the checkpoint in the faceswaplab/faces directory. """ )
""" Build a face based on a batch list of images. Will blend the resulting face and store the checkpoint in the faceswaplab/faces directory. """
)
with gr . Row ( ) :
with gr . Row ( ) :
batch_files = gr . components . File (
batch_files = gr . components . File (
type = " file " ,
type = " file " ,
file_count = " multiple " ,
file_count = " multiple " ,
label = " Batch Sources Images " ,
label = " Batch Sources Images " ,
optional = True ,
optional = True ,
elem_id = " faceswaplab_build_batch_files "
elem_id = " faceswaplab_build_batch_files " ,
)
preview = gr . components . Image (
type = " pil " ,
label = " Preview " ,
interactive = False ,
elem_id = " faceswaplab_build_preview_face " ,
)
)
preview = gr . components . Image ( type = " pil " , label = " Preview " , interactive = False , elem_id = " faceswaplab_build_preview_face " )
name = gr . Textbox (
name = gr . Textbox (
value = " Face " ,
value = " Face " ,
placeholder = " Name of the character " ,
placeholder = " Name of the character " ,
label = " Name of the character " ,
label = " Name of the character " ,
elem_id = " faceswaplab_build_character_name "
elem_id = " faceswaplab_build_character_name " ,
)
generate_checkpoint_btn = gr . Button (
" Save " , elem_id = " faceswaplab_build_save_btn "
)
)
generate_checkpoint_btn = gr . Button ( " Save " , elem_id = " faceswaplab_build_save_btn " )
with gr . Tab ( " Compare " ) :
with gr . Tab ( " Compare " ) :
gr . Markdown (
gr . Markdown (
""" Give a similarity score between two images (only first face is compared). """ )
""" Give a similarity score between two images (only first face is compared). """
)
with gr . Row ( ) :
with gr . Row ( ) :
img1 = gr . components . Image ( type = " pil " ,
img1 = gr . components . Image (
label = " Face 1 " ,
type = " pil " , label = " Face 1 " , elem_id = " faceswaplab_compare_face1 "
elem_id = " faceswaplab_compare_face1 "
)
)
img2 = gr . components . Image ( type = " pil " ,
img2 = gr . components . Image (
label = " Face 2 " ,
type = " pil " , label = " Face 2 " , elem_id = " faceswaplab_compare_face2 "
elem_id = " faceswaplab_compare_face2 "
)
)
compare_btn = gr . Button ( " Compare " , elem_id = " faceswaplab_compare_btn " )
compare_btn = gr . Button ( " Compare " , elem_id = " faceswaplab_compare_btn " )
compare_result_text = gr . Textbox (
compare_result_text = gr . Textbox (
interactive = False , label = " Similarity " , value = " 0 " , elem_id = " faceswaplab_compare_result "
interactive = False ,
label = " Similarity " ,
value = " 0 " ,
elem_id = " faceswaplab_compare_result " ,
)
)
with gr . Tab ( " Extract " ) :
with gr . Tab ( " Extract " ) :
gr . Markdown (
gr . Markdown (
""" Extract all faces from a batch of images. Will apply enhancement in the tools enhancement tab. """ )
""" Extract all faces from a batch of images. Will apply enhancement in the tools enhancement tab. """
)
with gr . Row ( ) :
with gr . Row ( ) :
extracted_source_files = gr . components . File (
extracted_source_files = gr . components . File (
type = " file " ,
type = " file " ,
file_count = " multiple " ,
file_count = " multiple " ,
label = " Batch Sources Images " ,
label = " Batch Sources Images " ,
optional = True ,
optional = True ,
elem_id = " faceswaplab_extract_batch_images "
elem_id = " faceswaplab_extract_batch_images " ,
)
)
extracted_faces = gr . Gallery (
extracted_faces = gr . Gallery (
label = " Extracted faces " , show_label = False ,
label = " Extracted faces " ,
elem_id = " faceswaplab_extract_results "
show_label = False ,
elem_id = " faceswaplab_extract_results " ,
) . style ( columns = [ 2 ] , rows = [ 2 ] )
) . style ( columns = [ 2 ] , rows = [ 2 ] )
extract_save_path = gr . Textbox ( label = " Destination Directory " , value = " " , elem_id = " faceswaplab_extract_destination " )
extract_save_path = gr . Textbox (
label = " Destination Directory " ,
value = " " ,
elem_id = " faceswaplab_extract_destination " ,
)
extract_btn = gr . Button ( " Extract " , elem_id = " faceswaplab_extract_btn " )
extract_btn = gr . Button ( " Extract " , elem_id = " faceswaplab_extract_btn " )
with gr . Tab ( " Explore Model " ) :
with gr . Tab ( " Explore Model " ) :
model = gr . Dropdown (
model = gr . Dropdown (
choices = models ,
choices = models ,
label = " Model not found, please download one and reload automatic 1111 " ,
label = " Model not found, please download one and reload automatic 1111 " ,
elem_id = " faceswaplab_explore_model "
elem_id = " faceswaplab_explore_model " ,
)
)
explore_btn = gr . Button ( " Explore " , elem_id = " faceswaplab_explore_btn " )
explore_btn = gr . Button ( " Explore " , elem_id = " faceswaplab_explore_btn " )
explore_result_text = gr . Dataframe (
explore_result_text = gr . Dataframe (
interactive = False , label = " Explored " ,
interactive = False ,
elem_id = " faceswaplab_explore_result "
label = " Explored " ,
elem_id = " faceswaplab_explore_result " ,
)
)
with gr . Tab ( " Analyse Face " ) :
with gr . Tab ( " Analyse Face " ) :
img_to_analyse = gr . components . Image ( type = " pil " , label = " Face " , elem_id = " faceswaplab_analyse_face " )
img_to_analyse = gr . components . Image (
analyse_det_threshold = gr . Slider ( 0.1 , 1 , 0.5 , step = 0.01 , label = " Detection threshold " , elem_id = " faceswaplab_analyse_det_threshold " )
type = " pil " , label = " Face " , elem_id = " faceswaplab_analyse_face "
)
analyse_det_threshold = gr . Slider (
0.1 ,
1 ,
0.5 ,
step = 0.01 ,
label = " Detection threshold " ,
elem_id = " faceswaplab_analyse_det_threshold " ,
)
analyse_btn = gr . Button ( " Analyse " , elem_id = " faceswaplab_analyse_btn " )
analyse_btn = gr . Button ( " Analyse " , elem_id = " faceswaplab_analyse_btn " )
analyse_results = gr . Textbox ( label = " Results " , interactive = False , value = " " , elem_id = " faceswaplab_analyse_results " )
analyse_results = gr . Textbox (
label = " Results " ,
interactive = False ,
value = " " ,
elem_id = " faceswaplab_analyse_results " ,
)
with gr . Tab ( " Batch Process " ) :
with gr . Tab ( " Batch Process " ) :
with gr . Tab ( " Source Images " ) :
with gr . Tab ( " Source Images " ) :
gr . Markdown (
gr . Markdown (
""" Batch process images. Will apply enhancement in the tools enhancement tab. """ )
""" Batch process images. Will apply enhancement in the tools enhancement tab. """
)
with gr . Row ( ) :
with gr . Row ( ) :
batch_source_files = gr . components . File (
batch_source_files = gr . components . File (
type = " file " ,
type = " file " ,
file_count = " multiple " ,
file_count = " multiple " ,
label = " Batch Sources Images " ,
label = " Batch Sources Images " ,
optional = True ,
optional = True ,
elem_id = " faceswaplab_batch_images "
elem_id = " faceswaplab_batch_images " ,
)
)
batch_results = gr . Gallery (
batch_results = gr . Gallery (
label = " Batch result " , show_label = False ,
label = " Batch result " ,
elem_id = " faceswaplab_batch_results "
show_label = False ,
elem_id = " faceswaplab_batch_results " ,
) . style ( columns = [ 2 ] , rows = [ 2 ] )
) . style ( columns = [ 2 ] , rows = [ 2 ] )
batch_save_path = gr . Textbox ( label = " Destination Directory " , value = " outputs/faceswap/ " , elem_id = " faceswaplab_batch_destination " )
batch_save_path = gr . Textbox (
batch_save_btn = gr . Button ( " Process & Save " , elem_id = " faceswaplab_extract_btn " )
label = " Destination Directory " ,
value = " outputs/faceswap/ " ,
elem_id = " faceswaplab_batch_destination " ,
)
batch_save_btn = gr . Button (
" Process & Save " , elem_id = " faceswaplab_extract_btn "
)
unit_components = [ ]
unit_components = [ ]
for i in range ( 1 , opts . data . get ( " faceswaplab_units_count " , 3 ) + 1 ) :
for i in range ( 1 , opts . data . get ( " faceswaplab_units_count " , 3 ) + 1 ) :
unit_components + = faceswap_unit_ui ( False , i , id_prefix = " faceswaplab_tab " )
unit_components + = faceswap_unit_ui ( False , i , id_prefix = " faceswaplab_tab " )
upscale_options = upscaler_ui ( )
upscale_options = upscaler_ui ( )
explore_btn . click ( explore_onnx_faceswap_model , inputs = [ model ] , outputs = [ explore_result_text ] )
explore_btn . click (
explore_onnx_faceswap_model , inputs = [ model ] , outputs = [ explore_result_text ]
)
compare_btn . click ( compare , inputs = [ img1 , img2 ] , outputs = [ compare_result_text ] )
compare_btn . click ( compare , inputs = [ img1 , img2 ] , outputs = [ compare_result_text ] )
generate_checkpoint_btn . click ( build_face_checkpoint_and_save , inputs = [ batch_files , name ] , outputs = [ preview ] )
generate_checkpoint_btn . click (
extract_btn . click ( extract_faces , inputs = [ extracted_source_files , extract_save_path ] + upscale_options , outputs = [ extracted_faces ] )
build_face_checkpoint_and_save , inputs = [ batch_files , name ] , outputs = [ preview ]
analyse_btn . click ( analyse_faces , inputs = [ img_to_analyse , analyse_det_threshold ] , outputs = [ analyse_results ] )
)
batch_save_btn . click ( batch_process , inputs = [ batch_source_files , batch_save_path ] + unit_components + upscale_options , outputs = [ batch_results ] )
extract_btn . click (
extract_faces ,
inputs = [ extracted_source_files , extract_save_path ] + upscale_options ,
outputs = [ extracted_faces ] ,
)
analyse_btn . click (
analyse_faces ,
inputs = [ img_to_analyse , analyse_det_threshold ] ,
outputs = [ analyse_results ] ,
)
batch_save_btn . click (
batch_process ,
inputs = [ batch_source_files , batch_save_path ]
+ unit_components
+ upscale_options ,
outputs = [ batch_results ] ,
)
def on_ui_tabs ( ) :
def on_ui_tabs ( ) :
with gr . Blocks ( analytics_enabled = False ) as ui_faceswap :
with gr . Blocks ( analytics_enabled = False ) as ui_faceswap :
tools_ui ( )
tools_ui ( )
return [ ( ui_faceswap , " FaceSwapLab " , " faceswaplab_tab " ) ]
return [ ( ui_faceswap , " FaceSwapLab " , " faceswaplab_tab " ) ]