Commit 0b34b777 authored by Tiago de Freitas Pereira's avatar Tiago de Freitas Pereira
Browse files

Merge branch 'display-annot' into 'master'

Port display-face-annotations script

See merge request !80
parents c566524f c0983e3f
Pipeline #46328 failed with stages
in 7 minutes and 17 seconds
include README.rst bootstrap-buildout.py buildout.cfg develop.cfg LICENSE version.txt requirements.txt
recursive-include doc *.py *.rst
recursive-include bob/bio/face/test/data *.hdf5 *.jpg *.pos *.png
recursive-include bob/bio/face/test/data *.hdf5 *.jpg *.pos *.png *.json
#!../bin/python
"""This script displays the iamges with annotations provided by any face database.
Basically, anything that can be used as a --database for verify.py can be specified here as well, including configuration files and ``database`` resources: ``resources.py -d database``.
"""This script displays the images with annotations provided by any face database.
By default, all images and their corresponding annotations are displayed, and you have to press ``Enter`` after each image.
If the database does not include annotations, or you want to display a different set of annotations, you can specify the ``--annotation-directory`` (and if required modify the ``--annotation-file-extension`` and ``--annotation-file-type``.
......@@ -13,130 +12,228 @@ Note that this script can only be used with face image databases, not with video
from __future__ import print_function
import os
import argparse
import click
import sys
import bob.bio.base
import bob.core
logger = bob.core.log.setup("bob.bio.face")
def command_line_arguments(command_line_parameters):
"""Defines the command line parameters that are accepted."""
# create parser
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
# add parameters
parser.add_argument('-d', '--database', nargs = '+', help = 'Select the database for which the images plus annotations should be shown.')
parser.add_argument('-V', '--video', action = 'store_true', help = 'Provide this flag if your database is a video database. For video databases, the annotations for the first frame is shown.')
parser.add_argument('-f', '--file-ids', nargs = '+', help = 'If given, only the images of the --database with the given file id are shown (non-existing IDs will be silently skipped).')
parser.add_argument('-a', '--annotation-directory', help = 'If given, use the annotations stored in the given annotation directory (this might be required for some databases).')
parser.add_argument('-x', '--annotation-file-extension', default = '.pos', help = 'Annotation files have the given filename extension.')
parser.add_argument('-t', '--annotation-file-type', default = 'named', help = 'Select the annotation file style, see bob.db.base documentation for valid types.')
parser.add_argument('-n', '--annotate-names', action = 'store_true', help = 'Plot the names of the annotations, too.')
parser.add_argument('-m', '--marker-style', default='rx', help = 'Select the marker style')
parser.add_argument('-M', '--marker-size', type=float, default=10., help = 'Select the marker size')
parser.add_argument('-F', '--font-size', type=int, default=16, help = 'Select the font size for the annotation names')
parser.add_argument('-C', '--font-color', default = 'b', help = 'Select the color for the annotation names')
parser.add_argument('--database-directories-file', metavar = 'FILE', default = "%s/.bob_bio_databases.txt" % os.environ["HOME"], help = 'An optional file, where database directories are stored (to avoid changing the database configurations)')
parser.add_argument('-o', '--output', help = "If given, it will save the plots in this output file instead of showing them. This option is useful when you don't have a display server (ssh).")
parser.add_argument('--self-test', action='store_true', help=argparse.SUPPRESS)
bob.core.log.add_command_line_option(parser)
args = parser.parse_args(command_line_parameters)
bob.core.log.set_verbosity_level(logger, args.verbose)
return args
def main(command_line_parameters=None):
args = command_line_arguments(command_line_parameters)
# load database
database = bob.bio.base.load_resource("".join(args.database), "database")
# replace directories
if isinstance(database, bob.bio.base.database.BioDatabase):
database.replace_directories(args.database_directories_file)
# get all files
if bob.bio.base.utils.is_argument_available('flat', database.all_files):
files = database.all_files(flat=True)
else:
files = database.all_files()
# filter file ids; convert them to str first
if args.file_ids is not None:
files = [f for f in files if str(f.id) in args.file_ids]
# open figure
if not args.self_test:
import logging
import json
from bob.extension.scripts.click_helper import (
verbosity_option,
ConfigCommand,
ResourceOption,
)
import bob.ip.color
logger = logging.getLogger(__name__)
@click.command(
entry_point_group="bob.bio.config",
cls=ConfigCommand,
epilog="""\b
Examples:
$ bob bio display-face-annotations -vvv -d <database> -a <annot_dir>
""",
)
@click.option(
"-d",
"--database",
required=True,
cls=ResourceOption,
entry_point_group="bob.bio.database",
help="Select the database for which the images plus annotations should be shown.",
)
@click.option(
"-V",
"--video",
"is_video",
is_flag=True,
help="Provide this flag if your database is a video database. "
"For video databases, the annotations for the first frame is shown.",
)
@click.option(
"-a",
"--annotations-dir",
help="Use the annotations stored in this directory "
"(when annotated with `$ bob bio annnotate` for example). "
"If not given, will try to load the annotations from the database.",
)
@click.option(
"-x",
"--annotations-extension",
default = ".json",
show_default=True,
help="Annotations files have the given filename extension.",
)
@click.option(
"-t",
"--annotations-type",
default = "json",
show_default=True,
help="Annotations type given to bob.bio.base.read_annotations.",
)
@click.option(
"-n",
"--display-names",
is_flag=True,
help="Plot the names of the annotations, too.",
)
@click.option(
"-m",
"--marker-style",
default="rx",
show_default=True,
help="Select the marker style",
)
@click.option(
"-M",
"--marker-size",
type=float,
default=10.,
show_default=True,
help="Select the marker size",
)
@click.option(
"-C",
"--font-color",
default="b",
show_default=True,
help="Select the color for the annotations names",
)
@click.option(
"-F",
"--font-size",
type=int,
default=16,
show_default=True,
help="Select the font size for the annotations names",
)
@click.option(
"-o",
"--output-dir",
help="If given, it will save the plots in this output file instead of showing them. This option is useful when you don't have a display server (ssh).",
)
@click.option(
"-k",
"--keep-all",
is_flag=True,
help="When -o is given: keeps every annotated samples instead of just one.",
)
@click.option(
"--self-test",
is_flag=True,
help="Prevents outputing to the screen and waiting for user input.",
)
@click.option(
"--groups",
"-g",
multiple=True,
default=["dev", "eval"],
show_default=True,
help="Biometric Database group that will be displayed.",
)
@verbosity_option(cls=ResourceOption)
def display_face_annotations(
database,
is_video,
annotations_dir,
annotations_extension,
annotations_type,
marker_style,
marker_size,
display_names,
font_color,
font_size,
output_dir,
keep_all,
self_test,
groups,
**kwargs
):
"""
Plots annotations on the corresponding face picture.
"""
logger.debug("Retrieving samples from database.")
samples = database.all_samples(groups)
logger.debug(f"{len(samples)} samples loaded from database.")
# open figure
from matplotlib import pyplot
if args.output is None:
pyplot.ion()
pyplot.show()
if not self_test and not output_dir:
pyplot.ion()
pyplot.show()
else:
pyplot.ioff()
pyplot.ioff()
pyplot.figure()
for f in files:
# load image
logger.info("loading image for file %s", f.id)
image = f.load(database.original_directory, database.original_extension)
if args.video:
frame_id, image, _ = image[0]
# convert to color if it is not
if image.ndim == 2:
image = bob.ip.color.gray_to_rgb(image)
# get annotations
annotations = {}
if args.annotation_directory is not None:
# load annotation file
annotation_file = f.make_path(args.annotation_directory, args.annotation_file_extension)
if os.path.exists(annotation_file):
logger.info("Loading annotations from file %s", annotation_file)
annotations = bob.db.base.read_annotation_file(annotation_file, args.annotation_file_type)
else:
logger.warn("Could not find annotation file %s", annotation_file)
else:
# get annotations from database
annotations = database.annotations(f)
if not annotations:
logger.warn("Could not find annotations for file %s", f.id)
if args.video:
assert frame_id in annotations, annotations
annotations = annotations[frame_id]
if not args.self_test:
pyplot.clf()
pyplot.imshow(image.transpose(1,2,0))
global_annotation = []
for n,a in annotations.items():
if isinstance(a, (list,tuple)) and len(a) == 2:
pyplot.plot(a[1], a[0], args.marker_style, ms = args.marker_size, mew = args.marker_size / 5.)
if args.annotate_names:
pyplot.annotate(n, (a[1], a[0]), color=args.font_color, fontsize=args.font_size)
for sample in samples:
# load image
logger.info("loading image for sample %s", sample.key)
image = sample.data
if is_video:
frame_id, image, _ = image[0]
# convert to color if it is not
if image.ndim == 2:
image = bob.ip.color.gray_to_rgb(image)
# get annotations
annotations = {}
if annotations_dir is not None:
# Loads the corresponding annotations file
annotations_file = os.path.join(annotations_dir, sample.key + annotations_extension)
if os.path.exists(annotations_file):
logger.info("Loading annotations from file %s", annotations_file)
annotations = bob.db.base.read_annotation_file(annotations_file, annotations_type)
else:
logger.warn("Could not find annotation file %s", annotations_file)
else:
global_annotation.append("%s=%s"%(n,a))
# plot all global annotations, at the top center of the image
pyplot.annotate(";".join(global_annotation), (image.shape[-1]/2, 0), color=args.font_color, fontsize=args.font_size, ha='center', va='baseline')
pyplot.gca().set_aspect("equal")
pyplot.gca().autoscale(tight=True)
if args.output is None:
pyplot.pause(0.001)
else:
pyplot.savefig(args.output)
input_text = "Press Enter to continue to the next image (or Ctrl-C + Enter to exit)"
if sys.version_info >= (3, 0):
input(input_text)
else:
raw_input(input_text)
# get annotations from database
annotations = database.annotations(sample)
if not annotations:
logger.warn("Could not find annotations for file %s", sample.key)
continue
if is_video:
assert frame_id in annotations, annotations
annotations = annotations[frame_id]
pyplot.clf()
pyplot.imshow(image.transpose(1,2,0))
global_annotation = []
for n,a in annotations.items():
if isinstance(a, (list,tuple)) and len(a) == 2:
pyplot.plot(a[1], a[0], marker_style, ms = marker_size, mew = marker_size / 5.)
if display_names:
pyplot.annotate(n, (a[1], a[0]), color=font_color, fontsize=font_size)
else:
global_annotation.append("%s=%s"%(n,a))
# plot all global annotations, at the top center of the image
pyplot.annotate(";".join(global_annotation), (image.shape[-1]/2, 0), color=font_color, fontsize=font_size, ha='center', va='baseline')
pyplot.gca().set_aspect("equal")
pyplot.gca().autoscale(tight=True)
if output_dir is None:
if self_test:
raise RuntimeError("Do not run self_test without --output_dir.")
pyplot.pause(0.001)
else:
if keep_all:
output_path = os.path.join(output_dir, sample.key + ".png")
else:
output_path = os.path.join(output_dir, "annotated.png")
os.makedirs(os.path.dirname(output_path), exist_ok=True)
pyplot.savefig(output_path)
if not self_test:
input_text = "Press Enter to continue to the next image (or Ctrl-C to exit)"
if sys.version_info >= (3, 0):
input(input_text)
else:
raw_input(input_text)
{"topleft": [5.476375102996826, 11.880301475524902], "bottomright": [78.71327209472656, 111.0], "reye": [27.06552505493164, 52.629173278808594], "leye": [61.69809341430664, 51.46814727783203], "nose": [45.439552307128906, 72.81857299804688], "mouthright": [30.882678985595703, 89.54910278320312], "mouthleft": [59.577816009521484, 89.41582489013672], "quality": 0.999476969242096}
\ No newline at end of file
import bob.bio.base.test.utils
import bob.bio.face
from click.testing import CliRunner
import pkg_resources
import tempfile
import shutil
import os
# TODO: Disabling this test until we have bob.bio.base#146
"""
def test_display_annotations():
from bob.bio.face.script.display_face_annotations import main
from bob.bio.face.script.display_face_annotations import display_face_annotations
try:
tmp_dir = tempfile.mkdtemp(prefix="bobtest_")
annotations_dir = pkg_resources.resource_filename(
"bob.bio.face.test",
"data/annotations/"
)
runner = CliRunner()
result = runner.invoke(
display_face_annotations,
args=(
'--database', 'dummy',
'--groups', 'world', '--groups', 'dev',
'--annotations-dir', annotations_dir,
'--output-dir', tmp_dir, '--keep-all',
'--self-test',
)
)
assertion_error_message = (
'Command exited with this output: `{}\' \n'
'If the output is empty, you can run this script locally to see '
'what is wrong:\n'
'$ bob bio display_face_annotations -vvv -d dummy -g world -g dev -a ./annotations/ -o /tmp/temp_annotated'
''.format(result.output))
assert result.exit_code == 0, assertion_error_message
with bob.bio.base.test.utils.Quiet():
parameters = ['-d', 'dummy', '-a', '/very/unlikely/directory', '--self-test']
main(parameters)
"""
# Checks if an annotated sample exists
sample_1_path = os.path.join(tmp_dir, "s1","1.png")
assertion_error_message = "File '{}' not created.".format(sample_1_path)
assert os.path.isfile(sample_1_path), assertion_error_message
finally:
shutil.rmtree(tmp_dir)
......@@ -7,7 +7,6 @@ package:
build:
entry_points:
- display_face_annotations.py = bob.bio.face.script.display_face_annotations:main
number: {{ environ.get('BOB_BUILD_NUMBER', 0) }}
run_exports:
- {{ pin_subpackage(name) }}
......@@ -59,6 +58,7 @@ test:
imports:
- {{ name }}
commands:
- bob bio display-face-annotations --help
- nosetests --with-coverage --cover-package={{ name }} -sv {{ name }}
- sphinx-build -aEW {{ project_dir }}/doc {{ project_dir }}/sphinx
- sphinx-build -aEb doctest {{ project_dir }}/doc sphinx
......
......@@ -195,6 +195,10 @@ setup(
'fargo = bob.bio.face.config.database.fargo',
],
'bob.bio.cli': [
'display-face-annotations = bob.bio.face.script.display_face_annotations:display_face_annotations',
],
},
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment