Unified CLI (#22)

* Created a single script to call the other ones.

Usage is ./faceswap.py {train|extract|convert}

* Improved the help from the commands.

* Added forgotten faceswap.py file.

* Changed gitignore to add the scripts.

* Updates gitignore.

* Added guarding not to execute code when imported.

* Removed useless script. Display help when no arguments are provided.

* Update README
This commit is contained in:
Édouard WILLISSECK 2017-12-25 02:17:02 +01:00 committed by Hidde Jansen
parent f0c971e8a5
commit 59d234ae5e
9 changed files with 73 additions and 45 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@
!Dockerfile*
!requirements*
!lib/*.py
!scripts

View File

@ -47,13 +47,13 @@ The project has multiple entry points. You will have to:
- **Convert** your sources with the model
### Extract
From your setup folder, run `python extract.py`. This will take photos from `src` folder and extract faces into `extract` folder.
From your setup folder, run `python faceswap.py extract`. This will take photos from `src` folder and extract faces into `extract` folder.
### Train
From your setup folder, run `python train.py`. This will take photos from `data/trump` and `data/cage` folder and train a model that will be saved inside the `models` folder.
From your setup folder, run `python faceswap.py train`. This will take photos from two folders containing pictures of both faces and train a model that will be saved inside the `models` folder.
### Convert
From your setup folder, run `python convert.py`. This will take photos from `original` folder and apply new faces into `modified` folder.
From your setup folder, run `python faceswap.py convert`. This will take photos from `original` folder and apply new faces into `modified` folder.
#### General notes:
- All of the scripts mentioned have `-h`/`--help` options with a arguments that they will accept. You're smart, you can figure out how this works, right?!

View File

@ -1,10 +0,0 @@
### Simple face extractor
Takes pictures in the 'src' folder and extracts faces in 'extract'
Note : the cropped area may have to be improved
From https://docs.opencv.org/3.3.0/d7/d8b/tutorial_py_face_detection.html
And https://stackoverflow.com/questions/13211745/detect-face-then-autocrop-pictures
You can also look tools like https://github.com/leblancfg/autocrop

17
faceswap.py Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env python3
import argparse
from scripts.extract import ExtractTrainingData
from lib.cli import TrainingProcessor
from scripts.convert import ConvertImage
if __name__ == "__main__":
parser = argparse.ArgumentParser()
subparser = parser.add_subparsers()
extract = ExtractTrainingData(subparser, "extract", "Extract the faces from a pictures.")
train = TrainingProcessor(subparser, "train", "This command trains the model for the two faces A and B.")
convert = ConvertImage(subparser, "convert", "Convert a source image to a new one with the face swapped.")
arguments = parser.parse_args()
try:
arguments.func(arguments)
except:
parser.print_help()

View File

@ -22,10 +22,11 @@ class FullPaths(argparse.Action):
class TrainingProcessor(object):
arguments = None
def __init__(self, description='default'):
print('Initializing')
self.parse_arguments(description)
def __init__(self, subparser, command, description='default'):
self.parse_arguments(description, subparser, command)
def process_arguments(self, arguments):
self.arguments = arguments
print("Model A Directory: {}".format(self.arguments.input_A))
print("Model B Directory: {}".format(self.arguments.input_B))
print("Training data directory: {}".format(self.arguments.model_dir))
@ -41,8 +42,10 @@ class TrainingProcessor(object):
self.process()
def parse_arguments(self, description):
parser = argparse.ArgumentParser(
def parse_arguments(self, description, subparser, command):
parser = subparser.add_parser(
command,
help="This command trains the model for the two faces A and B.",
description=description,
epilog="Questions and feedback: \
https://github.com/deepfakes/faceswap-playground"
@ -78,7 +81,7 @@ class TrainingProcessor(object):
default=False,
help="Show verbose output")
parser = self.add_optional_arguments(parser)
self.arguments = parser.parse_args()
parser.set_defaults(func=self.process_arguments)
def add_optional_arguments(self, parser):
# Override this for custom arguments
@ -150,6 +153,7 @@ class DirectoryProcessor(object):
and writes output to the specified folder
'''
arguments = None
parser = None
input_dir = None
output_dir = None
@ -159,10 +163,12 @@ class DirectoryProcessor(object):
images_processed = 0
faces_detected = 0
def __init__(self, description='default'):
print('Initializing')
self.parse_arguments(description)
def __init__(self, subparser, command, description='default'):
self.create_parser(subparser, command, description)
self.parse_arguments(description, subparser, command)
def process_arguments(self, arguments):
self.arguments = arguments
print("Input Directory: {}".format(self.arguments.input_dir))
print("Output Directory: {}".format(self.arguments.output_dir))
print('Starting, this may take a while...')
@ -176,6 +182,9 @@ class DirectoryProcessor(object):
self.images_found = len(self.input_dir)
self.process_directory()
def process_directory(self):
for filename in self.input_dir:
if self.arguments.verbose:
print('Processing: {}'.format(os.path.basename(filename)))
@ -185,32 +194,35 @@ class DirectoryProcessor(object):
self.finalize()
def parse_arguments(self, description):
parser = argparse.ArgumentParser(
description=description,
epilog="Questions and feedback: \
https://github.com/deepfakes/faceswap-playground"
)
parser.add_argument('-i', '--input-dir',
def parse_arguments(self, description, subparser, command):
self.parser.add_argument('-i', '--input-dir',
action=FullPaths,
dest="input_dir",
default="input",
help="Input directory. A directory containing the files \
you wish to process. Defaults to 'input'")
parser.add_argument('-o', '--output-dir',
self.parser.add_argument('-o', '--output-dir',
action=FullPaths,
dest="output_dir",
default="output",
help="Output directory. This is where the converted files will \
be stored. Defaults to 'output'")
parser.add_argument('-v', '--verbose',
self.parser.add_argument('-v', '--verbose',
action="store_true",
dest="verbose",
default=False,
help="Show verbose output")
parser = self.add_optional_arguments(parser)
self.arguments = parser.parse_args()
self.parser = self.add_optional_arguments(self.parser)
self.parser.set_defaults(func=self.process_arguments)
def create_parser(self, subparser, command, description):
parser = subparser.add_parser(
command,
description=description,
epilog="Questions and feedback: \
https://github.com/deepfakes/faceswap-playground"
)
return parser
def add_optional_arguments(self, parser):
# Override this for custom arguments

0
scripts/__init__.py Normal file
View File

View File

@ -7,6 +7,14 @@ from lib.faces_detect import crop_faces
class ConvertImage(DirectoryProcessor):
filename = ''
def create_parser(self, subparser, command, description):
self.parser = subparser.add_parser(
command,
help="Convert a source image to a new one with the face swapped.",
description=description,
epilog="Questions and feedback: \
https://github.com/deepfakes/faceswap-playground"
)
def add_optional_arguments(self, parser):
parser.add_argument('-m', '--model-dir',
@ -34,4 +42,3 @@ class ConvertImage(DirectoryProcessor):
print('Failed to extract from image: {}. Reason: {}'.format(filename, e))
extract_cli = ConvertImage(description='Swaps faces for images in a directory')

View File

@ -4,12 +4,17 @@ from pathlib import Path
class ExtractTrainingData(DirectoryProcessor):
def create_parser(self, subparser, command, description):
self.parser = subparser.add_parser(
command,
help="Extract the faces from a pictures.",
description=description,
epilog="Questions and feedback: \
https://github.com/deepfakes/faceswap-playground"
)
def process_face(self, face, index, filename):
resized_image = cv2.resize(face.image, (256, 256))
output_file = self.output_dir / Path(filename).stem
cv2.imwrite(str(output_file) + str(index) + Path(filename).suffix,
resized_image)
extract_cli = ExtractTrainingData(description='Extracts faces from a collection of pictures \
and saves them to a separate directory')

View File

@ -1,4 +0,0 @@
from lib.cli import TrainingProcessor
training_processor = TrainingProcessor(description='Processes a collection of pictures \
to train a machine learning model')