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 @@ ...@@ -3,6 +3,7 @@
#ifndef DLIB_HASHED_IMAGE_FEATUrES_H__ #ifndef DLIB_HASHED_IMAGE_FEATUrES_H__
#define DLIB_HASHED_IMAGE_FEATUrES_H__ #define DLIB_HASHED_IMAGE_FEATUrES_H__
#include "../lsh/projection_hash.h"
#include "hashed_feature_image_abstract.h" #include "hashed_feature_image_abstract.h"
#include <vector> #include <vector>
#include "../algs.h" #include "../algs.h"
...@@ -15,24 +16,11 @@ namespace dlib ...@@ -15,24 +16,11 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
typename feature_extractor typename feature_extractor,
typename hash_function_type = projection_hash
> >
class hashed_feature_image : noncopyable 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: public:
...@@ -44,21 +32,13 @@ namespace dlib ...@@ -44,21 +32,13 @@ namespace dlib
void clear ( void clear (
); );
void set_hash_bin_sizes ( void set_hash (
const matrix<double,1,0>& bin_sizes const hash_function_type& hash_
); );
const matrix<double,1,0> get_hash_bin_sizes ( const hash_function_type& get_hash (
) const; ) const;
template <
typename image_type
>
inline void accumulate_image_statistics (
const image_type& img
);
void copy_configuration ( void copy_configuration (
const feature_extractor& item const feature_extractor& item
); );
...@@ -86,10 +66,6 @@ namespace dlib ...@@ -86,10 +66,6 @@ namespace dlib
inline long get_num_dimensions ( inline long get_num_dimensions (
) const; ) const;
void set_num_dimensions (
long new_num_dims
);
inline const descriptor_type& operator() ( inline const descriptor_type& operator() (
long row, long row,
long col long col
...@@ -130,20 +106,12 @@ namespace dlib ...@@ -130,20 +106,12 @@ namespace dlib
private: private:
inline bool has_image_statistics (
) const;
feature_extractor fe; feature_extractor fe;
typename feature_extractor::descriptor_type inv_stddev; hash_function_type phash;
std::vector<running_stats<double> > rs;
matrix<double,1,0> inv_bin_sizes;
long num_dims; // This is a transient variable. It is just here so it doesn't have to be
// reallocated over and over inside operator()
// 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;
mutable descriptor_type hash_feats; mutable descriptor_type hash_feats;
}; };
...@@ -157,10 +125,7 @@ namespace dlib ...@@ -157,10 +125,7 @@ namespace dlib
) )
{ {
serialize(item.fe, out); serialize(item.fe, out);
serialize(item.inv_stddev, out); serialize(item.phash, out);
serialize(item.rs, out);
serialize(item.inv_bin_sizes, out);
serialize(item.num_dims, out);
} }
template <typename T> template <typename T>
...@@ -170,10 +135,7 @@ namespace dlib ...@@ -170,10 +135,7 @@ namespace dlib
) )
{ {
deserialize(item.fe, in); deserialize(item.fe, in);
deserialize(item.inv_stddev, in); deserialize(item.phash, in);
deserialize(item.rs, in);
deserialize(item.inv_bin_sizes, in);
deserialize(item.num_dims, in);
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
...@@ -183,123 +145,64 @@ namespace dlib ...@@ -183,123 +145,64 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( hashed_feature_image (
) : )
num_dims(1000)
{ {
inv_bin_sizes = logspace(-1,1,3); hash_feats.resize(1);
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( clear (
) )
{ {
fe.clear(); fe.clear();
inv_stddev = 0; phash = hash_function_type();
inv_bin_sizes = logspace(-1,1,3);
rs.clear();
num_dims = 1000;
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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>::
set_hash_bin_sizes ( set_hash (
const matrix<double,1,0>& bin_sizes const hash_function_type& hash_
) )
{ {
// make sure requires clause is not broken phash = hash_;
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);
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
typename feature_extractor typename feature_extractor,
typename hash_function_type
> >
const matrix<double,1,0> hashed_feature_image<feature_extractor>:: const hash_function_type& hashed_feature_image<feature_extractor,hash_function_type>::
get_hash_bin_sizes ( get_hash (
) const ) const
{ {
return reciprocal(inv_bin_sizes); return phash;
}
// ----------------------------------------------------------------------------------------
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);
}
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( copy_configuration (
const feature_extractor& item const feature_extractor& item
) )
...@@ -310,45 +213,28 @@ namespace dlib ...@@ -310,45 +213,28 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( copy_configuration (
const hashed_feature_image& item 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); fe.copy_configuration(item.fe);
num_dims = item.num_dims; phash = item.phash;
}
// ----------------------------------------------------------------------------------------
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;
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
typename feature_extractor typename feature_extractor,
typename hash_function_type
> >
template < template <
typename image_type typename image_type
> >
void hashed_feature_image<feature_extractor>:: void hashed_feature_image<feature_extractor,hash_function_type>::
load ( load (
const image_type& img const image_type& img
) )
...@@ -359,9 +245,10 @@ namespace dlib ...@@ -359,9 +245,10 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( size (
) const ) const
{ {
...@@ -371,9 +258,10 @@ namespace dlib ...@@ -371,9 +258,10 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( nr (
) const ) const
{ {
...@@ -383,9 +271,10 @@ namespace dlib ...@@ -383,9 +271,10 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( nc (
) const ) const
{ {
...@@ -395,41 +284,23 @@ namespace dlib ...@@ -395,41 +284,23 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( get_num_dimensions (
) const ) const
{ {
return num_dims; return phash.num_hash_bins();
}
// ----------------------------------------------------------------------------------------
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;
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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() ( operator() (
long row, long row,
long col long col
...@@ -447,26 +318,17 @@ namespace dlib ...@@ -447,26 +318,17 @@ namespace dlib
<< "\n\t this: " << this << "\n\t this: " << this
); );
hash_feats.resize(inv_bin_sizes.size()); hash_feats[0] = std::make_pair(phash(fe(row,col)),1);
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);
}
return hash_feats; return hash_feats;
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( get_block_rect (
long row, long row,
long col long col
...@@ -490,9 +352,10 @@ namespace dlib ...@@ -490,9 +352,10 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( image_to_feat_space (
const point& p const point& p
) const ) const
...@@ -503,9 +366,10 @@ namespace dlib ...@@ -503,9 +366,10 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( image_to_feat_space (
const rectangle& rect const rectangle& rect
) const ) const
...@@ -516,9 +380,10 @@ namespace dlib ...@@ -516,9 +380,10 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( feat_to_image_space (
const point& p const point& p
) const ) const
...@@ -529,9 +394,10 @@ namespace dlib ...@@ -529,9 +394,10 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < 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 ( feat_to_image_space (
const rectangle& rect const rectangle& rect
) const ) const
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#undef DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_H__ #undef DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_H__
#ifdef DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_H__ #ifdef DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_H__
#include "../lsh/projection_hash_abstract.h"
#include <vector> #include <vector>
#include "../matrix.h" #include "../matrix.h"
#include "../statistics.h" #include "../statistics.h"
...@@ -13,7 +14,8 @@ namespace dlib ...@@ -13,7 +14,8 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
typename feature_extractor typename feature_extractor,
typename hash_function_type = projection_hash
> >
class hashed_feature_image : noncopyable class hashed_feature_image : noncopyable
{ {
...@@ -21,10 +23,11 @@ namespace dlib ...@@ -21,10 +23,11 @@ namespace dlib
REQUIREMENTS ON feature_extractor REQUIREMENTS ON feature_extractor
- must be an object with an interface compatible with dlib::hog_image - 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 INITIAL VALUE
- size() == 0 - size() == 0
- get_num_dimensions() == 1000
- get_hash_bin_sizes() == logspace(-1,1,3)
WHAT THIS OBJECT REPRESENTS WHAT THIS OBJECT REPRESENTS
This object is a tool for performing image feature extraction. In This object is a tool for performing image feature extraction. In
...@@ -32,9 +35,7 @@ namespace dlib ...@@ -32,9 +35,7 @@ namespace dlib
the wrapped image feature vectors into indicator vectors. It does the wrapped image feature vectors into indicator vectors. It does
this by hashing each feature vector into the range [0, get_num_dimensions()-1] 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 and then returns a new vector which is zero everywhere except for
the position determined by the hash. Additionally, this object can be the position determined by the hash.
configured to hash each feature vector into multiple bins, thereby
creating an indicator vector with multiple non-zero indicator features.
THREAD SAFETY THREAD SAFETY
...@@ -68,49 +69,20 @@ namespace dlib ...@@ -68,49 +69,20 @@ namespace dlib
- this object will have its initial value - this object will have its initial value
!*/ !*/
void set_hash_bin_sizes ( void set_hash (
const matrix<double,1,0>& bin_sizes const hash_function_type& hash
); );
/*! /*!
requires
- bin_sizes.size() > 0
- min(bin_sizes) > 0
ensures 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; ) const;
/*! /*!
ensures ensures
- When a feature vector from BASE_FE is hashed, it is hashed into exactly - returns the hash function used by this object to hash
get_hash_bin_sizes().size() hash bins. Each hash is computed as follows: base feature vectors into integers.
- 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.
!*/ !*/
void copy_configuration ( void copy_configuration (
...@@ -176,19 +148,8 @@ namespace dlib ...@@ -176,19 +148,8 @@ namespace dlib
/*! /*!
ensures ensures
- returns the dimensionality of the feature vectors returned by operator(). - returns the dimensionality of the feature vectors returned by operator().
In this case, this is the number of hash bins. In this case, this is the number of hash bins. That is, get_hash().num_hash_bins()
!*/
void set_num_dimensions (
long new_num_dims
);
/*!
requires
- new_num_dims > 0
ensures
- #get_num_dimensions() == new_num_dims
!*/ !*/
const descriptor_type& operator() ( const descriptor_type& operator() (
long row, long row,
long col long col
...@@ -197,14 +158,15 @@ namespace dlib ...@@ -197,14 +158,15 @@ namespace dlib
requires requires
- 0 <= row < nr() - 0 <= row < nr()
- 0 <= col < nc() - 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 ensures
- hashes BASE_FE(row,col) and returns the resulting indicator vector. - hashes BASE_FE(row,col) and returns the resulting indicator vector.
This vector will be represented as an unsorted sparse vector. - To be precise, this function returns a sparse vector V such that:
- Returns a vector V such that: - V.size() == 1
- V.size() == get_hash_bin_sizes().size() - V[0].first == get_hash()(BASE_FE(row,col))
- for all valid i: 0 <= V[i].first < get_num_dimensions() - V[0].second == 1
- if (BASE_FE(row,col) hashes into bin B) then
- V contains an element with .first == B and .second == 1
!*/ !*/
const rectangle get_block_rect ( 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