33 #ifndef GSLAM_VOCABULARY_H 34 #define GSLAM_VOCABULARY_H 53 #include <xmmintrin.h> 54 #include <emmintrin.h> 57 #include "GSLAM/core/GImage.h" 58 #include "GSLAM/core/Messenger.h" 60 #define GSLAM_VOCABULARY_KMAX 10 64 typedef size_t NodeId;
65 typedef size_t WordId;
66 typedef float WordValue;
67 typedef std::map<WordId,float> BowVector;
68 typedef std::map<WordId,std::vector<unsigned int> > FeatureVector;
71 typedef GImage TinyMat;
129 static std::shared_ptr<Vocabulary>
create(
const std::vector<TinyMat> &training_features,
136 bool save(
const std::string &filename,
bool binary_compressed=
false)
const;
142 bool load(
const std::string &filename);
145 bool load(std::istream& ifs);
151 virtual inline unsigned int size()
const{
152 unsigned int count=0;
153 for(
auto& n:
m_nodes)
if(!n.childNum) count++;
168 void transform(
const std::vector<TinyMat>& features, BowVector &v)
const;
174 virtual void transform(
const TinyMat & features, BowVector &v)
183 virtual void transform(
const std::vector<TinyMat>& features,
184 BowVector &v, FeatureVector &fv,
int levelsup=0)
const;
192 virtual void transform(
const TinyMat& features,
193 BowVector &v, FeatureVector &fv,
int levelsup=0)
const;
200 virtual WordId transform(
const TinyMat& feature)
const;
209 inline double score(
const BowVector &a,
const BowVector &b)
const;
218 virtual NodeId
getParentNode(WordId wid,
int levelsup)
const;
251 virtual inline TinyMat
getWord(WordId wid)
const;
303 return m_nodeDescriptors.cols;
308 return m_nodeDescriptors.type();
316 static void meanValue(
const std::vector<TinyMat> &descriptors,
325 float distance(
const TinyMat &a,
const TinyMat &b)
const;
341 virtual void transform(
const TinyMat &feature,
342 WordId &
id, WordValue &weight, NodeId* nid,
int levelsup = 0)
const;
351 virtual void transform(
const TinyMat &feature,
352 WordId &
id, WordValue &weight )
const;
361 static void addWeight(BowVector& bow,WordId
id, WordValue v)
363 BowVector::iterator vit = bow.lower_bound(
id);
365 if(vit != bow.end() && !(bow.key_comp()(id, vit->first)))
371 bow.insert(vit, BowVector::value_type(
id, v));
375 static void addIfNotExist(BowVector& bow,WordId
id, WordValue v)
377 BowVector::iterator vit = bow.lower_bound(
id);
379 if(vit == bow.end() || (bow.key_comp()(id, vit->first)))
381 bow.insert(vit, BowVector::value_type(
id, v));
386 static void normalize(BowVector& bow,
LNorm norm_type)
389 BowVector::iterator it;
393 for(it = bow.begin(); it != bow.end(); ++it)
394 norm += fabs(it->second);
398 for(it = bow.begin(); it != bow.end(); ++it)
399 norm += it->second * it->second;
405 for(it = bow.begin(); it != bow.end(); ++it)
410 static void addFeature(FeatureVector& fvec,NodeId
id,
unsigned int i_feature)
412 FeatureVector::iterator vit = fvec.lower_bound(
id);
414 if(vit != fvec.end() && vit->first == id)
416 vit->second.push_back(i_feature);
420 vit = fvec.insert(vit, FeatureVector::value_type(
id,
421 std::vector<unsigned int>() ));
422 vit->second.push_back(i_feature);
433 void HKmeansStep(NodeId parent_id,
const std::vector<TinyMat> &descriptors,
466 Node(): childNum(0), weight(0){}
472 inline bool isLeaf()
const {
return childNum==0; }
474 void addChild(NodeId _id)
483 typedef std::function<float(const uchar*,const uchar*)> DistanceFunc;
485 static float hamming32(
const uchar* a,
const uchar* b)
487 const uint64_t *pa = (uint64_t*)a;
488 const uint64_t *pb = (uint64_t*)b;
489 return std::bitset<64>(pa[0]^pb[0]).count()+std::bitset<64>(pa[1]^pb[1]).count()
490 +std::bitset<64>(pa[2]^pb[2]).count()+std::bitset<64>(pa[3]^pb[3]).count();
493 static float hamming64(
const uchar* a,
const uchar* b){
494 const uint64_t *pa = (uint64_t*)a;
495 const uint64_t *pb = (uint64_t*)b;
496 return std::bitset<64>(pa[0]^pb[0]).count()+std::bitset<64>(pa[1]^pb[1]).count()
497 +std::bitset<64>(pa[2]^pb[2]).count()+std::bitset<64>(pa[3]^pb[3]).count()
498 +std::bitset<64>(pa[4]^pb[4]).count()+std::bitset<64>(pa[5]^pb[5]).count()
499 +std::bitset<64>(pa[6]^pb[6]).count()+std::bitset<64>(pa[7]^pb[7]).count();
502 static float hamming8x(
const uchar* a,
const uchar* b,
int bytes)
504 const uint64_t *pa = (uint64_t*)a;
505 const uint64_t *pb = (uint64_t*)b;
508 for(
size_t i = 0; i < bytes /
sizeof(uint64_t); ++i, ++pa, ++pb)
510 ret+=std::bitset<64>(*pa ^ *pb).count();
515 #if defined(__AVX2__) 516 static float l2avx(
const uchar* a,
const uchar* b,
int floats){
517 int _nwords=floats/8;
518 __m256 sum=_mm256_setzero_ps(), sub_mult;
519 __m256* aptr=(__m256*)a;
520 __m256* bptr=(__m256*)b;
521 for(
int i=0;i<_nwords;i++){
522 sub_mult=_mm256_sub_ps(aptr[i],bptr[i]);
523 sub_mult=_mm256_mul_ps(sub_mult,sub_mult);
524 sum=_mm256_add_ps(sum,sub_mult);
526 sum=_mm256_hadd_ps(sum,sum);
527 sum=_mm256_hadd_ps(sum,sum);
528 float *sum_ptr=(
float*)∑
529 return sum_ptr[0]+sum_ptr[4];
533 #if defined(__SSE2__)&&defined(__SSE__) 534 static float l2sse(
const uchar* a,
const uchar* b,
int floats){
535 int _nwords=floats/4;
536 __m128 sum=_mm_setzero_ps(), sub_mult;
537 float* sum_ptr=(
float*)∑
539 __m128* aptr=(__m128*)a;
540 __m128* bptr=(__m128*)b;
541 for(
int i=0;i<_nwords;i++){
542 sub_mult=_mm_sub_ps(aptr[i],bptr[i]);
543 sub_mult=_mm_mul_ps(sub_mult,sub_mult);
544 sum=_mm_add_ps(sum,sub_mult);
546 return sum_ptr[0]+sum_ptr[1]+sum_ptr[2]+sum_ptr[3] ;
550 static float l2generic(
const uchar* a,
const uchar* b,
int floats){
552 const float *a_ptr=(
float*)a;
553 const float *b_ptr=(
float*)b;
554 for(
int i = 0; i < floats; i ++)
556 tmp = (a_ptr[i ] - b_ptr[i ]);
562 static DistanceFunc
create(
const TinyMat& des){
564 if (des.type()==GImageType<uchar>::Type){
565 if(des.cols==32)
return std::bind(&DistanceFactory::hamming32,std::placeholders::_1,std::placeholders::_2);
566 else if(des.cols==64)
return std::bind(&DistanceFactory::hamming64,std::placeholders::_1,std::placeholders::_2);
567 else if(des.cols%8==0)
return std::bind(&DistanceFactory::hamming8x,std::placeholders::_1,std::placeholders::_2,des.cols);
570 else if(des.type()==GImageType<float>::Type){
571 #if defined(__AVX2__) 572 if(des.cols%8)
return std::bind(&DistanceFactory::l2avx,std::placeholders::_1,std::placeholders::_2,des.cols);
574 #if defined(__SSE2__) 575 if(des.cols%4)
return std::bind(&DistanceFactory::l2sse,std::placeholders::_1,std::placeholders::_2,des.cols);
577 return std::bind(&DistanceFactory::l2generic,std::placeholders::_1,std::placeholders::_2,des.cols);
601 TinyMat m_nodeDescriptors;
604 std::shared_ptr<msg::ThreadPool> m_workthreads;
605 DistanceFactory::DistanceFunc m_distanceFunc;
622 virtual double score(
const BowVector &v,
const BowVector &w)
const = 0;
632 static inline const double LOG_EPS(){
633 static const double logeps=log(DBL_EPSILON);
647 #define __SCORING_CLASS(NAME, MUSTNORMALIZE, NORM) \ 648 NAME: public GeneralScoring \ 656 virtual double score(const BowVector &v, const BowVector &w) const; \ 663 virtual inline bool mustNormalize(Vocabulary::LNorm &norm) const \ 664 { norm = NORM; return MUSTNORMALIZE; } \ 668 class __SCORING_CLASS(L1Scoring, true, Vocabulary::L1);
671 class __SCORING_CLASS(L2Scoring, true, Vocabulary::L2);
674 class __SCORING_CLASS(ChiSquareScoring, true, Vocabulary::L1);
677 class __SCORING_CLASS(KLScoring, true, Vocabulary::L1);
680 class __SCORING_CLASS(BhattacharyyaScoring, true, Vocabulary::L1);
683 class __SCORING_CLASS(DotProductScoring, false, Vocabulary::L1);
685 #undef __SCORING_CLASS 691 inline double L1Scoring::score(const BowVector &v1, const BowVector &v2) const
693 BowVector::const_iterator v1_it, v2_it;
694 const BowVector::const_iterator v1_end = v1.end();
695 const BowVector::const_iterator v2_end = v2.end();
702 while(v1_it != v1_end && v2_it != v2_end)
704 const WordValue& vi = v1_it->second;
705 const WordValue& wi = v2_it->second;
707 if(v1_it->first == v2_it->first)
709 score += fabs(vi - wi) - fabs(vi) - fabs(wi);
715 else if(v1_it->first < v2_it->first)
718 v1_it = v1.lower_bound(v2_it->first);
724 v2_it = v2.lower_bound(v1_it->first);
741 inline double L2Scoring::score(
const BowVector &v1,
const BowVector &v2)
const 743 BowVector::const_iterator v1_it, v2_it;
744 const BowVector::const_iterator v1_end = v1.end();
745 const BowVector::const_iterator v2_end = v2.end();
752 while(v1_it != v1_end && v2_it != v2_end)
754 const WordValue& vi = v1_it->second;
755 const WordValue& wi = v2_it->second;
757 if(v1_it->first == v2_it->first)
765 else if(v1_it->first < v2_it->first)
768 v1_it = v1.lower_bound(v2_it->first);
774 v2_it = v2.lower_bound(v1_it->first);
785 score = 1.0 - sqrt(1.0 - score);
793 inline double ChiSquareScoring::score(
const BowVector &v1,
const BowVector &v2)
796 BowVector::const_iterator v1_it, v2_it;
797 const BowVector::const_iterator v1_end = v1.end();
798 const BowVector::const_iterator v2_end = v2.end();
807 while(v1_it != v1_end && v2_it != v2_end)
809 const WordValue& vi = v1_it->second;
810 const WordValue& wi = v2_it->second;
812 if(v1_it->first == v2_it->first)
816 if(vi + wi != 0.0) score += vi * wi / (vi + wi);
822 else if(v1_it->first < v2_it->first)
825 v1_it = v1.lower_bound(v2_it->first);
830 v2_it = v2.lower_bound(v1_it->first);
843 inline double KLScoring::score(
const BowVector &v1,
const BowVector &v2)
const 845 BowVector::const_iterator v1_it, v2_it;
846 const BowVector::const_iterator v1_end = v1.end();
847 const BowVector::const_iterator v2_end = v2.end();
856 while(v1_it != v1_end && v2_it != v2_end)
858 const WordValue& vi = v1_it->second;
859 const WordValue& wi = v2_it->second;
861 if(v1_it->first == v2_it->first)
863 if(vi != 0 && wi != 0) score += vi * log(vi/wi);
869 else if(v1_it->first < v2_it->first)
872 score += vi * (log(vi) - LOG_EPS());
878 v2_it = v2.lower_bound(v1_it->first);
884 for(; v1_it != v1_end; ++v1_it)
885 if(v1_it->second != 0)
886 score += v1_it->second * (log(v1_it->second) - LOG_EPS());
894 inline double BhattacharyyaScoring::score(
const BowVector &v1,
895 const BowVector &v2)
const 897 BowVector::const_iterator v1_it, v2_it;
898 const BowVector::const_iterator v1_end = v1.end();
899 const BowVector::const_iterator v2_end = v2.end();
906 while(v1_it != v1_end && v2_it != v2_end)
908 const WordValue& vi = v1_it->second;
909 const WordValue& wi = v2_it->second;
911 if(v1_it->first == v2_it->first)
913 score += sqrt(vi * wi);
919 else if(v1_it->first < v2_it->first)
922 v1_it = v1.lower_bound(v2_it->first);
928 v2_it = v2.lower_bound(v1_it->first);
939 inline double DotProductScoring::score(
const BowVector &v1,
940 const BowVector &v2)
const 942 BowVector::const_iterator v1_it, v2_it;
943 const BowVector::const_iterator v1_end = v1.end();
944 const BowVector::const_iterator v2_end = v2.end();
951 while(v1_it != v1_end && v2_it != v2_end)
953 const WordValue& vi = v1_it->second;
954 const WordValue& wi = v2_it->second;
956 if(v1_it->first == v2_it->first)
964 else if(v1_it->first < v2_it->first)
967 v1_it = v1.lower_bound(v2_it->first);
973 v2_it = v2.lower_bound(v1_it->first);
1023 m_scoring_object = std::shared_ptr<GeneralScoring>(
new BhattacharyyaScoring);
1053 std::shared_ptr<Vocabulary> voc(
new Vocabulary(k,L,weighting,scoring));
1056 int expected_nodes =(int)((pow((
double)voc->m_k, (
double)voc->m_L + 1) - 1)/(voc->m_k - 1));
1057 TinyMat firstF=imgFeatures.front();
1058 voc->m_nodes.resize(expected_nodes);
1059 voc->m_nodeDescriptors=TinyMat(expected_nodes,firstF.cols,firstF.type(),
nullptr,
false,32);
1060 int featBytes=firstF.elemSize()*firstF.cols;
1062 if(!voc->m_distanceFunc) voc->m_distanceFunc=DistanceFactory::create(firstF);
1066 for(
const TinyMat& m:imgFeatures)
1068 TinyMat featureHolder(featureNum,firstF.cols,firstF.type(),
nullptr,
false,32);
1069 LOG_IF(INFO,(((int64_t)featureHolder.data)&0x1F)!=0)
1070 <<
"FeatureHolder adress "<<((int64_t)featureHolder.data)
1071 <<
" are not ready to perform AVX acceleration.\n";
1072 std::vector<TinyMat> vtf;
1073 vtf.reserve(featureNum);
1074 for(
const TinyMat& m:imgFeatures){
1075 auto curSize=vtf.size();
1076 memcpy(featureHolder.data+featBytes*curSize,m.data,featBytes*m.rows);
1077 for(
int iend=curSize+m.rows;curSize<iend;curSize++)
1078 vtf.push_back(featureHolder.row(curSize));
1081 voc->m_workthreads=std::shared_ptr<msg::ThreadPool>(
new msg::ThreadPool(k));
1082 voc->HKmeansStep(0, vtf, 1);
1085 const unsigned int NWords = voc->m_nodes.size();
1086 const unsigned int NDocs = imgFeatures.size();
1088 if(voc->m_weighting == TF || voc->m_weighting == BINARY)
1091 for(
unsigned int i = 0; i < NWords; i++)
1092 voc->m_nodes[i].weight = 1;
1094 else if(voc->m_weighting == IDF || voc->m_weighting == TF_IDF)
1101 std::vector<unsigned int> Ni(NWords, 0);
1102 std::vector<bool> counted(NWords,
false);
1105 for(
const TinyMat& mit:imgFeatures)
1107 fill(counted.begin(), counted.end(),
false);
1108 for(
int r=0;r<mit.rows;r++)
1112 voc->transform(mit.row(r), word_id,weight);
1114 if(!counted[word_id])
1117 counted[word_id] =
true;
1123 for(
unsigned int i = 0; i < NWords; i++)
1127 voc->m_nodes[i].weight = log((
double)NDocs / (
double)Ni[i]);
1139 const std::vector<TinyMat> &descriptors,
int current_level)
1142 if(descriptors.empty())
return;
1144 std::vector<TinyMat> clusters;
1145 std::vector<std::vector<unsigned int> > groups;
1148 clusters.reserve(
m_k);
1149 groups.reserve(
m_k);
1152 if((
int)descriptors.size() <=
m_k)
1155 groups.resize(descriptors.size());
1157 for(
unsigned int i = 0; i < descriptors.size(); i++)
1159 groups[i].push_back(i);
1160 clusters.push_back(descriptors[i]);
1167 bool first_time =
true;
1171 std::vector<int> last_association, current_association;
1196 clusters.reserve(
m_k);
1197 std::vector<double> min_dists(descriptors.size(), std::numeric_limits<double>::max());
1201 int ifeature = rand()% descriptors.size();
1204 clusters.push_back(descriptors[ifeature]);
1207 std::vector<double>::iterator dit;
1208 dit = min_dists.begin();
1209 for(
auto fit = descriptors.begin(); fit != descriptors.end(); ++fit, ++dit)
1211 *dit =
distance((*fit), clusters.back());
1214 while((
int)clusters.size() <
m_k)
1217 dit = min_dists.begin();
1218 for(
auto fit = descriptors.begin(); fit != descriptors.end(); ++fit, ++dit)
1222 double dist =
distance((*fit), clusters.back());
1223 if(dist < *dit) *dit = dist;
1228 double dist_sum = std::accumulate(min_dists.begin(), min_dists.end(), 0.0);
1236 cut_d = (double(rand())/ double(RAND_MAX))* dist_sum;
1237 }
while(cut_d == 0.0);
1239 double d_up_now = 0;
1240 for(dit = min_dists.begin(); dit != min_dists.end(); ++dit)
1243 if(d_up_now >= cut_d)
break;
1246 if(dit == min_dists.end())
1247 ifeature = descriptors.size()-1;
1249 ifeature = dit - min_dists.begin();
1252 clusters.push_back(descriptors[ifeature]);
1263 for(
unsigned int c = 0; c < clusters.size(); ++c)
1265 std::vector<TinyMat> cluster_descriptors;
1266 cluster_descriptors.reserve(groups[c].
size());
1267 std::vector<unsigned int>::const_iterator vit;
1268 for(vit = groups[c].begin(); vit != groups[c].end(); ++vit)
1270 cluster_descriptors.push_back(descriptors[*vit]);
1273 meanValue(cluster_descriptors, clusters[c]);
1282 groups.resize(clusters.size(), std::vector<unsigned int>());
1283 current_association.resize(descriptors.size());
1288 for(
auto fit = descriptors.begin(); fit != descriptors.end(); ++fit)
1290 double best_dist =
distance((*fit), clusters[0]);
1291 unsigned int icluster = 0;
1293 for(
unsigned int c = 1; c < clusters.size(); ++c)
1295 double dist =
distance((*fit), clusters[c]);
1296 if(dist < best_dist)
1305 groups[icluster].push_back(fit - descriptors.begin());
1306 current_association[ fit - descriptors.begin() ] = icluster;
1321 for(
unsigned int i = 0; i < current_association.size(); i++)
1323 if(current_association[i] != last_association[i]){
1333 last_association = current_association;
1343 parent.childNum=clusters.size();
1344 int des_bytes=m_nodeDescriptors.cols*m_nodeDescriptors.elemSize();
1345 int childID=parent_id*
m_k+1;
1346 uchar* des_data=m_nodeDescriptors.data+des_bytes*(childID);
1347 for(
unsigned int i = 0; i < clusters.size(); ++i)
1349 memcpy(des_data,clusters[i].data,des_bytes);
1352 std::vector<std::future<void> > futures;
1354 if(current_level <
m_L)
1357 for(
unsigned int i = 0; i < parent.childNum; ++i)
1359 NodeId
id = childID+i;
1361 std::vector<TinyMat> child_features;
1362 child_features.reserve(groups[i].
size());
1364 std::vector<unsigned int>::const_iterator vit;
1365 for(vit = groups[i].begin(); vit != groups[i].end(); ++vit)
1367 child_features.push_back(descriptors[*vit]);
1370 if(child_features.size() > 1)
1372 if(m_workthreads&¤t_level==1)
1373 futures.push_back(m_workthreads->Add([
this,
id,child_features,current_level](){
1374 return HKmeansStep(id, child_features, current_level + 1);
1377 HKmeansStep(
id, child_features, current_level + 1);
1381 for(
auto& f:futures) f.wait();
1407 return m_nodeDescriptors.row(wid);
1421 inline WordId Vocabulary::transform
1422 (
const TinyMat& feature)
const 1431 transform(feature, wid,weight);
1437 inline void Vocabulary::transform(
1438 const TinyMat& features, BowVector &v)
const 1460 for(
int r=0;r<features.rows;r++)
1465 transform(features.row(r), id, w);
1470 if(!v.empty() && !must)
1473 const double nd = v.size();
1474 for(BowVector::iterator vit = v.begin(); vit != v.end(); vit++)
1481 for(
int r=0;r<features.rows;r++)
1487 transform(features.row(r), id, w);
1490 if(w > 0) addIfNotExist(v,
id, w);
1495 if(must) normalize(v,norm);
1501 inline void Vocabulary::transform(
const std::vector<TinyMat>& features, BowVector &v)
const 1517 for(
auto fit = features.begin(); fit < features.end(); ++fit)
1523 transform(*fit,
id, w);
1529 if(!v.empty() && !must)
1532 const double nd = v.size();
1533 for(BowVector::iterator vit = v.begin(); vit != v.end(); vit++)
1540 for(
auto fit = features.begin(); fit < features.end(); ++fit)
1546 transform(*fit,
id, w);
1549 if(w > 0) addIfNotExist(v,
id, w);
1554 if(must) normalize(v,norm);
1558 inline void Vocabulary::transform(
const TinyMat& features,
1559 BowVector &v, FeatureVector &fv,
int levelsup)
const 1576 for(
unsigned int i_feature = 0; i_feature<features.rows; ++i_feature)
1583 transform(features.row(i_feature), id, w, &nid, levelsup);
1588 addFeature(fv,nid, i_feature);
1592 if(!v.empty() && !must)
1595 const double nd = v.size();
1596 for(BowVector::iterator vit = v.begin(); vit != v.end(); vit++)
1603 for(
unsigned int i_feature = 0; i_feature<features.rows; ++i_feature)
1610 transform(features.row(i_feature), id, w, &nid, levelsup);
1614 addIfNotExist(v,
id, w);
1615 addFeature(fv,nid, i_feature);
1620 if(must) normalize(v,norm);
1623 inline void Vocabulary::transform(
1624 const std::vector<TinyMat>& features,
1625 BowVector &v, FeatureVector &fv,
int levelsup)
const 1642 unsigned int i_feature = 0;
1643 for(
auto fit = features.begin(); fit < features.end(); ++fit, ++i_feature)
1650 transform(*fit,
id, w, &nid, levelsup);
1655 addFeature(fv,nid, i_feature);
1659 if(!v.empty() && !must)
1662 const double nd = v.size();
1663 for(BowVector::iterator vit = v.begin(); vit != v.end(); vit++)
1670 unsigned int i_feature = 0;
1671 for(
auto fit = features.begin(); fit < features.end(); ++fit, ++i_feature)
1678 transform(*fit,
id, w, &nid, levelsup);
1682 addIfNotExist(v,
id, w);
1683 addFeature(fv,nid, i_feature);
1688 if(must) normalize(v,norm);
1695 inline void Vocabulary::transform(
const TinyMat &feature,
1696 WordId &word_id, WordValue &weight, NodeId *nid,
int levelsup)
const 1702 const int nid_level =
m_L - levelsup;
1703 if(nid_level <= 0 && nid != NULL) *nid = 0;
1705 NodeId final_id = 0;
1706 int current_level = 0;
1707 int featureBytes=m_nodeDescriptors.cols*m_nodeDescriptors.elemSize();
1712 float best_d = std::numeric_limits<float>::max();
1713 NodeId best_id= final_id;
1716 NodeId
id=final_id*
m_k+1;
1717 for(NodeId idEnd=
id+node.childNum;
id<idEnd;++
id)
1719 float d = m_distanceFunc(feature.data, m_nodeDescriptors.data+featureBytes*
id);
1728 if(nid != NULL && current_level == nid_level)
1735 weight =
m_nodes[final_id].weight;
1740 inline void Vocabulary::transform(
const TinyMat &feature,
1741 WordId &word_id, WordValue &weight )
const 1745 NodeId final_id = 0;
1749 float best_d = std::numeric_limits<float>::max();
1750 NodeId bestID=final_id;
1752 for(
int i=0;i<node.childNum;i++)
1754 NodeId
id=final_id*
m_k+1+i;
1755 uint64_t dist=
distance(feature, m_nodeDescriptors.row(
id));
1769 weight =
m_nodes[final_id].weight;
1774 (WordId wid,
int levelsup)
const 1777 while(levelsup > 0 && ret != 0)
1789 (NodeId nid, std::vector<WordId> &words)
const 1795 words.push_back(nid);
1801 std::vector<NodeId> parents;
1802 parents.push_back(nid);
1804 while(!parents.empty())
1806 NodeId parentid = parents.back();
1809 for(
int i=0;i<
m_nodes[parentid].childNum;i++)
1811 const auto id=parentid*
m_k+1+i;
1814 words.push_back(
id);
1816 parents.push_back(
id);
1831 if((*wit).weight < minWeight)
1845 if(filename.find(
".yml")!=std::string::npos)
1851 std::ofstream out_str(filename);
1852 if (!out_str)
throw std::runtime_error(
"Vocabulary::saveBinary Could not open file :"+filename+
" for writing");
1854 uint64_t sig=88877711233;
1855 out_str.write((
char*)&sig,
sizeof(sig));
1856 out_str.write((
char*)&compressed,
sizeof(compressed));
1857 uint32_t nnodes=
m_nodes.size();
1858 out_str.write((
char*)&nnodes,
sizeof(nnodes));
1859 if (nnodes==0)
return false;
1861 std::stringstream aux_stream;
1862 aux_stream.write((
char*)&
m_k,
sizeof(
m_k));
1863 aux_stream.write((
char*)&
m_L,
sizeof(
m_L));
1869 aux_stream.write((
char*)&cols,
sizeof(cols));
1870 aux_stream.write((
char*)&rows,
sizeof(rows));
1871 aux_stream.write((
char*)&type,
sizeof(type));
1874 aux_stream.write((
char*)m_nodeDescriptors.data,
1875 m_nodeDescriptors.elemSize()*m_nodeDescriptors.total());
1882 out_str<<aux_stream.rdbuf();
1893 ifile.read((
char*)&sig,
sizeof(sig));
1894 if (sig==88877711233) {
1897 ifile.read((
char*)&compressed,
sizeof(compressed));
1898 ifile.read((
char*)&nnodes,
sizeof(nnodes));
1899 if(nnodes==0)
return false;
1900 std::istream *_used_str=0;
1909 _used_str->read((
char*)&
m_k,
sizeof(
m_k));
1910 _used_str->read((
char*)&
m_L,
sizeof(
m_L));
1917 _used_str->read((
char*)&cols,
sizeof(cols));
1918 _used_str->read((
char*)&rows,
sizeof(rows));
1919 _used_str->read((
char*)&type,
sizeof(type));
1921 m_nodeDescriptors=TinyMat(nnodes,cols,type,
nullptr,
false,32);
1922 m_distanceFunc=DistanceFactory::create(m_nodeDescriptors);
1924 _used_str->read((
char*)
m_nodes.data(),nnodes*
sizeof(
Node));
1925 _used_str->read((
char*)m_nodeDescriptors.data,
1926 m_nodeDescriptors.total()*m_nodeDescriptors.elemSize());
1930 std::cerr<<
"Vocabulary: Wrong signature.";
1938 std::ifstream ifile(filename,std::ios::in|std::ios::binary);
1939 if (!ifile.is_open())
1941 std::cerr<<
"Vocabulary::load Could not open file "<<filename<<
" for reading"<<std::endl;
1948 if(filename.find(
".yml")!=std::string::npos)
1950 throw std::runtime_error(
"Vocabulary loading failure: .yml loading is not implemented!" );
1952 else if(filename.find(
".voc")!=std::string::npos)
1954 throw std::runtime_error(
"Vocabulary loading failure: .voc loading is not implemented!" );
1966 inline std::ostream& operator<<(std::ostream &os,
1967 const Vocabulary &voc)
1971 <<
", Weighting = ";
1975 case Vocabulary::TF_IDF: os <<
"tf-idf";
break;
1976 case Vocabulary::TF: os <<
"tf";
break;
1977 case Vocabulary::IDF: os <<
"idf";
break;
1978 case Vocabulary::BINARY: os <<
"binary";
break;
1981 os <<
", Scoring = ";
1984 case Vocabulary::L1_NORM: os <<
"L1-norm";
break;
1985 case Vocabulary::L2_NORM: os <<
"L2-norm";
break;
1986 case Vocabulary::CHI_SQUARE: os <<
"Chi square distance";
break;
1987 case Vocabulary::KL: os <<
"KL-divergence";
break;
1988 case Vocabulary::BHATTACHARYYA: os <<
"Bhattacharyya coefficient";
break;
1989 case Vocabulary::DOT_PRODUCT: os <<
"Dot product";
break;
1992 os <<
", Number of words = " << voc.
size();
2005 m_nodeDescriptors=TinyMat();
2012 if(descriptors.empty())
return;
2014 if(descriptors.size() == 1)
2016 mean = descriptors[0].clone();
2020 if (descriptors[0].type()==GImageType<uchar>::Type ){
2022 int L= descriptors[0].cols;
2023 std::vector<int> sum( L * 8, 0);
2025 for(
size_t i = 0; i < descriptors.size(); ++i)
2027 const TinyMat &d = descriptors[i];
2028 const unsigned char *p = d.data;
2030 for(
int j = 0; j < d.cols; ++j, ++p)
2032 if(*p & (1 << 7)) ++sum[ j*8 ];
2033 if(*p & (1 << 6)) ++sum[ j*8 + 1 ];
2034 if(*p & (1 << 5)) ++sum[ j*8 + 2 ];
2035 if(*p & (1 << 4)) ++sum[ j*8 + 3 ];
2036 if(*p & (1 << 3)) ++sum[ j*8 + 4 ];
2037 if(*p & (1 << 2)) ++sum[ j*8 + 5 ];
2038 if(*p & (1 << 1)) ++sum[ j*8 + 6 ];
2039 if(*p & (1)) ++sum[ j*8 + 7 ];
2043 mean = TinyMat(1, L, GImageType<uchar>::Type);
2044 memset(mean.data,0,mean.total());
2045 unsigned char *p = mean.data;
2047 const int N2 = (int)descriptors.size() / 2 + descriptors.size() % 2;
2048 for(
size_t i = 0; i < sum.size(); ++i)
2053 *p |= 1 << (7 - (i % 8));
2061 assert(descriptors[0].type()==GImageType<float>::Type);
2063 mean= TinyMat(1, descriptors[0].cols,GImageType<float>::Type);
2064 memset(mean.data,0,mean.total()*mean.elemSize());
2065 float inv_s =1./double( descriptors.size());
2066 for(
size_t i=0;i<descriptors.size();i++)
2067 for(
int idx=0;idx<descriptors[i].total();idx++)
2068 mean.at<
float>(idx) += ((
float*)descriptors[i].data)[idx] * inv_s;
2075 return m_distanceFunc(a.data,b.data);
Definition: Vocabulary.h:481
bool isLeaf() const
Returns whether the node is a leaf node.
Definition: Vocabulary.h:472
static void meanValue(const std::vector< TinyMat > &descriptors, TinyMat &mean)
Calculates the mean value of a set of descriptors.
Definition: Vocabulary.h:2008
bool load(const std::string &filename)
Loads the vocabulary from a file created with save.
Definition: Vocabulary.h:1934
bool save(const std::string &filename, bool binary_compressed=false) const
Saves the vocabulary into a file.
Definition: Vocabulary.h:1843
static std::shared_ptr< Vocabulary > create(const std::vector< TinyMat > &training_features, int k=10, int L=5, WeightingType weighting=TF_IDF, ScoringType scoring=L1_NORM)
Creates a vocabulary from the training features, setting the branching factor nad the depth levels of...
Definition: Vocabulary.h:1050
void setScoringType(ScoringType type)
Changes the scoring method.
Definition: Vocabulary.h:1036
void clear()
Clears the vocabulary object.
Definition: Vocabulary.h:2001
void HKmeansStep(NodeId parent_id, const std::vector< TinyMat > &descriptors, int current_level)
Creates a level in the tree, under the parent, by running kmeans with a descriptor set...
Definition: Vocabulary.h:1138
virtual WordValue getWordWeight(WordId wid) const
Returns the weight of a word.
Definition: Vocabulary.h:1413
std::shared_ptr< GeneralScoring > m_scoring_object
Object for computing scores.
Definition: Vocabulary.h:597
Vocabulary(int k=10, int L=5, WeightingType weighting=TF_IDF, ScoringType scoring=L1_NORM)
Initiates an empty vocabulary.
Definition: Vocabulary.h:982
ScoringType m_scoring
Scoring method.
Definition: Vocabulary.h:594
static void addWeight(BowVector &bow, WordId id, WordValue v)
Returns the word id associated to a feature.
Definition: Vocabulary.h:361
float getEffectiveLevels() const
Returns the real depth levels of the tree on average.
Definition: Vocabulary.h:1388
ScoringType
Scoring type.
Definition: Vocabulary.h:97
int getDescritorSize() const
Returns the size of the descriptor employed.
Definition: Vocabulary.h:302
Tree node.
Definition: Vocabulary.h:458
virtual unsigned int size() const
Returns the number of nodes in the vocabulary.
Definition: Vocabulary.h:151
void getWordsFromNode(NodeId nid, std::vector< WordId > &words) const
Returns the ids of all the words that are under the given node id, by traversing any of the branches ...
Definition: Vocabulary.h:1789
LNorm
L-norms for normalization.
Definition: Vocabulary.h:81
WeightingType m_weighting
Weighting method.
Definition: Vocabulary.h:591
virtual TinyMat getWord(WordId wid) const
Returns the descriptor of a word.
Definition: Vocabulary.h:1405
int getBranchingFactor() const
Returns the branching factor of the tree (k)
Definition: Vocabulary.h:232
int getDescritorType() const
Returns the type of the descriptor employed normally(8U_C1, 32F_C1)
Definition: Vocabulary.h:307
float distance(const TinyMat &a, const TinyMat &b) const
Calculates the distance between two descriptors.
Definition: Vocabulary.h:2073
WeightingType
Weighting type.
Definition: Vocabulary.h:88
int m_k
Branching factor.
Definition: Vocabulary.h:585
void createScoringObject()
Creates an instance of the scoring object accoring to m_scoring.
Definition: Vocabulary.h:1000
virtual int stopWords(double minWeight)
Stops those words whose weight is below minWeight.
Definition: Vocabulary.h:1826
Node()
Empty constructor.
Definition: Vocabulary.h:466
int m_L
Depth levels.
Definition: Vocabulary.h:588
virtual NodeId getParentNode(WordId wid, int levelsup) const
Returns the id of the node that is "levelsup" levels from the word given.
Definition: Vocabulary.h:1774
Definition: Vocabulary.h:74
std::vector< Node > m_nodes
Tree nodes.
Definition: Vocabulary.h:600
Base class of scoring functions.
Definition: Vocabulary.h:612
int getDepthLevels() const
Returns the depth levels of the tree (L)
Definition: Vocabulary.h:238
double score(const BowVector &a, const BowVector &b) const
Returns the score of two vectors.
ScoringType getScoringType() const
Returns the scoring method.
Definition: Vocabulary.h:270
void setWeightingType(WeightingType type)
Changes the weighting method.
Definition: Vocabulary.h:1045
virtual ~GeneralScoring()
Required for virtual base classes.
Definition: Vocabulary.h:637
WeightingType getWeightingType() const
Returns the weighting method.
Definition: Vocabulary.h:264
virtual bool empty() const
Returns whether the vocabulary is empty (i.e.
Definition: Vocabulary.h:162