query.py 8.97 KB
Newer Older
1
2
3
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#
# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program 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. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19
20
21
22
23
24
25
26

"""This module provides the Dataset interface allowing the user to query the
Biosecure database in the most obvious ways.
"""

import os
from .models import *
from .driver import Interface

27
import bob.db.base
28

29
SQLITE_FILE = Interface().files()[0]
30

31
class Database(bob.db.base.SQLiteDatabase):
32
33
34
35
36
37
  """The dataset class opens and maintains a connection opened to the Database.

  It provides many different ways to probe for the characteristics of the data
  and for the data itself inside the database.
  """

Manuel Günther's avatar
Manuel Günther committed
38
  def __init__(self, original_directory = None, original_extension = '.jpg'):
39
    # call base class constructors
40
41
42
    super(Database, self).__init__(SQLITE_FILE, File)
    self.original_directory = original_directory
    self.original_extension = original_extension
43

Laurent EL SHAFEY's avatar
Laurent EL SHAFEY committed
44
  def groups(self, protocol=None):
45
46
47
48
    """Returns the names of all registered groups"""

    return ProtocolPurpose.group_choices # Same as Client.group_choices for this database

49
50
51
52
53
54
55
56
57
  def clients(self, protocol=None, groups=None):
    """Returns a set of clients for the specific query by the user.

    Keyword Parameters:

    protocol
      The protocol to consider ('ca0', 'caf', 'wc')

    groups
58
      The groups to which the clients belong ('dev', 'eval', 'world')
59

60
    Returns: A list containing all the clients which have the given properties.
61
62
    """

63
64
    protocol = self.check_parameters_for_validity(protocol, "protocol", self.protocol_names())
    groups = self.check_parameters_for_validity(groups, "group", self.groups())
65
    # List of the clients
66
    q = self.query(Client).filter(Client.sgroup.in_(groups)).\
67
          order_by(Client.id)
68
    return list(q)
69
70
71
72
73
74

  def models(self, protocol=None, groups=None):
    """Returns a set of models for the specific query by the user.

    Keyword Parameters:

75
76
77
    protocol
      The protocol to consider ('ca0', 'caf', 'wc')

78
    groups
79
      The groups to which the subjects attached to the models belong ('dev', 'eval', 'world')
80

81
    Returns: A list containing all the models belonging to the given group.
82
83
84
85
    """

    return self.clients(protocol, groups)

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  def model_ids(self, protocol=None, groups=None):
    """Returns a list of model ids for the specific query by the user.

    Keyword Parameters:

    protocol
      The protocol to consider ('ca0', 'caf', 'wc')

    groups
      The groups to which the subjects attached to the models belong ('dev', 'eval', 'world')

    Returns: A list containing the ids of all models belonging to the given group.
    """

    return [client.id for client in self.clients(protocol, groups)]

102
103
104
  def has_client_id(self, id):
    """Returns True if we have a client with a certain integer identifier"""

105
    return self.query(Client).filter(Client.id==id).count() != 0
106
107
108
109
110

  def client(self, id):
    """Returns the client object in the database given a certain id. Raises
    an error if that does not exist."""

111
    return self.query(Client).filter(Client.id==id).one()
112

Manuel Günther's avatar
Manuel Günther committed
113
  def get_client_id_from_model_id(self, model_id, **kwargs):
114
    """Returns the client_id attached to the given model_id
115

116
117
118
119
120
121
122
123
124
    Keyword Parameters:

    model_id
      The model_id to consider

    Returns: The client_id attached to the given model_id
    """
    return model_id

125
  def objects(self, protocol=None, purposes=None, model_ids=None, groups=None,
126
      classes=None):
127
128
129
130
131
132
133
134
135
136
    """Returns a set of filenames for the specific query by the user.
    WARNING: Files used as impostor access for several different models are
    only listed one and refer to only a single model

    Keyword Parameters:

    protocol
      One of the Biosecure protocols ('ca0', 'caf', 'wc').

    purposes
137
      The purposes required to be retrieved ('enroll', 'probe', 'train') or a tuple
138
      with several of them. If 'None' is given (this is the default), it is
139
140
141
142
      considered the same as a tuple with all possible values. This field is
      ignored for the data from the "world" group.

    model_ids
143
144
      Only retrieves the files for the provided list of model ids (claimed
      client id). The model ids are string.  If 'None' is given (this is
145
146
147
      the default), no filter over the model_ids is performed.

    groups
148
149
      One of the groups ('dev', 'eval', 'world') or a tuple with several of them.
      If 'None' is given (this is the default), it is considered the same as a
150
151
152
      tuple with all possible values.

    classes
153
154
      The classes (types of accesses) to be retrieved ('client', 'impostor')
      or a tuple with several of them. If 'None' is given (this is the
155
156
      default), it is considered the same as a tuple with all possible values.

157
    Returns: A list of files which have the given properties.
158
159
    """

160
161
162
163
    protocol = self.check_parameters_for_validity(protocol, "protocol", self.protocol_names())
    purposes = self.check_parameters_for_validity(purposes, "purpose", self.purposes())
    groups = self.check_parameters_for_validity(groups, "group", self.groups())
    classes = self.check_parameters_for_validity(classes, "class", ('client', 'impostor'))
164
165
166
167
168

    import collections
    if(model_ids is None):
      model_ids = ()
    elif(not isinstance(model_ids,collections.Iterable)):
169
      model_ids = (model_ids,)
170
171
172

    # Now query the database
    retval = []
173
    if 'world' in groups:
174
      q = self.query(File).join(Client).join((ProtocolPurpose, File.protocolPurposes)).join(Protocol)
175
      q = q.filter(and_(Protocol.name.in_(protocol), ProtocolPurpose.sgroup == 'world'))
176
177
      if model_ids:
        q = q.filter(Client.id.in_(model_ids))
178
179
      q = q.order_by(File.client_id, File.camera, File.session_id, File.shot_id)
      retval += list(q)
180

181
    if ('dev' in groups or 'eval' in groups):
182
      if('enroll' in purposes):
183
        q = self.query(File).join(Client).join((ProtocolPurpose, File.protocolPurposes)).join(Protocol).\
184
              filter(and_(Protocol.name.in_(protocol), ProtocolPurpose.sgroup.in_(groups), ProtocolPurpose.purpose == 'enroll'))
185
186
        if model_ids:
          q = q.filter(Client.id.in_(model_ids))
187
188
189
        q = q.order_by(File.client_id, File.camera, File.session_id, File.shot_id)
        retval += list(q)

190
191
      if('probe' in purposes):
        if('client' in classes):
192
          q = self.query(File).join(Client).join((ProtocolPurpose, File.protocolPurposes)).join(Protocol).\
193
                filter(and_(Protocol.name.in_(protocol), ProtocolPurpose.sgroup.in_(groups), ProtocolPurpose.purpose == 'probe'))
194
195
          if model_ids:
            q = q.filter(Client.id.in_(model_ids))
196
197
198
          q = q.order_by(File.client_id, File.camera, File.session_id, File.shot_id)
          retval += list(q)

199
        if('impostor' in classes):
200
          q = self.query(File).join(Client).join((ProtocolPurpose, File.protocolPurposes)).join(Protocol).\
201
202
203
204
205
                filter(and_(Protocol.name.in_(protocol), ProtocolPurpose.sgroup.in_(groups), ProtocolPurpose.purpose == 'probe'))
          if len(model_ids) == 1:
            q = q.filter(not_(File.client_id.in_(model_ids)))
          q = q.order_by(File.client_id, File.camera, File.session_id, File.shot_id)
          retval += list(q)
206

207
    return list(set(retval)) # To remove duplicates
208

209
  def annotations(self, file):
Manuel Günther's avatar
Manuel Günther committed
210
211
212
213
    """Returns the annotations for the image with the given file id.

    Keyword Parameters:

214
215
    file
      The ``File`` object to retrieve the annotations for.
Manuel Günther's avatar
Manuel Günther committed
216
217
218
219
220
221

    Returns: the eye annotations as a dictionary {'reye':(y,x), 'leye':(y,x)}.
    """

    self.assert_validity()
    # return the annotations as returned by the call function of the Annotation object
222
    return file.annotation()
Manuel Günther's avatar
Manuel Günther committed
223
224


225
226
  def protocol_names(self):
    """Returns all registered protocol names"""
227

228
    return [str(p.name) for p in self.protocols()]
229

230
231
  def protocols(self):
    """Returns all registered protocols"""
232

233
    return list(self.query(Protocol))
234

235
236
  def has_protocol(self, name):
    """Tells if a certain protocol is available"""
237

238
    return self.query(Protocol).filter(Protocol.name==name).count() != 0
239

240
241
242
  def protocol(self, name):
    """Returns the protocol object in the database given a certain name. Raises
    an error if that does not exist."""
243

244
    return self.query(Protocol).filter(Protocol.name==name).one()
245

246
247
  def protocol_purposes(self):
    """Returns all registered protocol purposes"""
248

249
    return list(self.query(ProtocolPurpose))
250

251
252
  def purposes(self):
    """Returns the list of allowed purposes"""
253

254
    return ProtocolPurpose.purpose_choices
255

256