Source code for capmoe.cv.bof
# -*- coding: utf-8 -*-
"""
capmoe.cv.bof
~~~~~~~~~~~~~
:synopsis: Create BoF representation from features & visual words
"""
# python 2.x support
from __future__ import division, print_function, absolute_import, unicode_literals
# standard modules
import time
# 3rd party modules
import numpy as np
import pyflann
import simplejson as json
# original modules
import capmoe.util.logger
# global variables
logger = capmoe.util.logger.factory(__file__)
[docs]class BoFMaker(object):
"""Create BoF representation from features & visual words.
Since ANN algorithm is used internally,
the result BoF representation is approximation.
Index creation is wrapped by this class.
"""
[docs] def __init__(self, visualwords,
index_filepath=None,
algorithm='kdtree',
loglevel='WARNING'):
"""Create or load index of visual words.
:param visualwords: 2D array of base vectors
:type visualwords: M x len(feature) `numpy.ndarray`,
where each element is `numpy.float32`
:param index_filepath: If not `None`, index is not created
but load from specified file.
The file must be created by :func:`BoFMaker.save`
:param algorithm: passed to `pyflann.FLANN().build_index`
"""
self._n_visualwords = visualwords.shape[0]
self._flann = pyflann.FLANN()
if index_filepath is not None:
# load index
logger.debug('Loading visual words index from %s ...' %
(index_filepath))
t0 = time.time()
with open(BoFMaker.meta_filepath(index_filepath)) as f:
self._index_param = json.load(f)
self._flann.load_index(index_filepath, visualwords)
logger.debug('%f sec to load index' % (time.time() - t0))
else:
# create index
logger.debug('Creating index of visual words...')
t0 = time.time()
self._index_param = self._flann.build_index(
visualwords, algorithm=algorithm)
logger.debug('%f sec to create index' % (time.time() - t0))
[docs] def save(self, filepath):
"""Save index of visual words to ``filepath``"""
with open(BoFMaker.meta_filepath(filepath), 'w') as f:
json.dump(self._index_param, f)
self._flann.save_index(filepath)
[docs] def make(self, features, norm_order=None):
"""Create BoF representation of features.
:param features: 2D array of feature vectors
:type features: N x len(feature) `numpy.ndarray`,
where each element is `numpy.float32`
:param norm_order: `1` for L1-norm, `2` for L2-norm, ...
Histogram is not normalized when this is `None`.
"""
# nearest neighbor search
t0 = time.time()
nn_idx, dists = self._flann.nn_index(
features, 1, checks=self._index_param['checks'])
logger.debug('%f sec to search approx nearest neighbor' %
(time.time() - t0))
# make BoF histogram
bof_hist, bins = np.histogram(nn_idx, bins=self._n_visualwords)
if norm_order is None:
return bof_hist
return bof_hist / np.linalg.norm(bof_hist, ord=norm_order)
@staticmethod