Commit 87366f51 authored by Davis King's avatar Davis King

Refactored this object so it uses a hashing function supplied

by a template argument rather than its own method.  By default,
this object will use the projection_hash.
parent cfd0c994
......@@ -3,6 +3,7 @@
#ifndef DLIB_HASHED_IMAGE_FEATUrES_H__
#define DLIB_HASHED_IMAGE_FEATUrES_H__
#include "../lsh/projection_hash.h"
#include "hashed_feature_image_abstract.h"
#include <vector>
#include "../algs.h"
......@@ -15,24 +16,11 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type = projection_hash
>
class hashed_feature_image : noncopyable
{
/*!
INITIAL VALUE
- inv_bin_sizes == logspace(-1, 1, 3)
- num_dims == 1000
CONVENTION
- inv_bin_sizes.size() > 0
- num_dims == get_num_dimensions()
- if (has_image_statistics()) then
- rs[i] == the statistics of feature element i. I.e. the stats of fe(r,c)(i)
over a set of images supplied to accumulate_image_statistics().
- inv_stddev[i] == 1.0/(rs[i].stddev() + 1e-10)
!*/
public:
......@@ -44,21 +32,13 @@ namespace dlib
void clear (
);
void set_hash_bin_sizes (
const matrix<double,1,0>& bin_sizes
void set_hash (
const hash_function_type& hash_
);
const matrix<double,1,0> get_hash_bin_sizes (
const hash_function_type& get_hash (
) const;
template <
typename image_type
>
inline void accumulate_image_statistics (
const image_type& img
);
void copy_configuration (
const feature_extractor& item
);
......@@ -86,10 +66,6 @@ namespace dlib
inline long get_num_dimensions (
) const;
void set_num_dimensions (
long new_num_dims
);
inline const descriptor_type& operator() (
long row,
long col
......@@ -130,20 +106,12 @@ namespace dlib
private:
inline bool has_image_statistics (
) const;
feature_extractor fe;
typename feature_extractor::descriptor_type inv_stddev;
std::vector<running_stats<double> > rs;
matrix<double,1,0> inv_bin_sizes;
long num_dims;
// Transient variables. These are here just so they don't have to get constructed over
// and over inside operator(). I.e. they don't logically contribute to the state of
// this object.
mutable typename feature_extractor::descriptor_type scaled_feats;
mutable matrix<int32,0,1> quantized_feats;
hash_function_type phash;
// This is a transient variable. It is just here so it doesn't have to be
// reallocated over and over inside operator()
mutable descriptor_type hash_feats;
};
......@@ -157,10 +125,7 @@ namespace dlib
)
{
serialize(item.fe, out);
serialize(item.inv_stddev, out);
serialize(item.rs, out);
serialize(item.inv_bin_sizes, out);
serialize(item.num_dims, out);
serialize(item.phash, out);
}
template <typename T>
......@@ -170,10 +135,7 @@ namespace dlib
)
{
deserialize(item.fe, in);
deserialize(item.inv_stddev, in);
deserialize(item.rs, in);
deserialize(item.inv_bin_sizes, in);
deserialize(item.num_dims, in);
deserialize(item.phash, in);
}
// ----------------------------------------------------------------------------------------
......@@ -183,123 +145,64 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
hashed_feature_image<feature_extractor>::
hashed_feature_image<feature_extractor,hash_function_type>::
hashed_feature_image (
) :
num_dims(1000)
)
{
inv_bin_sizes = logspace(-1,1,3);
hash_feats.resize(1);
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
void hashed_feature_image<feature_extractor>::
void hashed_feature_image<feature_extractor,hash_function_type>::
clear (
)
{
fe.clear();
inv_stddev = 0;
inv_bin_sizes = logspace(-1,1,3);
rs.clear();
num_dims = 1000;
phash = hash_function_type();
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
void hashed_feature_image<feature_extractor>::
set_hash_bin_sizes (
const matrix<double,1,0>& bin_sizes
void hashed_feature_image<feature_extractor,hash_function_type>::
set_hash (
const hash_function_type& hash_
)
{
// make sure requires clause is not broken
DLIB_ASSERT(bin_sizes.size() > 0,
"\t void hashed_feature_image::set_hash_bin_sizes()"
<< "\n\t size of new_scales should not be zero"
<< "\n\t this: " << this
);
DLIB_ASSERT(min(bin_sizes) > 0,
"\t void hashed_feature_image::set_hash_bin_sizes()"
<< "\n\t All bins must have sizes greater than zero."
<< "\n\t min(bin_sizes): " << min(bin_sizes)
<< "\n\t this: " << this
);
inv_bin_sizes = reciprocal(bin_sizes);
phash = hash_;
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
const matrix<double,1,0> hashed_feature_image<feature_extractor>::
get_hash_bin_sizes (
const hash_function_type& hashed_feature_image<feature_extractor,hash_function_type>::
get_hash (
) const
{
return reciprocal(inv_bin_sizes);
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
>
template <
typename image_type
>
void hashed_feature_image<feature_extractor>::
accumulate_image_statistics (
const image_type& img
)
{
feature_extractor temp;
temp.load(img);
if (temp.size() == 0)
return;
rs.resize(temp(0,0).size());
typename feature_extractor::descriptor_type des;
for (long r = 0; r < temp.nr(); ++r)
{
for (long c = 0; c < temp.nc(); ++c)
{
des = temp(r,c);
for (long i = 0; i < des.size(); ++i)
{
rs[i].add(des(i));
}
}
}
if (rs[0].current_n() <= 1)
return;
// keep inv_stddev up to date with rs.
inv_stddev.set_size(des.nr(), des.nc());
for (long i = 0; i < des.size(); ++i)
{
inv_stddev(i) = 1.0/(rs[i].stddev() + 1e-10);
}
return phash;
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
void hashed_feature_image<feature_extractor>::
void hashed_feature_image<feature_extractor,hash_function_type>::
copy_configuration (
const feature_extractor& item
)
......@@ -310,45 +213,28 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
void hashed_feature_image<feature_extractor>::
void hashed_feature_image<feature_extractor,hash_function_type>::
copy_configuration (
const hashed_feature_image& item
)
{
rs = item.rs;
inv_stddev = item.inv_stddev;
inv_bin_sizes = item.inv_bin_sizes;
fe.copy_configuration(item.fe);
num_dims = item.num_dims;
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
>
bool hashed_feature_image<feature_extractor>::
has_image_statistics (
) const
{
// if we have enough data to compute standard deviations of the features
if (rs.size() > 0 && rs[0].current_n() > 1)
return true;
else
return false;
phash = item.phash;
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
template <
typename image_type
>
void hashed_feature_image<feature_extractor>::
void hashed_feature_image<feature_extractor,hash_function_type>::
load (
const image_type& img
)
......@@ -359,9 +245,10 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
unsigned long hashed_feature_image<feature_extractor>::
unsigned long hashed_feature_image<feature_extractor,hash_function_type>::
size (
) const
{
......@@ -371,9 +258,10 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
long hashed_feature_image<feature_extractor>::
long hashed_feature_image<feature_extractor,hash_function_type>::
nr (
) const
{
......@@ -383,9 +271,10 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
long hashed_feature_image<feature_extractor>::
long hashed_feature_image<feature_extractor,hash_function_type>::
nc (
) const
{
......@@ -395,41 +284,23 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
long hashed_feature_image<feature_extractor>::
long hashed_feature_image<feature_extractor,hash_function_type>::
get_num_dimensions (
) const
{
return num_dims;
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
>
void hashed_feature_image<feature_extractor>::
set_num_dimensions (
long new_num_dims
)
{
// make sure requires clause is not broken
DLIB_ASSERT(new_num_dims > 0,
"\t void hashed_feature_image::set_num_dimensions()"
<< "\n\t You can't have zero dimensions"
<< "\n\t this: " << this
);
num_dims = new_num_dims;
return phash.num_hash_bins();
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
const typename hashed_feature_image<feature_extractor>::descriptor_type& hashed_feature_image<feature_extractor>::
const std::vector<std::pair<unsigned int,double> >& hashed_feature_image<feature_extractor,hash_function_type>::
operator() (
long row,
long col
......@@ -447,26 +318,17 @@ namespace dlib
<< "\n\t this: " << this
);
hash_feats.resize(inv_bin_sizes.size());
if (has_image_statistics())
scaled_feats = pointwise_multiply(fe(row,col), inv_stddev);
else
scaled_feats = fe(row,col);
for (long i = 0; i < inv_bin_sizes.size(); ++i)
{
quantized_feats = matrix_cast<int32>(inv_bin_sizes(i)*scaled_feats);
hash_feats[i] = std::make_pair(hash(quantized_feats)%num_dims,1);
}
hash_feats[0] = std::make_pair(phash(fe(row,col)),1);
return hash_feats;
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
const rectangle hashed_feature_image<feature_extractor>::
const rectangle hashed_feature_image<feature_extractor,hash_function_type>::
get_block_rect (
long row,
long col
......@@ -490,9 +352,10 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
const point hashed_feature_image<feature_extractor>::
const point hashed_feature_image<feature_extractor,hash_function_type>::
image_to_feat_space (
const point& p
) const
......@@ -503,9 +366,10 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
const rectangle hashed_feature_image<feature_extractor>::
const rectangle hashed_feature_image<feature_extractor,hash_function_type>::
image_to_feat_space (
const rectangle& rect
) const
......@@ -516,9 +380,10 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
const point hashed_feature_image<feature_extractor>::
const point hashed_feature_image<feature_extractor,hash_function_type>::
feat_to_image_space (
const point& p
) const
......@@ -529,9 +394,10 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type
>
const rectangle hashed_feature_image<feature_extractor>::
const rectangle hashed_feature_image<feature_extractor,hash_function_type>::
feat_to_image_space (
const rectangle& rect
) const
......
......@@ -3,6 +3,7 @@
#undef DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_H__
#ifdef DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_H__
#include "../lsh/projection_hash_abstract.h"
#include <vector>
#include "../matrix.h"
#include "../statistics.h"
......@@ -13,7 +14,8 @@ namespace dlib
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
typename feature_extractor,
typename hash_function_type = projection_hash
>
class hashed_feature_image : noncopyable
{
......@@ -21,10 +23,11 @@ namespace dlib
REQUIREMENTS ON feature_extractor
- must be an object with an interface compatible with dlib::hog_image
REQUIREMENTS ON hash_function_type
- must be an object with an interface compatible with projection_hash
INITIAL VALUE
- size() == 0
- get_num_dimensions() == 1000
- get_hash_bin_sizes() == logspace(-1,1,3)
WHAT THIS OBJECT REPRESENTS
This object is a tool for performing image feature extraction. In
......@@ -32,9 +35,7 @@ namespace dlib
the wrapped image feature vectors into indicator vectors. It does
this by hashing each feature vector into the range [0, get_num_dimensions()-1]
and then returns a new vector which is zero everywhere except for
the position determined by the hash. Additionally, this object can be
configured to hash each feature vector into multiple bins, thereby
creating an indicator vector with multiple non-zero indicator features.
the position determined by the hash.
THREAD SAFETY
......@@ -68,49 +69,20 @@ namespace dlib
- this object will have its initial value
!*/
void set_hash_bin_sizes (
const matrix<double,1,0>& bin_sizes
void set_hash (
const hash_function_type& hash
);
/*!
requires
- bin_sizes.size() > 0
- min(bin_sizes) > 0
ensures
- #get_hash_bin_sizes() == bin_sizes
- #get_hash() == hash
!*/
const matrix<double,1,0> get_hash_bin_sizes (
const hash_function_type& get_hash (
) const;
/*!
ensures
- When a feature vector from BASE_FE is hashed, it is hashed into exactly
get_hash_bin_sizes().size() hash bins. Each hash is computed as follows:
- First normalize the feature vector.
- Then divide it by an element of get_hash_bin_sizes().
- Then convert the resulting vector to a vector of dlib::int32.
- Finally, hash the integer vector into a hash bin.
- The size of the numbers in get_hash_bin_sizes() determines how big the hash
bins are. A very large value would result in all input vectors being hashed
into the same bin, while smaller values would result in only similar vectors
falling into the same bins. However, a value too small would result in
all vectors going into different bins. In this case, the bins are too fine
grained.
!*/
template <
typename image_type
>
void accumulate_image_statistics (
const image_type& img
);
/*!
requires
- image_type == any type that can be supplied to feature_extractor::load()
ensures
- Part of the hashing step is to normalize the features produced by BASE_FE.
This function will accumulate image statistics used to perform this normalization.
Note that it will accumulate across multiple calls. Therefore, it can be
beneficial to pass in many images.
- returns the hash function used by this object to hash
base feature vectors into integers.
!*/
void copy_configuration (
......@@ -176,19 +148,8 @@ namespace dlib
/*!
ensures
- returns the dimensionality of the feature vectors returned by operator().
In this case, this is the number of hash bins.
!*/
void set_num_dimensions (
long new_num_dims
);
/*!
requires
- new_num_dims > 0
ensures
- #get_num_dimensions() == new_num_dims
In this case, this is the number of hash bins. That is, get_hash().num_hash_bins()
!*/
const descriptor_type& operator() (
long row,
long col
......@@ -197,14 +158,15 @@ namespace dlib
requires
- 0 <= row < nr()
- 0 <= col < nc()
- It must be legal to evaluate expressions of the form: get_hash()(BASE_FE(row,col))
(e.g. the hash function must be properly configured to process the feature
vectors produced by the base feature extractor)
ensures
- hashes BASE_FE(row,col) and returns the resulting indicator vector.
This vector will be represented as an unsorted sparse vector.
- Returns a vector V such that:
- V.size() == get_hash_bin_sizes().size()
- for all valid i: 0 <= V[i].first < get_num_dimensions()
- if (BASE_FE(row,col) hashes into bin B) then
- V contains an element with .first == B and .second == 1
- To be precise, this function returns a sparse vector V such that:
- V.size() == 1
- V[0].first == get_hash()(BASE_FE(row,col))
- V[0].second == 1
!*/
const rectangle get_block_rect (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment