replay.py 6.02 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Pavel Korshunov <pavel.korshunov@idiap.ch>
# Mon 12 Oct 14:43:22 CEST 2015

"""
  Replay attack database implementation of bob.bio.base.database.BioDatabase interface.
  It is an extension of an SQL-based database interface, which directly talks to Replay database, for
  verification experiments (good to use in bob.bio.base framework).
  It also implements a kind of hack so that you can run vulnerability analysis with it.
"""

from .database import FaceBioFile
14
15
16
17
from bob.bio.base.database import BioDatabase


class ReplayBioFile(FaceBioFile):
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
18
19
    """BioFile implementation for the bob.db.replay database"""

20
21
22
23
24
25
26
27
    def __init__(self, f):
        super(FaceBioFile, self).__init__(client_id=f.client_id, path=f.path, file_id=f.id)
        self._f = f

    def load(self, directory=None, extension=None):
        video = self._f.load(directory, extension)
        # just return the 10th frame.
        return video[10]
28
29
30
31
32


class ReplayBioDatabase(BioDatabase):
    """
    Implements verification API for querying Replay database.
33
    This database only loads the 10th image from the video files
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    """
    __doc__ = __doc__

    def __init__(self, **kwargs):
        # call base class constructors to open a session to the database
        super(ReplayBioDatabase, self).__init__(name='replay', **kwargs)

        from bob.db.replay import Database as LowLevelDatabase
        self.__db = LowLevelDatabase()

        self.low_level_group_names = ('train', 'devel', 'test')
        self.high_level_group_names = ('world', 'dev', 'eval')

    def protocol_names(self):
        """Returns all registered protocol names
        Here I am going to hack and double the number of protocols
        with -licit and -spoof. This is done for running vulnerability
        analysis"""
        names = [p.name + '-licit' for p in self.__db.protocols()]
        names += [p.name + '-spoof' for p in self.__db.protocols()]
        return names

    def groups(self):
        return self.convert_names_to_highlevel(
            self.__db.groups(), self.low_level_group_names, self.high_level_group_names)

    def annotations(self, file):
61
62
63
        """Will return the bounding box annotation of 10th frame of the video."""
        fn = 10  # 10th frame number
        annots = file._f.bbx(directory=self.original_directory)
64
        # bob uses the (y, x) format
65
66
67
        topleft = (annots[fn][2], annots[fn][1])
        bottomright = (annots[fn][2] + annots[fn][4], annots[fn][1] + annots[fn][3])
        annotations = {'topleft': topleft, 'bottomright': bottomright}
68
69
70
71
        return annotations

    def model_ids_with_protocol(self, groups=None, protocol=None, **kwargs):
        # since the low-level API does not support verification straight-forward-ly, we improvise.
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
72
        files = self.objects(groups=groups, protocol=protocol, purposes='enroll', **kwargs)
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
        return sorted(set(f.client_id for f in files))

    def objects(self, groups=None, protocol=None, purposes=None, model_ids=None, **kwargs):
        if protocol == '.':
            protocol = None
        protocol = self.check_parameter_for_validity(protocol, "protocol", self.protocol_names(), 'grandtest-licit')
        groups = self.check_parameters_for_validity(groups, "group", self.groups(), self.groups())
        purposes = self.check_parameters_for_validity(purposes, "purpose", ('enroll', 'probe'), ('enroll', 'probe'))
        purposes = list(purposes)
        groups = self.convert_names_to_lowlevel(
            groups, self.low_level_group_names, self.high_level_group_names)

        # protocol licit is not defined in the low level API
        # so do a hack here.
        if '-licit' in protocol:
            # for licit we return the grandtest protocol
            protocol = protocol.replace('-licit', '')
            # The low-level API has only "attack", "real", "enroll" and "probe"
            # should translate to "real" or "attack" depending on the protocol.
            # enroll does not to change.
            if 'probe' in purposes:
                purposes.remove('probe')
                purposes.append('real')
                if len(purposes) == 1:
                    # making the model_ids to None will return all clients which make
                    # the impostor data also available.
                    model_ids = None
                elif model_ids:
                    raise NotImplementedError(
                       'Currently returning both enroll and probe for specific '
                       'client(s) in the licit protocol is not supported. '
                       'Please specify one purpose only.')
        elif '-spoof' in protocol:
            protocol = protocol.replace('-spoof', '')
            # you need to replace probe with attack and real for the spoof protocols.
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
108
109
            # You can add the real here also to create positives scores also
            # but usually you get these scores when you run the licit protocol
110
111
112
113
114
115
116
117
118
119
120
121
            if 'probe' in purposes:
                purposes.remove('probe')
                purposes.append('attack')

        # now, query the actual Replay database
        objects = self.__db.objects(groups=groups, protocol=protocol, cls=purposes, clients=model_ids, **kwargs)

        # make sure to return BioFile representation of a file, not the database one
        # also make sure you replace client ids with spoof/metatdata1/metadata2/...
        retval = []
        for f in objects:
            if f.is_real():
122
                retval.append(ReplayBioFile(f))
123
            else:
124
                temp = ReplayBioFile(f)
125
126
127
                temp.client_id = 'attack'
                retval.append(temp)
        return retval
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
128
129
130
131
132
133
134
135
136
137
138
139

    def arrange_by_client(self, files):
        client_files = {}
        for file in files:
            if str(file.client_id) not in client_files:
                client_files[str(file.client_id)] = []
            client_files[str(file.client_id)].append(file)

        files_by_clients = []
        for client in sorted(client_files.keys()):
            files_by_clients.append(client_files[client])
        return files_by_clients