Commit 615b3cf6 authored by Davis King's avatar Davis King

Added an option to weight the features from a hashed_feature_image

relative to the number of times they occur in an image.  I also set
the new default behavior to use this relative weighting and changed
the serialization format to accommodate this.
parent 712c6577
...@@ -68,6 +68,15 @@ namespace dlib ...@@ -68,6 +68,15 @@ namespace dlib
inline long get_num_dimensions ( inline long get_num_dimensions (
) const; ) const;
void use_relative_feature_weights (
);
void use_uniform_feature_weights (
);
bool uses_uniform_feature_weights (
) const;
inline const descriptor_type& operator() ( inline const descriptor_type& operator() (
long row, long row,
long col long col
...@@ -111,6 +120,8 @@ namespace dlib ...@@ -111,6 +120,8 @@ namespace dlib
array2d<unsigned long> feats; array2d<unsigned long> feats;
feature_extractor fe; feature_extractor fe;
hash_function_type phash; hash_function_type phash;
std::vector<float> feat_counts;
bool uniform_feature_weights;
// This is a transient variable. It is just here so it doesn't have to be // This is a transient variable. It is just here so it doesn't have to be
...@@ -127,9 +138,13 @@ namespace dlib ...@@ -127,9 +138,13 @@ namespace dlib
std::ostream& out std::ostream& out
) )
{ {
int version = 1;
serialize(version, out);
serialize(item.feats, out); serialize(item.feats, out);
serialize(item.fe, out); serialize(item.fe, out);
serialize(item.phash, out); serialize(item.phash, out);
serialize(item.feat_counts, out);
serialize(item.uniform_feature_weights, out);
} }
template <typename T> template <typename T>
...@@ -138,9 +153,16 @@ namespace dlib ...@@ -138,9 +153,16 @@ namespace dlib
std::istream& in std::istream& in
) )
{ {
int version = 0;
deserialize(version, in);
if (version != 1)
throw serialization_error("Unexpected version found while deserializing a dlib::hashed_feature_image object.");
deserialize(item.feats, in); deserialize(item.feats, in);
deserialize(item.fe, in); deserialize(item.fe, in);
deserialize(item.phash, in); deserialize(item.phash, in);
deserialize(item.feat_counts, in);
deserialize(item.uniform_feature_weights, in);
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
...@@ -157,6 +179,7 @@ namespace dlib ...@@ -157,6 +179,7 @@ namespace dlib
hashed_feature_image ( hashed_feature_image (
) )
{ {
clear();
hash_feats.resize(1); hash_feats.resize(1);
} }
...@@ -173,6 +196,8 @@ namespace dlib ...@@ -173,6 +196,8 @@ namespace dlib
fe.clear(); fe.clear();
phash = hash_function_type(); phash = hash_function_type();
feats.clear(); feats.clear();
feat_counts.clear();
uniform_feature_weights = false;
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
...@@ -229,6 +254,7 @@ namespace dlib ...@@ -229,6 +254,7 @@ namespace dlib
{ {
fe.copy_configuration(item.fe); fe.copy_configuration(item.fe);
phash = item.phash; phash = item.phash;
uniform_feature_weights = item.uniform_feature_weights;
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
...@@ -250,11 +276,26 @@ namespace dlib ...@@ -250,11 +276,26 @@ namespace dlib
if (fe.size() != 0) if (fe.size() != 0)
{ {
feats.set_size(fe.nr(), fe.nc()); feats.set_size(fe.nr(), fe.nc());
feat_counts.assign(phash.num_hash_bins(),1);
if (uniform_feature_weights)
{
for (long r = 0; r < feats.nr(); ++r)
{
for (long c = 0; c < feats.nc(); ++c)
{
feats[r][c] = phash(fe(r,c));
}
}
}
else
{
for (long r = 0; r < feats.nr(); ++r) for (long r = 0; r < feats.nr(); ++r)
{ {
for (long c = 0; c < feats.nc(); ++c) for (long c = 0; c < feats.nc(); ++c)
{ {
feats[r][c] = phash(fe(r,c)); feats[r][c] = phash(fe(r,c));
feat_counts[feats[r][c]]++;
}
} }
} }
} }
...@@ -263,6 +304,18 @@ namespace dlib ...@@ -263,6 +304,18 @@ namespace dlib
feats.set_size(0,0); feats.set_size(0,0);
} }
if (!uniform_feature_weights)
{
// use the inverse frequency as the scale for each feature. We also scale
// these counts so that they are invariant to the size of the image (we scale
// them so they all look like they come from a 500x400 images).
const double scale = img.size()/(500.0*400.0);
for (unsigned long i = 0; i < feat_counts.size(); ++i)
{
feat_counts[i] = scale/feat_counts[i];
}
}
fe.unload(); fe.unload();
} }
...@@ -318,6 +371,45 @@ namespace dlib ...@@ -318,6 +371,45 @@ namespace dlib
return phash.num_hash_bins(); return phash.num_hash_bins();
} }
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor,
typename hash_function_type
>
void hashed_feature_image<feature_extractor,hash_function_type>::
use_relative_feature_weights (
)
{
uniform_feature_weights = false;
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor,
typename hash_function_type
>
void hashed_feature_image<feature_extractor,hash_function_type>::
use_uniform_feature_weights (
)
{
uniform_feature_weights = true;
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor,
typename hash_function_type
>
bool hashed_feature_image<feature_extractor,hash_function_type>::
uses_uniform_feature_weights (
) const
{
return uniform_feature_weights;
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -342,7 +434,7 @@ namespace dlib ...@@ -342,7 +434,7 @@ namespace dlib
<< "\n\t this: " << this << "\n\t this: " << this
); );
hash_feats[0] = std::make_pair(feats[row][col],1); hash_feats[0] = std::make_pair(feats[row][col],feat_counts[feats[row][col]]);
return hash_feats; return hash_feats;
} }
......
...@@ -28,14 +28,15 @@ namespace dlib ...@@ -28,14 +28,15 @@ namespace dlib
INITIAL VALUE INITIAL VALUE
- size() == 0 - size() == 0
- uses_uniform_feature_weights() == false
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
particular, it wraps another image feature extractor and converts particular, it wraps another image feature extractor and converts the
the wrapped image feature vectors into sparse indicator vectors. It does wrapped image feature vectors into sparse indicator vectors. It does this
this by hashing each feature vector into the range [0, get_num_dimensions()-1] 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
the position determined by the hash. position determined by the hash.
THREAD SAFETY THREAD SAFETY
...@@ -153,6 +154,30 @@ namespace dlib ...@@ -153,6 +154,30 @@ namespace dlib
In this case, this is the number of hash bins. That is, get_hash().num_hash_bins() In this case, this is the number of hash bins. That is, get_hash().num_hash_bins()
!*/ !*/
void use_relative_feature_weights (
);
/*!
ensures
- #uses_uniform_feature_weights() == false
!*/
void use_uniform_feature_weights (
);
/*!
ensures
- #uses_uniform_feature_weights() == true
!*/
bool uses_uniform_feature_weights (
) const;
/*!
ensures
- returns true if this object weights each feature with a value of 1 and
false if it uses a weighting of 1/N where N is the number of occurrences
of the feature in an image (note that we normalize N so that it is
invariant to the size of the image given to load()).
!*/
const descriptor_type& operator() ( const descriptor_type& operator() (
long row, long row,
long col long col
...@@ -169,7 +194,13 @@ namespace dlib ...@@ -169,7 +194,13 @@ namespace dlib
- To be precise, this function returns a sparse vector V such that: - To be precise, this function returns a sparse vector V such that:
- V.size() == 1 - V.size() == 1
- V[0].first == get_hash()(BASE_FE(row,col)) - V[0].first == get_hash()(BASE_FE(row,col))
- if (uses_uniform_feature_weights()) then
- V[0].second == 1 - V[0].second == 1
- else
- V[0].second == 1/N where N is the number of times a feature in
hash bin V[0].first was observed in the image given to load().
Note that we scale all the counts so that they are invariant to
the size of the image.
!*/ !*/
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