test_extractors.py 7.08 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
61
62
63
64
65
66
67
68
69
70
71
72
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Manuel Guenther <Manuel.Guenther@idiap.ch>
# @date: Thu May 24 10:41:42 CEST 2012
#
# Copyright (C) 2011-2012 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/>.

import bob.bio.base
import bob.bio.face

import unittest
import os
import numpy
import math
from nose.plugins.skip import SkipTest

import bob.io.base.test_utils
from bob.bio.base.test import utils

import pkg_resources

regenerate_refs = False

def _compare(data, reference, write_function = bob.bio.base.save, read_function = bob.bio.base.load):
  # write reference?
  if regenerate_refs:
    write_function(data, reference)

  # compare reference
  reference = read_function(reference)
  assert numpy.allclose(data, reference, atol=1e-5)

def _data():
  return bob.bio.base.load(pkg_resources.resource_filename('bob.bio.face.test', 'data/cropped.hdf5'))


def test_dct_blocks():
  # read input
  data = _data()
  dct = bob.bio.base.load_resource('dct-blocks', 'extractor')
  assert isinstance(dct, bob.bio.face.extractor.DCTBlocks)
  assert isinstance(dct, bob.bio.base.extractor.Extractor)
  assert not dct.requires_training

  # generate smaller extractor, using mixed tuple and int input for the block size and overlap
  dct = bob.bio.face.extractor.DCTBlocks(8, (0,0), 15)

  # extract features
  feature = dct(data)
  assert feature.ndim == 2
  # feature dimension is one lower than the block size, since blocks are normalized by default
  assert feature.shape == (80, 14)
  reference = pkg_resources.resource_filename('bob.bio.face.test', 'data/dct_blocks.hdf5')
  _compare(feature, reference, dct.write_feature, dct.read_feature)


def test_graphs():
  data = _data()
  graph = bob.bio.base.load_resource('grid-graph', 'extractor')
  assert isinstance(graph, bob.bio.face.extractor.GridGraph)
  assert isinstance(graph, bob.bio.base.extractor.Extractor)
  assert not graph.requires_training

  # generate smaller extractor, using mixed tuple and int input for the node distance and first location
  graph = bob.bio.face.extractor.GridGraph(node_distance = 24, image_resolution = data.shape)

  # extract features
  feature = graph(data)

  reference = pkg_resources.resource_filename('bob.bio.face.test', 'data/graph_regular.hdf5')
  # write reference?
  if regenerate_refs:
    graph.write_feature(feature, reference)

  # compare reference
  reference = graph.read_feature(reference)
  assert len(reference) == len(feature)
  assert all(isinstance(f, bob.ip.gabor.Jet) for f in feature)
  assert all(numpy.allclose(r.jet, f.jet) for r,f in zip(reference, feature))


  # get reference face graph extractor
  cropper = bob.bio.base.load_resource('face-crop-eyes', 'preprocessor')
  eyes = cropper.cropped_positions
  # generate aligned graph extractor
  graph = bob.bio.face.extractor.GridGraph(
    # setup of the aligned grid
    eyes = eyes,
    nodes_between_eyes = 4,
    nodes_along_eyes = 2,
    nodes_above_eyes = 2,
    nodes_below_eyes = 7
  )

  nodes = graph.graph.nodes
  assert len(nodes) == 100
  assert numpy.allclose(nodes[22], eyes['reye'])
  assert numpy.allclose(nodes[27], eyes['leye'])

  assert nodes[0] < eyes['reye']
  assert nodes[-1] > eyes['leye']


def test_lgbphs():
  data = _data()
  lgbphs = bob.bio.base.load_resource('lgbphs', 'extractor')
  assert isinstance(lgbphs, bob.bio.face.extractor.LGBPHS)
  assert isinstance(lgbphs, bob.bio.base.extractor.Extractor)
  assert not lgbphs.requires_training

  # in this test, we use a smaller setup of the LGBPHS features
  lgbphs = bob.bio.face.extractor.LGBPHS(
      block_size = 8,
      block_overlap = 0,
      gabor_directions = 4,
      gabor_scales = 2,
      gabor_sigma = math.sqrt(2.) * math.pi,
      sparse_histogram = True
  )

  # extract feature
  feature = lgbphs(data)
  assert feature.ndim == 2

  reference = pkg_resources.resource_filename('bob.bio.face.test', 'data/lgbphs_sparse.hdf5')
  _compare(feature, reference, lgbphs.write_feature, lgbphs.read_feature)

  # generate new non-sparse extractor including Gabor phases
  lgbphs = bob.bio.face.extractor.LGBPHS(
      block_size = 8,
      block_overlap = 0,
      gabor_directions = 4,
      gabor_scales = 2,
      gabor_sigma = math.sqrt(2.) * math.pi,
      use_gabor_phases = True
  )
  feature = lgbphs(data)
  assert feature.ndim == 1

  reference = pkg_resources.resource_filename('bob.bio.face.test', 'data/lgbphs_with_phase.hdf5')
  _compare(feature, reference, lgbphs.write_feature, lgbphs.read_feature)


def test_eigenface():
  temp_file = bob.io.base.test_utils.temporary_filename()
  data = _data()
  eigen1 = bob.bio.base.load_resource('eigenface', 'extractor')
  assert isinstance(eigen1, bob.bio.face.extractor.Eigenface)
  assert isinstance(eigen1, bob.bio.base.extractor.Extractor)
  assert eigen1.requires_training

  # create extractor with a smaller number of kept eigenfaces
  train_data = utils.random_training_set(data.shape, 400, 0., 255.)
  eigen2 = bob.bio.face.extractor.Eigenface(subspace_dimension = 5)
  reference = pkg_resources.resource_filename('bob.bio.face.test', 'data/eigenface_extractor.hdf5')
  try:
    # train the projector
    eigen2.train(train_data, temp_file)

    assert os.path.exists(temp_file)

    if regenerate_refs: shutil.copy(temp_file, reference_file)

    # check projection matrix
    eigen1.load(reference)
    eigen2.load(temp_file)

    assert eigen1.machine.shape == eigen2.machine.shape
    for i in range(5):
      assert numpy.abs(eigen1.machine.weights[:,i] - eigen2.machine.weights[:,i] < 1e-5).all() or numpy.abs(eigen1.machine.weights[:,i] + eigen2.machine.weights[:,i] < 1e-5).all()

  finally:
    if os.path.exists(temp_file): os.remove(temp_file)

  # now, we can execute the extractor and check that the feature is still identical
  feature = eigen1(data)
  assert feature.ndim == 1
  reference = pkg_resources.resource_filename('bob.bio.face.test', 'data/eigenface_feature.hdf5')
  _compare(feature, reference, eigen1.write_feature, eigen1.read_feature)


"""
  def test05_sift_key_points(self):
    # check if VLSIFT is available
    import bob.ip.base
    if not hasattr(bob.ip.base, "VLSIFT"):
      raise SkipTest("VLSIFT is not part of bob.ip.base; maybe SIFT headers aren't installed in your system?")

    # we need the preprocessor tool to actually read the data
    preprocessor = facereclib.preprocessing.Keypoints()
    data = preprocessor.read_data(self.input_dir('key_points.hdf5'))
    # now, we extract features from it
    extractor = self.config('sift')
    feature = self.execute(extractor, data, 'sift.hdf5', epsilon=1e-4)
    self.assertEqual(len(feature.shape), 1)


"""