Skip to content

Commit

Permalink
Name intermediate files sequentially rather than using the input file…
Browse files Browse the repository at this point in the history
… base name. This guarantees the order is the same as on input, but also allows the user to choose intermediate file format
  • Loading branch information
matthewearl committed Jan 24, 2016
1 parent 1b6f80b commit b1568b4
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 13 deletions.
15 changes: 10 additions & 5 deletions README.md
Expand Up @@ -42,14 +42,17 @@ dclib/files/dlib/v18.10/shape_predictor_68_face_landmarks.dat.bz2).

General `pada.py` options:

$ ./pada.py --help
$ pada.py --help
usage: pada.py [-h] [--debug] [--config CONFIG] [--aligned-path ALIGNED_PATH]
[--aligned-extension ALIGNED_EXTENSION]
[--predictor-path PREDICTOR_PATH]
[--filtered-files FILTERED_FILES]
{align,framedrop} ...
{print_config_paths,align,framedrop} ...

positional arguments:
{align,framedrop} Sub-command help
{print_config_paths,align,framedrop}
Sub-command help
print_config_paths print config paths and exit
align align a set of images
framedrop Drop frames from a set of images

Expand All @@ -59,14 +62,16 @@ General `pada.py` options:
--config CONFIG Config file path
--aligned-path ALIGNED_PATH
Path where aligned images will be stored
--aligned-extension ALIGNED_EXTENSION
Extension (and filetype) to use for aligned images.
--predictor-path PREDICTOR_PATH
DLib face predictor dat file
--filtered-files FILTERED_FILES
File to write filtered files to

`pada.py align` options:

$ ./pada.py align --help
$ pada.py align --help
usage: pada.py align [-h] [--input-glob INPUT_GLOB] [--img-thresh IMG_THRESH]

optional arguments:
Expand All @@ -78,7 +83,7 @@ General `pada.py` options:

`pada.py framedrop` options:

$ ./pada.py framedrop --help
$ pada.py framedrop --help
usage: pada.py framedrop [-h] [--erode-amount ERODE_AMOUNT]
[--frame-skip FRAME_SKIP]

Expand Down
3 changes: 2 additions & 1 deletion examples/pada.conf
Expand Up @@ -2,7 +2,8 @@
"global": {
"aligned_path": "./aligned",
"predictor_path": "~/shape_predictor_68_face_landmarks.dat",
"filtered_files": "filtered.txt"
"filtered_files": "filtered.txt",
"aligned_extension": "jpg"
},
"align": {
"input_glob": "./input/*.jpg",
Expand Down
2 changes: 1 addition & 1 deletion make_vid.sh
Expand Up @@ -23,5 +23,5 @@

mencoder -idx -nosound -noskip -of lavf -lavfopts format=mp4 -ovc x264 \
-x264encopts pass=1:bitrate=2000:crf=24 -o output.mp4 -mf fps=30 \
'mf://@files.txt'
'mf://@filtered.txt'

10 changes: 8 additions & 2 deletions pada.py
Expand Up @@ -46,6 +46,9 @@ def parse_args():
default=CONFIG_FILE_NAME)
parser.add_argument('--aligned-path',
help='Path where aligned images will be stored')
parser.add_argument('--aligned-extension',
help='Extension (and filetype) to use for aligned '
'images.')
parser.add_argument('--predictor-path',
help='DLib face predictor dat file',
type=unicode)
Expand Down Expand Up @@ -140,12 +143,15 @@ def parse_args():
pada.align.align_images(
input_files=sorted(glob.glob(cfg['input_glob'])),
out_path=cfg['aligned_path'],
out_extension=cfg['aligned_extension'],
landmark_finder=landmark_finder,
img_thresh=cfg['img_thresh'])
elif cli_args.cmd == "framedrop":
input_files_glob = os.path.join(
cfg['aligned_path'],
'*.{}'.format(cfg['aligned_extension']))
filtered_files = pada.framedrop.filter_files(
input_files=sorted(glob.glob(
os.path.join(cfg['aligned_path'], '*.jpg'))),
input_files=sorted(glob.glob(input_files_glob)),
frame_skip=cfg['frame_skip'],
erode_amount=cfg['erode_amount'],
landmark_finder=landmark_finder)
Expand Down
15 changes: 11 additions & 4 deletions pada/align.py
Expand Up @@ -121,7 +121,8 @@ def get_ims_and_landmarks(images, landmark_finder):
logger.info("Read %s images with landmarks", count)


def align_images(input_files, out_path, landmark_finder, img_thresh=0.0):
def align_images(input_files, out_path, out_extension, landmark_finder,
img_thresh=0.0):
"""
Align a set of images of a person's face.
Expand All @@ -134,6 +135,10 @@ def align_images(input_files, out_path, landmark_finder, img_thresh=0.0):
Directory to write the aligned files to. The output files have the same
basename as the corresponding input file.
:param out_extension:
Extension to use for aligned images.
:param landmark_finder:
An instance of :class:`.LandmarkFinder`, used to find the facial
Expand All @@ -155,7 +160,8 @@ def align_images(input_files, out_path, landmark_finder, img_thresh=0.0):
raise Exception("Path {} exists, but it is not a directory".format(
out_path))
logger.info("%s already exists. Removing existing images.", out_path)
for fname in glob.glob(os.path.join(out_path, "*.jpg")):
for fname in glob.glob(os.path.join(out_path,
"*.{}".format(out_extension))):
os.remove(fname)
else:
logger.info("%s does not exist. Creating it.", out_path)
Expand All @@ -165,7 +171,7 @@ def align_images(input_files, out_path, landmark_finder, img_thresh=0.0):
ims_and_landmarks = get_ims_and_landmarks(
read_ims(input_files, img_thresh=img_thresh),
landmark_finder)
for n, im, lms in ims_and_landmarks:
for idx, (n, im, lms) in enumerate(ims_and_landmarks):
mask = landmarks.get_face_mask(im.shape, lms)
masked_im = mask[:, :, numpy.newaxis] * im
color = ((numpy.sum(masked_im, axis=(0, 1)) /
Expand All @@ -177,7 +183,8 @@ def align_images(input_files, out_path, landmark_finder, img_thresh=0.0):
M = orthogonal_procrustes(ref_landmarks, lms)
warped = warp_im(im, M, im.shape)
warped_corrected = warped * ref_color / color
out_fname = os.path.join(out_path, os.path.basename(n))
out_fname = os.path.join(out_path,
"{:08d}.{}".format(idx, out_extension))
cv2.imwrite(out_fname, warped_corrected)
logger.debug("Wrote file %s", out_fname)

4 changes: 4 additions & 0 deletions pada/framedrop.py
Expand Up @@ -102,12 +102,15 @@ def filter_files(input_files, frame_skip, erode_amount, landmark_finder):
"""
input_files = list(input_files)
logger.info("Filtering %s files", len(input_files))

# Make a mask, which defines the area over which frame difference is
# measured.
logger.debug("Making mask")
mask = make_mask(input_files[0], erode_amount, landmark_finder)

# Find the nodes in the first and last layer.
logger.debug("Finding weights")
weights = find_weights(input_files, mask, frame_skip)
sources = input_files[:frame_skip]
if len(input_files) % frame_skip != 0:
Expand All @@ -118,6 +121,7 @@ def filter_files(input_files, frame_skip, erode_amount, landmark_finder):
# Compute `dist` which gives the minimum distance from any frame to a start
# frame, and `parent` which given a node returns the previous node on the
# shortest path to that node.
logger.debug("Computing distances")
dist = {n: (0 if n in sources else None) for n in input_files}
parent = {}
for u in input_files:
Expand Down

0 comments on commit b1568b4

Please sign in to comment.