diff --git a/advanced/databases/atvskeystroke/5.json b/advanced/databases/atvskeystroke/5.json new file mode 100644 index 0000000000000000000000000000000000000000..3940cb4c1731d4d8dea2e9cce7feb6ca22b0b62c --- /dev/null +++ b/advanced/databases/atvskeystroke/5.json @@ -0,0 +1,25 @@ +{ + "description": "The ATVS Keystroke database", + "root_folder": "/idiap/group/biometric/databases/atvs_keystroke", + "protocols": [ + { + "name": "A", + "template": "simple_keystroke_recognition/1", + "views": { + "templates": { + "view": "Templates", + "parameters": { + "protocol": "A" + } + }, + "probes": { + "view": "Probes", + "parameters": { + "protocol": "A" + } + } + } + } + ], + "schema_version": 2 +} \ No newline at end of file diff --git a/advanced/databases/atvskeystroke/5.py b/advanced/databases/atvskeystroke/5.py new file mode 100644 index 0000000000000000000000000000000000000000..c9a4339c709e4ff62a24aa8b510b5cc49c9b9805 --- /dev/null +++ b/advanced/databases/atvskeystroke/5.py @@ -0,0 +1,266 @@ +############################################################################### +# # +# Copyright (c) 2018 Idiap Research Institute, http://www.idiap.ch/ # +# Contact: beat.support@idiap.ch # +# # +# This file is part of the beat.examples module of the BEAT platform. # +# # +# Commercial License Usage # +# Licensees holding valid commercial BEAT licenses may use this file in # +# accordance with the terms contained in a written agreement between you # +# and Idiap. For further information contact tto@idiap.ch # +# # +# Alternatively, this file may be used under the terms of the GNU Affero # +# Public License version 3 as published by the Free Software and appearing # +# in the file LICENSE.AGPL included in the packaging of this file. # +# The BEAT platform is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # +# or FITNESS FOR A PARTICULAR PURPOSE. # +# # +# You should have received a copy of the GNU Affero Public License along # +# with the BEAT platform. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +import numpy as np +from collections import namedtuple + +from beat.backend.python.database import View + +import bob.db.atvskeystroke + + +keystroke_feature = ['', 'holdtime', 'rplatency', 'pplatency', 'rrlatency', 'prlatency'] +keystroke_type = ['', 'given_name', 'family_name', 'email', 'nationality', 'id_number'] + + +#---------------------------------------------------------- + + +def keystroke_reader(filename): + counter = 0 + feat = 0 + + data = {} + for line in open(filename, 'r').readlines(): + if not line.strip(): continue + if counter % 6 == 0: + feat += 1 + label = line.strip() + data[keystroke_feature[feat]] = {} + else: + values = [np.int32(v) for v in line.strip().split(' ')] + data[keystroke_feature[feat]][keystroke_type[counter % 6]] = np.array(values) + counter += 1 + + return data + + +#---------------------------------------------------------- + + +class Templates(View): + """Outputs: + - keystroke: "{{ user.username }}/atvs_keystroke/1 + - file_id: "{{ system_user.username }}/uint64/1" + - template_id: "{{ system_user.username }}/text/1" + - client_id: "{{ system_user.username }}/text/1" + + One "file_id" is associated with a given "keystroke". + Several "keystroke" are associated with a given "template_id". + Several "template_id" are associated with a given "client_id". + + --------------- --------------- --------------- --------------- --------------- --------------- + | keystroke | | keystroke | | keystroke | | keystroke | | keystroke | | keystroke | + --------------- --------------- --------------- --------------- --------------- --------------- + --------------- --------------- --------------- --------------- --------------- --------------- + | file_id | | file_id | | file_id | | file_id | | file_id | | file_id | + --------------- --------------- --------------- --------------- --------------- --------------- + ----------------------------------------------- ----------------------------------------------- + | template_id | | template_id | + ----------------------------------------------- ----------------------------------------------- + ----------------------------------------------------------------------------------------------- + | client_id | + ----------------------------------------------------------------------------------------------- + + Note: for this particular database, there is only one "template_id" + per "client_id". + """ + + def index(self, root_folder, parameters): + Entry = namedtuple('Entry', ['client_id', 'template_id', 'file_id', 'keystroke']) + + # Open the database and load the objects to provide via the outputs + db = bob.db.atvskeystroke.Database() + + template_ids = db.model_ids(groups='eval', + protocol=parameters['protocol']) + + entries = [] + + for template_id in template_ids: + objs = db.objects(groups='eval', + protocol=parameters['protocol'], + purposes='enrol', + model_ids=[template_id]) + + entries.extend([ Entry(x.client_id, template_id, x.id, x.make_path(root_folder, '.txt')) + for x in objs ]) + + return sorted(entries, key=lambda x: (x.client_id, x.template_id, x.file_id)) + + + def get(self, output, index): + obj = self.objs[index] + + if output == 'client_id': + return { + 'text': str(obj.client_id) + } + + elif output == 'template_id': + return { + 'text': str(obj.template_id) + } + + elif output == 'file_id': + return { + 'value': np.uint64(obj.file_id) + } + + elif output == 'keystroke': + return keystroke_reader(obj.keystroke) + + +#---------------------------------------------------------- + + +class Probes(View): + """Outputs: + - keystroke: "{{ user.username }}/atvs_keystroke/1 + - file_id: "{{ system_user.username }}/uint64/1" + - client_id: "{{ system_user.username }}/text/1" + - probe_id: "{{ system_user.username }}/uint64/1", + - template_ids: "{{ system_user.username }}/array_1d_text/1", + + One "file_id" is associated with a given "keystroke". + One "probe_id" is associated with a given "keystroke". + Several "keystroke" are associated with a given "client_id". + Several "client_id" are associated with a given "template_ids". + + --------------- --------------- --------------- --------------- --------------- --------------- + | keystroke | | keystroke | | keystroke | | keystroke | | keystroke | | keystroke | + --------------- --------------- --------------- --------------- --------------- --------------- + --------------- --------------- --------------- --------------- --------------- --------------- + | file_id | | file_id | | file_id | | file_id | | file_id | | file_id | + --------------- --------------- --------------- --------------- --------------- --------------- + --------------- --------------- --------------- --------------- --------------- --------------- + | probe_id | | probe_id | | probe_id | | probe_id | | probe_id | | probe_id | + --------------- --------------- --------------- --------------- --------------- --------------- + ----------------------------------------------- ----------------------------------------------- + | client_id | | client_id | + ----------------------------------------------- ----------------------------------------------- + ----------------------------------------------------------------------------------------------- + | template_ids | + ----------------------------------------------------------------------------------------------- + """ + + def index(self, root_folder, parameters): + Entry = namedtuple('Entry', ['template_ids', 'client_id', 'probe_id', 'file_id', + 'keystroke']) + + # Open the database and load the objects to provide via the outputs + db = bob.db.atvskeystroke.Database() + + template_ids = sorted(db.model_ids(protocol=parameters['protocol'], + groups='eval'), + key=lambda x: int(x)) + + template_probes = {} + for template_id in template_ids: + objs = sorted(db.objects(protocol=parameters['protocol'], + groups='eval', + purposes='probe', + model_ids=[template_id]), + key=lambda x: (x.client_id, x.id)) + + template_probes[template_id] = [ p.id for p in objs ] + + + objs = sorted(db.objects(protocol=parameters['protocol'], + groups='eval', + purposes='probe'), + key=lambda x: (x.client_id, x.id)) + + entries = [] + for obj in objs: + templates = [ template_id for template_id in template_ids + if obj.id in template_probes[template_id] ] + entries.append( Entry(templates, obj.client_id, obj.id, obj.id, + obj.make_path(root_folder, '.txt')) ) + + return sorted(entries, key=lambda x: (len(x.template_ids), x.template_ids, + x.client_id, x.probe_id)) + + + def get(self, output, index): + obj = self.objs[index] + + if output == 'template_ids': + return { + 'text': [ str(x) for x in obj.template_ids ] + } + + elif output == 'client_id': + return { + 'text': str(obj.client_id) + } + + elif output == 'probe_id': + return { + 'value': np.uint64(obj.probe_id) + } + + elif output == 'file_id': + return { + 'value': np.uint64(obj.file_id) + } + + elif output == 'keystroke': + return keystroke_reader(obj.keystroke) + + +#---------------------------------------------------------- + + +def setup_tests(): + # Install a mock load function for the keystrokes + def mock_keystroke_reader(filename): + return {} + + global keystroke_reader + keystroke_reader = mock_keystroke_reader + + +#---------------------------------------------------------- + + +# Test the behavior of the views (on fake data) +if __name__ == '__main__': + + setup_tests() + + view = Templates() + view.objs = view.index(root_folder='', parameters=dict(protocol = 'A')) + view.get('client_id', 0) + view.get('template_id', 0) + view.get('file_id', 0) + view.get('keystroke', 0) + + view = Probes() + view.objs = view.index(root_folder='', parameters=dict(protocol = 'A')) + view.get('template_ids', 0) + view.get('client_id', 0) + view.get('probe_id', 0) + view.get('file_id', 0) + view.get('keystroke', 0) diff --git a/advanced/databases/atvskeystroke/5.rst b/advanced/databases/atvskeystroke/5.rst new file mode 100644 index 0000000000000000000000000000000000000000..fe80803c56815cce01c171354aef3128d9ba732d --- /dev/null +++ b/advanced/databases/atvskeystroke/5.rst @@ -0,0 +1 @@ +The ATVS Keystroke database \ No newline at end of file