mirror of
https://github.com/deepfakes/faceswap
synced 2025-06-08 11:53:26 -04:00
* Pre push commit. Add filetypes support to gui through new classes in lib/cli.py Add various new functions to tools/effmpeg.py * Finish developing basic effmpeg functionality. Ready for public alpha test. * Add ffmpy to requirements. Fix gen-vid to allow specifying a new file in GUI. Fix extract throwing an error when supplied with a valid directory. Add two new gui user pop interactions: save (allows you to create new files/directories) and nothing (disables the prompt button when it's not needed). Improve logic and argument processing in effmpeg. * Fix post merge bugs. Reformat tools.py to match the new style of faceswap.py Fix some whitespace issues. * Fix matplotlib.use() being called after pyplot was imported. * Fix various effmpeg bugs and add ability do terminate nested subprocess to GUI. effmpeg changes: Fix get-fps not printing to terminal. Fix mux-audio not working. Add verbosity option. If verbose is not specified than ffmpeg output is reduced with the -hide_banner flag. scripts/gui.py changes: Add ability to terminate nested subprocesses, i.e. the following type of process tree should now be terminated safely: gui -> command -> command-subprocess -> command-subprocess -> command-sub-subprocess * Add functionality to tools/effmpeg.py, fix some docstring and print statement issues in some files. tools/effmpeg.py: Transpose choices now display detailed name in GUI, while in cli they can still be entered as a number or the full command name. Add quiet option to effmpeg that only shows critical ffmpeg errors. Improve user input handling. lib/cli.py; scripts/convert.py; scripts/extract.py; scripts/train.py: Fix some line length issues and typos in docstrings, help text and print statements. Fix some whitespace issues. lib/cli.py: Add filetypes to '--alignments' argument. Change argument action to DirFullPaths where appropriate. * Bug fixes and improvements to tools/effmpeg.py Fix bug where duration would not be used even when end time was not set. Add option to specify output filetype for extraction. Enchance gen-vid to be able to generate a video from images that were zero padded to any arbitrary number, and not just 5. Enchance gen-vid to be able to use any of the image formats that a video can be extracted into. Improve gen-vid output video quality. Minor code quality improvements and ffmpeg argument formatting improvements. * Remove dependency on psutil in scripts/gui.py and various small improvements. lib/utils.py: Add _image_extensions and _video_extensions as global variables to make them easily portable across all of faceswap. Fix lack of new lines between function and class declarions to conform to PEP8. Fix some typos and line length issues in doctsrings and comments. scripts/convert.py: Make tqdm print to stdout. scripts/extract.py: Make tqdm print to stdout. Apply workaround for occasional TqdmSynchronisationWarning being thrown. Fix some typos and line length issues in doctsrings and comments. scripts/fsmedia.py: Did TODO in scripts/fsmedia.py in Faces.load_extractor(): TODO Pass extractor_name as argument Fix lack of new lines between function and class declarions to conform to PEP8. Fix some typos and line length issues in doctsrings and comments. Change 2 print statements to use format() for string formatting instead of the old '%'. scripts/gui.py: Refactor subprocess generation and termination to remove dependency on psutil. Fix some typos and line length issues in comments. tools/effmpeg.py Refactor DataItem class to use new lib/utils.py global media file extensions. Improve ffmpeg subprocess termination handling.
114 lines
4.5 KiB
Python
114 lines
4.5 KiB
Python
#!/usr/bin python3
|
|
""" The script to run the extract process of faceswap """
|
|
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from tqdm import tqdm
|
|
tqdm.monitor_interval = 0 # workaround for TqdmSynchronisationWarning
|
|
|
|
from lib.multithreading import pool_process
|
|
from scripts.fsmedia import Alignments, Faces, Images, Utils
|
|
|
|
|
|
class Extract(object):
|
|
""" The extract process. """
|
|
|
|
def __init__(self, arguments):
|
|
self.args = arguments
|
|
|
|
self.images = Images(self.args)
|
|
self.faces = Faces(self.args)
|
|
self.alignments = Alignments(self.args)
|
|
|
|
self.output_dir = self.faces.output_dir
|
|
|
|
self.export_face = True
|
|
|
|
def process(self):
|
|
""" Perform the extraction process """
|
|
print('Starting, this may take a while...')
|
|
Utils.set_verbosity(self.args.verbose)
|
|
|
|
if hasattr(self.args, 'processes') and self.args.processes > 1:
|
|
self.extract_multi_process()
|
|
else:
|
|
self.extract_single_process()
|
|
|
|
self.alignments.write_alignments(self.faces.faces_detected)
|
|
|
|
images, faces = Utils.finalize(self.images.images_found,
|
|
self.faces.num_faces_detected,
|
|
self.faces.verify_output)
|
|
self.images.images_found = images
|
|
self.faces.num_faces_detected = faces
|
|
|
|
def extract_single_process(self):
|
|
""" Run extraction in a single process """
|
|
for filename in tqdm(self.images.input_images, file=sys.stdout):
|
|
filename, faces = self.process_single_image(filename)
|
|
self.faces.faces_detected[os.path.basename(filename)] = faces
|
|
|
|
def extract_multi_process(self):
|
|
""" Run the extraction on the correct number of processes """
|
|
for filename, faces in tqdm(pool_process(self.process_single_image,
|
|
self.images.input_images,
|
|
processes=self.args.processes),
|
|
total=self.images.images_found,
|
|
file=sys.stdout):
|
|
self.faces.num_faces_detected += 1
|
|
self.faces.faces_detected[os.path.basename(filename)] = faces
|
|
|
|
def process_single_image(self, filename):
|
|
""" Detect faces in an image. Rotate the image the specified amount
|
|
until at least one face is found, or until image rotations are
|
|
depleted.
|
|
Once at least one face has been detected, pass to
|
|
process_single_face to process the individual faces """
|
|
retval = filename, list()
|
|
try:
|
|
image = Utils.cv2_read_write('read', filename)
|
|
|
|
for angle in self.images.rotation_angles:
|
|
currentimage = Utils.rotate_image_by_angle(image, angle)
|
|
faces = self.faces.get_faces(currentimage, angle)
|
|
process_faces = [(idx, face) for idx, face in faces]
|
|
if process_faces and angle != 0 and self.args.verbose:
|
|
print("found face(s) by rotating image {} degrees".format(angle))
|
|
if process_faces:
|
|
break
|
|
|
|
final_faces = [self.process_single_face(idx, face, filename, currentimage)
|
|
for idx, face in process_faces]
|
|
|
|
retval = filename, final_faces
|
|
except Exception as err:
|
|
if self.args.verbose:
|
|
print("Failed to extract from image: {}. Reason: {}".format(filename, err))
|
|
return retval
|
|
|
|
def process_single_face(self, idx, face, filename, image):
|
|
""" Perform processing on found faces """
|
|
output_file = self.output_dir / Path(filename).stem if self.export_face else None
|
|
|
|
self.faces.draw_landmarks_on_face(face, image)
|
|
|
|
resized_face, t_mat = self.faces.extractor.extract(image,
|
|
face,
|
|
256,
|
|
self.faces.align_eyes)
|
|
|
|
blurry_file = self.faces.detect_blurry_faces(face, t_mat, resized_face, filename)
|
|
output_file = blurry_file if blurry_file else output_file
|
|
|
|
if self.export_face:
|
|
filename = "{}_{}{}".format(str(output_file), str(idx), Path(filename).suffix)
|
|
Utils.cv2_read_write('write', filename, resized_face)
|
|
|
|
return {"r": face.r,
|
|
"x": face.x,
|
|
"w": face.w,
|
|
"y": face.y,
|
|
"h": face.h,
|
|
"landmarksXY": face.landmarksAsXY()}
|