Commit fe2f04c1 authored by André Anjos's avatar André Anjos 💬 Committed by André Anjos
Browse files

Add script to help debugging watershedding

parent 483e6b5b
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Wed 4 Oct 11:23:52 2017 CEST
"""Preprocesses a fingervein image with a watershed/neural-net seeded mask
Usage: %(prog)s [-v...] [-s <path>] [-f <float>] [-b <float>] [--scan]
<model> <database> [<stem>...]
%(prog)s --help
%(prog)s --version
<model> Path to model to use for find watershed markers
<database> Name of the database to use for creating the model (options are:
"fv3d" or "verafinger")
<stem> Name of the object on the database to display, without the root
or the extension. If none provided, run for all possible stems on
the database
-h, --help Shows this help message and exits
-V, --version Prints the version and exits
-v, --verbose Increases the output verbosity level
-f, --fg-threshold=<float> Foreground threshold value. Should be set to a
number that is between 0.5 and 1.0. The higher,
the less markers for the foreground watershed
process will be produced. [default: 0.7]
-b, --bg-threshold=<float> Background threshold value. Should be set to a
number that is between 0.0 and 0.5. The smaller,
the less markers for the foreground watershed
process will be produced. [default: 0.3]
-S, --scan If set, ignores settings for the threshold and
scans the whole range of threshold printing the
Jaccard, M1 and M2 merith figures
-s <path>, --save=<path> If set, saves image into a file instead of
displaying it
Visualize the preprocessing toolchain over a single image
$ %(prog)s model.hdf5 verafinger sample-stem
Save the results of the preprocessing to a file. In this case, the program
runs non-interactively:
$ %(prog)s -s graphics.png model.hdf5 verafinger sample-stem
Scans the set of possible thresholds printing Jaccard, M1 and M2 indexes:
$ %(prog)s --scan model.hdf5 verafinger sample-stem
import os
import sys
import time
import numpy
import schema
import docopt
import bob.core
logger = bob.core.log.setup("")
import matplotlib.pyplot as plt
def validate(args):
'''Validates command-line arguments, returns parsed values
This function uses :py:mod:`schema` for validating :py:mod:`docopt`
arguments. Logging level is not checked by this procedure (actually, it is
ignored) and must be previously setup as some of the elements here may use
logging for outputing information.
args (dict): Dictionary of arguments as defined by the help message and
returned by :py:mod:`docopt`
dict: Validate dictionary with the same keys as the input and with values
possibly transformed by the validation procedure
schema.SchemaError: in case one of the checked options does not validate.
valid_databases = ('fv3d', 'verafinger')
sch = schema.Schema({
'<model>': schema.And(os.path.exists,
error='<model> should point to an existing path'),
'<database>': schema.And(lambda n: n in valid_databases,
error='<database> must be one of %s' % ', '.join(valid_databases)),
'--fg-threshold': schema.And(
schema.Use(float), lambda n: 0.5 < n < 1.0,
error='--fg-threshold should be a float between 0.5 and 1.0',
'--bg-threshold': schema.And(
schema.Use(float), lambda n: 0.0 < n < 0.5,
error='--bg-threshold should be a float between 0.0 and 0.5',
str: object, #ignores strings we don't care about
}, ignore_extra_keys=True)
return sch.validate(args)
def make_figure(image, markers, edges, mask):
'''Returns a matplotlib figure with the detailed processing result'''
plt.clf() #completely clears the current figure
figure = plt.gcf()
_ = markers.copy().astype('uint8')
_[_==1] = 128
plt.imshow(_, cmap='gray')
_ = numpy.dstack([
(_ | (2550*edges).astype('uint8')),
plt.imshow(mask.astype('uint8')*255, cmap='gray')
plt.imshow(image, cmap='gray')
red_mask = numpy.dstack([
plt.imshow(red_mask, alpha=0.15)
plt.title('Image (masked)')
return figure
def process_one(args, image, path):
'''Processes a single image'''
from import WatershedMask, AnnotatedRoIMask
# loads the processor once - avoids re-reading weights from the disk
processor = WatershedMask(
annotator = AnnotatedRoIMask()
from import \
jaccard_index, intersect_ratio, intersect_ratio_of_complement
start = time.time()
markers, edges, mask =
total_time = time.time() - start
# error
annotated_mask = annotator(image)
ji = jaccard_index(annotated_mask, mask)
m1 = intersect_ratio(annotated_mask, mask)
m2 = intersect_ratio_of_complement(annotated_mask, mask)
logger.debug('%s, %.2f, %.2f, %.2f, %g, %g, %g', path, total_time,
args['--fg-threshold'], args['--bg-threshold'], ji, m1, m2)
if not args['--scan']:
fig = make_figure(image, markers, edges, mask)
fig.suptitle('%s @ %s - JI=%.4f, M1=%.4f, M2=%.4f\n' \
'($\\tau_{FG}$ = %.2f - $\\tau_{BG}$ = %.2f)' % \
(path, args['<database>'], ji, m1, m2, args['--fg-threshold'],
args['--bg-threshold']), fontsize=12)
if args['--save']:
print('Close the figure to continue...')
return (path, total_time, args['--fg-threshold'], args['--bg-threshold'],
ji, m1, m2)
def eval_best_thresholds(results):
'''Evaluates the best thresholds taking into consideration various indexes'''
m1 = numpy.array([k[-2] for k in results])
m2 = numpy.array([k[-1] for k in results])
index = m1/m2
return index.argmax()
def main(user_input=None):
if user_input is not None:
argv = user_input
argv = sys.argv[1:]
import pkg_resources
completions = dict(
args = docopt.docopt(
__doc__ % completions,
from .validate import setup_logger
logger = setup_logger('', args['--verbose'])
args = validate(args)
except schema.SchemaError as e:
if args['<database>'] == 'fv3d':
from ..configurations.fv3d import database as db
elif args['<database>'] == 'verafinger':
from ..configurations.verafinger import database as db
database_replacement = "%s/.bob_bio_databases.txt" % os.environ["HOME"]
all_files = db.objects()
# if a specific <stem> was not provided, run for all possible stems
if not args['<stem>']:
args['<stem>'] = [k.path for k in all_files]
# Loads the image, the mask and save it to a PNG file
for stem in args['<stem>']:
f = [k for k in all_files if k.path == stem]
if len(f) == 0:
raise RuntimeError('File with stem "%s" does not exist on "%s"' % \
stem, args['<database>'])
f = f[0]
image = f.load(db.original_directory, db.original_extension)
if args['--scan']:
results = []
logger.debug('stem, time, fg_thres, bg_thres, jaccard, m1, m2')
for fg_threshold in numpy.arange(0.6, 1.0, step=0.1):
for bg_threshold in numpy.arange(0.1, 0.5, step=0.1):
args['--fg-threshold'] = fg_threshold
args['--bg-threshold'] = bg_threshold
results.append(process_one(args, image, f.path))
best_thresholds = eval_best_thresholds(results)'%s: FG = %.2f | BG = %.2f | M1/M2 = %.2f', f.path,
results[best_thresholds][2], results[best_thresholds][3],
process_one(args, image, f.path)
Supports Markdown
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