diff --git a/advanced/databases/frgc/5.json b/advanced/databases/frgc/5.json new file mode 100644 index 0000000000000000000000000000000000000000..005a74da4c7b7aef71395f67ffe010fc47afb05f --- /dev/null +++ b/advanced/databases/frgc/5.json @@ -0,0 +1,169 @@ +{ + "description": "The Face Recognition Grand Challenge", + "root_folder": "/idiap/resource/database/frgc/FRGC-2.0-dist", + "protocols": [ + { + "name": "2.0.1_maskI", + "template": "simple_face_recognition_frgc/1", + "views": { + "train": { + "view": "Train", + "parameters": { + "mask": "maskI", + "protocol": "2.0.1" + } + }, + "templates": { + "view": "Templates", + "parameters": { + "mask": "maskI", + "protocol": "2.0.1" + } + }, + "probes": { + "view": "Probes", + "parameters": { + "mask": "maskI", + "protocol": "2.0.1" + } + } + } + }, + { + "name": "2.0.4_maskI", + "template": "simple_face_recognition_frgc/1", + "views": { + "train": { + "view": "Train", + "parameters": { + "mask": "maskI", + "protocol": "2.0.4" + } + }, + "templates": { + "view": "Templates", + "parameters": { + "mask": "maskI", + "protocol": "2.0.4" + } + }, + "probes": { + "view": "Probes", + "parameters": { + "mask": "maskI", + "protocol": "2.0.4" + } + } + } + }, + { + "name": "2.0.1_maskII", + "template": "simple_face_recognition_frgc/1", + "views": { + "train": { + "view": "Train", + "parameters": { + "mask": "maskII", + "protocol": "2.0.1" + } + }, + "templates": { + "view": "Templates", + "parameters": { + "mask": "maskII", + "protocol": "2.0.1" + } + }, + "probes": { + "view": "Probes", + "parameters": { + "mask": "maskII", + "protocol": "2.0.1" + } + } + } + }, + { + "name": "2.0.4_maskII", + "template": "simple_face_recognition_frgc/1", + "views": { + "train": { + "view": "Train", + "parameters": { + "mask": "maskII", + "protocol": "2.0.4" + } + }, + "templates": { + "view": "Templates", + "parameters": { + "mask": "maskII", + "protocol": "2.0.4" + } + }, + "probes": { + "view": "Probes", + "parameters": { + "mask": "maskII", + "protocol": "2.0.4" + } + } + } + }, + { + "name": "2.0.1_maskIII", + "template": "simple_face_recognition_frgc/1", + "views": { + "train": { + "view": "Train", + "parameters": { + "mask": "maskIII", + "protocol": "2.0.1" + } + }, + "templates": { + "view": "Templates", + "parameters": { + "mask": "maskIII", + "protocol": "2.0.1" + } + }, + "probes": { + "view": "Probes", + "parameters": { + "mask": "maskIII", + "protocol": "2.0.1" + } + } + } + }, + { + "name": "2.0.4_maskIII", + "template": "simple_face_recognition_frgc/1", + "views": { + "train": { + "view": "Train", + "parameters": { + "mask": "maskIII", + "protocol": "2.0.4" + } + }, + "templates": { + "view": "Templates", + "parameters": { + "mask": "maskIII", + "protocol": "2.0.4" + } + }, + "probes": { + "view": "Probes", + "parameters": { + "mask": "maskIII", + "protocol": "2.0.4" + } + } + } + } + ], + "schema_version": 2 +} \ No newline at end of file diff --git a/advanced/databases/frgc/5.py b/advanced/databases/frgc/5.py new file mode 100644 index 0000000000000000000000000000000000000000..70e53012eb68e44d73d4ae75477ba4a1bca0c062 --- /dev/null +++ b/advanced/databases/frgc/5.py @@ -0,0 +1,412 @@ +############################################################################### +# # +# 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 os +import numpy as np +from collections import namedtuple + +from beat.backend.python.database import View + +import bob.io.base +import bob.io.image +import bob.db.frgc + + +#---------------------------------------------------------- + + +class Train(View): + """Outputs: + - image: "{{ system_user.username }}/array_3d_uint8/1" + - eye_centers: "{{ system_user.username }}/eye_positions/1" + - file_id: "{{ system_user.username }}/text/1" + - client_id: "{{ system_user.username }}/text/1" + + One "file_id" is associated with a given "image". + One "eye_centers" is associated with a given "image". + Several "image" are associated with a given "client_id". + + --------------- --------------- --------------- --------------- --------------- --------------- + | image | | image | | image | | image | | image | | image | + --------------- --------------- --------------- --------------- --------------- --------------- + --------------- --------------- --------------- --------------- --------------- --------------- + | eye_centers | | eye_centers | | eye_centers | | eye_centers | | eye_centers | | eye_centers | + --------------- --------------- --------------- --------------- --------------- --------------- + --------------- --------------- --------------- --------------- --------------- --------------- + | file_id | | file_id | | file_id | | file_id | | file_id | | file_id | + --------------- --------------- --------------- --------------- --------------- --------------- + ----------------------------------------------- ----------------------------------------------- + | client_id | | client_id | + ----------------------------------------------- ----------------------------------------------- + """ + + def index(self, root_folder, parameters): + Entry = namedtuple('Entry', ['client_id', 'file_id', 'eye_centers', 'image']) + + # Open the database and load the objects to provide via the outputs + db = bob.db.frgc.Database(original_directory=root_folder) + + objs = sorted(db.objects(protocol=parameters['protocol'], + groups='world', + mask_type=parameters['mask']), + key=lambda x: (x.client_id, x.id)) + + entries = [] + + for obj in objs: + filename = obj.make_path(root_folder, '.jpg') + if not os.path.exists(filename): + filename = obj.make_path(root_folder, '.JPG') + + entries.append(Entry(obj.client_id, obj.id, db.annotations(obj), filename)) + + return entries + + + def get(self, output, index): + obj = self.objs[index] + + if output == 'client_id': + return { + 'text': obj.client_id + } + + elif output == 'file_id': + return { + 'text': obj.file_id + } + + elif output == 'eye_centers': + return { + 'left': { + 'y': np.int32(obj.eye_centers['leye'][0]), + 'x': np.int32(obj.eye_centers['leye'][1]), + }, + 'right': { + 'y': np.int32(obj.eye_centers['reye'][0]), + 'x': np.int32(obj.eye_centers['reye'][1]), + } + } + + elif output == 'image': + return { + 'value': bob.io.base.load(obj.image) + } + + +#---------------------------------------------------------- + + +class Templates(View): + """Outputs: + - image: "{{ system_user.username }}/array_3d_uint8/1" + - eye_centers: "{{ system_user.username }}/eye_positions/1" + - file_id: "{{ system_user.username }}/text/1" + - template_id: "{{ system_user.username }}/uint64/1" + - client_id: "{{ system_user.username }}/text/1" + + One "file_id" is associated with a given "image". + One "eye_centers" is associated with a given "image". + Several "image" are associated with a given "template_id". + Several "template_id" are associated with a given "client_id". + + --------------- --------------- --------------- --------------- --------------- --------------- + | image | | image | | image | | image | | image | | image | + --------------- --------------- --------------- --------------- --------------- --------------- + --------------- --------------- --------------- --------------- --------------- --------------- + | eye_centers | | eye_centers | | eye_centers | | eye_centers | | eye_centers | | eye_centers | + --------------- --------------- --------------- --------------- --------------- --------------- + --------------- --------------- --------------- --------------- --------------- --------------- + | file_id | | file_id | | file_id | | file_id | | file_id | | file_id | + --------------- --------------- --------------- --------------- --------------- --------------- + ----------------------------------------------- ----------------------------------------------- + | template_id | | template_id | + ----------------------------------------------- ----------------------------------------------- + ----------------------------------------------------------------------------------------------- + | client_id | + ----------------------------------------------------------------------------------------------- + """ + + def index(self, root_folder, parameters): + Entry = namedtuple('Entry', ['client_id', 'template_id', 'file_id', 'eye_centers', 'image']) + + # Open the database and load the objects to provide via the outputs + db = bob.db.frgc.Database(original_directory=root_folder) + + model_files = bob.db.frgc.models.get_list(root_folder, + 'dev', + parameters['protocol'], + 'enroll') + + mask = bob.db.frgc.models.get_mask(root_folder, + parameters['protocol'], + parameters['mask']) + + entries = [] + for model_index, model in enumerate(model_files): + if (mask[:, model_index] > 0).any(): + for presentation in model.m_files: + obj = bob.db.frgc.models.File(model.m_signature, + presentation, + model.m_files[presentation]) + + filename = obj.make_path(root_folder, '.jpg') + if not os.path.exists(filename): + filename = obj.make_path(root_folder, '.JPG') + + entries.append(Entry(obj.client_id, model.m_model, obj.id, + db.annotations(obj), filename)) + + 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': obj.client_id + } + + elif output == 'template_id': + return { + 'value': np.uint64(obj.template_id) + } + + elif output == 'file_id': + return { + 'text': obj.file_id + } + + elif output == 'eye_centers': + return { + 'left': { + 'y': np.int32(obj.eye_centers['leye'][0]), + 'x': np.int32(obj.eye_centers['leye'][1]), + }, + 'right': { + 'y': np.int32(obj.eye_centers['reye'][0]), + 'x': np.int32(obj.eye_centers['reye'][1]), + } + } + + elif output == 'image': + return { + 'value': bob.io.base.load(obj.image) + } + + +#---------------------------------------------------------- + + +class Probes(View): + """Outputs: + - image: "{{ system_user.username }}/array_3d_uint8/1" + - eye_centers: "{{ system_user.username }}/eye_positions/1" + - file_id: "{{ system_user.username }}/text/1" + - probe_id: "{{ system_user.username }}/text/1" + - client_id: "{{ system_user.username }}/text/1" + - template_ids: "{{ system_user.username }}/array_1d_uint64/1" + + One "file_id" is associated with a given "image". + One "eye_centers" is associated with a given "image". + One "probe_id" is associated with a given "image". + Several "image" are associated with a given "client_id". + Several "client_id" are associated with a given "template_ids". + + --------------- --------------- --------------- --------------- --------------- --------------- + | image | | image | | image | | image | | image | | image | + --------------- --------------- --------------- --------------- --------------- --------------- + --------------- --------------- --------------- --------------- --------------- --------------- + | eye_centers | | eye_centers | | eye_centers | | eye_centers | | eye_centers | | eye_centers | + --------------- --------------- --------------- --------------- --------------- --------------- + --------------- --------------- --------------- --------------- --------------- --------------- + | 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', + 'eye_centers', 'image']) + + # Open the database and load the objects to provide via the outputs + db = bob.db.frgc.Database(original_directory=root_folder) + + probe_files = bob.db.frgc.models.get_list(root_folder, + 'dev', + parameters['protocol'], + 'probe') + + model_files = bob.db.frgc.models.get_list(root_folder, + 'dev', + parameters['protocol'], + 'enroll') + + mask = bob.db.frgc.models.get_mask(root_folder, + parameters['protocol'], + parameters['mask']) + + template_ids = np.array([ x.m_model for x in model_files ]) + + entries = [] + for probe_index, probe in enumerate(probe_files): + template_indices = mask[probe_index, :].nonzero()[0] + templates = sorted(template_ids.take(template_indices)) + + for presentation in probe.m_files: + obj = bob.db.frgc.models.File(probe.m_signature, + presentation, + probe.m_files[presentation]) + + filename = obj.make_path(root_folder, '.jpg') + if not os.path.exists(filename): + filename = obj.make_path(root_folder, '.JPG') + + entries.append(Entry(templates, obj.client_id, obj.id, obj.id, + db.annotations(obj), filename)) + + 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 { + 'value': np.uint64(obj.template_ids) + } + + elif output == 'client_id': + return { + 'text': obj.client_id + } + + elif output == 'probe_id': + return { + 'text': obj.file_id + } + + elif output == 'file_id': + return { + 'text': obj.file_id + } + + elif output == 'eye_centers': + return { + 'left': { + 'y': np.int32(obj.eye_centers['leye'][0]), + 'x': np.int32(obj.eye_centers['leye'][1]), + }, + 'right': { + 'y': np.int32(obj.eye_centers['reye'][0]), + 'x': np.int32(obj.eye_centers['reye'][1]), + } + } + + elif output == 'image': + return { + 'value': bob.io.base.load(obj.image) + } + + +#---------------------------------------------------------- + + +def setup_tests(): + # Install a mock load function for the images + def mock_load(root_folder): + return np.ndarray((3, 10, 20), dtype=np.uint8) + + # Install a mock os.path.exists function + def mock_exists(path): + return True + + bob.io.base.load = mock_load + os.path.exists = mock_exists + + +#---------------------------------------------------------- + + +# Test the behavior of the views (on fake data) +if __name__ == '__main__': + + setup_tests() + + # Note: This database can't be tested without the actual data, since + # some files are needed by this implementation + + view = Train() + view.objs = view.index( + root_folder='', + parameters=dict( + protocol='2.0.1', + mask='maskI', + ) + ) + view.get('client_id', 0) + view.get('file_id', 0) + view.get('eye_centers', 0) + view.get('image', 0) + + + view = Templates() + view.objs = view.index( + root_folder='', + parameters=dict( + protocol='2.0.1', + mask='maskI', + ) + ) + view.get('client_id', 0) + view.get('template_id', 0) + view.get('file_id', 0) + view.get('eye_centers', 0) + view.get('image', 0) + + + view = Probes() + view.objs = view.index( + root_folder='', + parameters=dict( + protocol='2.0.1', + mask='maskI', + ) + ) + view.get('template_ids', 0) + view.get('client_id', 0) + view.get('probe_id', 0) + view.get('file_id', 0) + view.get('eye_centers', 0) + view.get('image', 0) diff --git a/advanced/databases/frgc/5.rst b/advanced/databases/frgc/5.rst new file mode 100644 index 0000000000000000000000000000000000000000..b767be8bef0e6679c1e8dd294e9e39b5d44be3ea --- /dev/null +++ b/advanced/databases/frgc/5.rst @@ -0,0 +1 @@ +The Face Recognition Grand Challenge \ No newline at end of file