Source code for bob.db.hci_tagging.models

#!/usr/bin/env python
# vim: set fileencoding=utf-8 :

import os
import pkg_resources

import bob.db.base
import bob.io.base
import bob.ip.facedetect

from . import utils


class File(bob.db.base.File):
  """ Generic file container for HCI-Tagging files


  Parameters:

    basedir (str): The base directory for the data

    bdf (str): The name of the BDF file that accompanies the video file,
      containing the physiological signals.

    video (str): The name of the video file to be used

    duration (int): The time in seconds that corresponds to the estimated
      duration of the data (video and physiological signals).

  """

  def __init__(self, basedir, bdf, video, duration):

    self.basedir = basedir
    self.stem = bdf
    self.path = os.path.join(self.basedir, self.stem)
    self.video_stem = video
    self.duration = int(duration)


  def __repr__(self):
    return "File('%s')" % self.stem


[docs] def default_extension(self): return '.bdf'
[docs] def make_path(self, directory=None, extension=None): """Wraps this files' filename so that a complete path is formed Keyword parameters: directory An optional directory name that will be prefixed to the returned result. extension An optional extension that will be suffixed to the returned filename. The extension normally includes the leading ``.`` character as in ``.png`` or ``.bmp``. If not specified the default extension for the original file in the database will be used Returns a string containing the newly generated file path. """ return os.path.join( directory or '', self.basedir, self.stem + (extension or self.default_extension()), )
[docs] def load(self, directory=None, extension='.avi'): """Loads the video for this file entry Parameters: directory (str): The path to the root of the database installation. This is the path leading to the directory ``Sessions`` of the database. Returns: numpy.ndarray: A 4D array of 8-bit unsigned integers corresponding to the input video for this file in (frame,channel,y,x) notation (Bob-style). """ path = os.path.join(directory, self.basedir, self.video_stem + '.avi') if not os.path.exists(path): raise IOError("Video file `%s' is not available - have you downloaded the database raw files from the original site?" % (path,)) return bob.io.base.load(path)
[docs] def load_video(self, directory): """Loads the colored video file associated to this object Parameters: directory (str): A directory name that will be prefixed to the returned result. Returns bob.io.video.reader: Preloaded and ready to be iterated by your code. """ path = os.path.join(directory, self.basedir, self.video_stem + '.avi') if not os.path.exists(path): raise IOError("Video file `%s' is not available - have you downloaded the database raw files from the original site?" % (path,)) return bob.io.video.reader(path)
[docs] def run_face_detector(self, directory, max_frames=0): """Runs bob.ip.facedetect stock detector on the selected frames. .. warning:: This method is deprecated and serves only as a development basis to clean-up the :py:meth:`load_face_detection`, which for now relies on ``.face`` files shipped with this package. Technically, the output of this method and the detected faces shipped should be the same as of today, 13 december 2016. Parameters: directory (str): A directory name that leads to the location the database is installed on the local disk max_frames (int): If set, delimits the maximum number of frames to treat from the associated video file. A value of zero (default), makes the detector run for all frames. Returns: dict: A dictionary where the key is the frame number and the values are instances of :py:class:`bob.ip.facedetect.BoundingBox`. """ detections = {} data = self.load_video(directory) if max_frames: data = data[:max_frames] for k, frame in enumerate(data): bb, quality = bob.ip.facedetect.detect_single_face(frame) detections[k] = bb return detections
[docs] def load_face_detection(self): """Load bounding boxes for this file This function loads bounding boxes for each frame of a video sequence. Bounding boxes are loaded from the package directory and are the ones provided with it. Bounding boxes generated from :py:meth:`run_face_detector` (which should be exactly the same) are not used by this method. Returns: dict: A dictionary where the key is the frame number and the values are instances of :py:class:`bob.ip.facedetect.BoundingBox`. """ basedir = os.path.join('data', 'bbox') data_dir = pkg_resources.resource_filename(__name__, basedir) path = self.make_path(data_dir, '.face') if not os.path.exists(path): raise IOError("Face bounding-box file `%s' is not available - have you run the metadata generation step or `bob_dbmanage.py hci_tagging download'?" % (path,)) retval = {} with open(path, 'rt') as f: for row in f: if not row.strip(): continue p = row.split() # .face file: <frame> <x> <y> <width> <height> # BoundingBox ctor: top left (y, x), size (height, width) retval[int(p[0])] = bob.ip.facedetect.BoundingBox((float(p[2]), float(p[1])), (float(p[4]), float(p[3]))) return retval
[docs] def estimate_heartrate_in_bpm(self, directory): """Estimates the person's heart rate using the ECG sensor data Parameters: directory (str): A directory name that leads to the location the database is installed on the local disk """ from .utils import estimate_average_heartrate, chooser estimates = [] for channel in ('EXG1', 'EXG2', 'EXG3'): signal, freq = utils.bdf_load_signal(self.make_path(directory), channel) avg_hr, peaks = estimate_average_heartrate(signal, freq) estimates.append(avg_hr) return chooser(estimates)
[docs] def load_heart_rate_in_bpm(self): """Loads heart-rate from locally stored files, raises if it isn't there""" data_dir = pkg_resources.resource_filename(__name__, 'data') path = self.make_path(data_dir, '.hdf5') if not os.path.exists(path): raise IOError("Metadata file `%s' is not available - have you run the metadata generation step or `bob_dbmanage.py hci_tagging download'?" % (path,)) f = bob.io.base.HDF5File(path) return f.get('heartrate')
[docs] def load_drmf_keypoints(self): """Loads the 66-keypoints coming from the Discriminative Response Map Fitting (DRMF) landmark detector. Raises if metadata file isn't there. Reference: http://ibug.doc.ic.ac.uk/resources/drmf-matlab-code-cvpr-2013/. The code was written for Matlab. Data for the first frame of the colour video of this object was loaded on a compatible Matlab framework and the keypoints extracted taking as basis the currently available face bounding box, enlarged by 7% (so the key-point detector performs reasonably well). The extracted keypoints were then merged into this database access package so they are easy to load from python. The points are in the form (y, x), as it is standard on Bob-based packages. """ data_dir = pkg_resources.resource_filename(__name__, 'data') path = self.make_path(data_dir, '.hdf5') if not os.path.exists(path): raise IOError("Metadata file `%s' is not available - have you run the metadata generation step or `bob_dbmanage.py hci_tagging download'?" % (path,)) f = bob.io.base.HDF5File(path) return f.get('drmf_landmarks66')
[docs] def save(self, data, directory=None, extension='.hdf5'): """Saves the input data at the specified location and using the given extension. Keyword parameters: data The data blob to be saved (normally a :py:class:`numpy.ndarray`). directory If not empty or None, this directory is prefixed to the final file destination extension The extension of the filename - this will control the type of output and the codec for saving the input blob. """ path = self.make_path(directory, extension) if not os.path.exists(os.path.dirname(path)): os.makedirs(os.path.dirname(path)) bob.io.base.save(data, path)