1 //*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
23 // * Redistribution's in binary form must reproduce the above copyright notice,
24 // this list of conditions and the following disclaimer in the documentation
25 // and/or other materials provided with the distribution.
27 // * The name of the copyright holders may not be used to endorse or promote products
28 // derived from this software without specific prior written permission.
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
58 /****************************************************************************************\
59 The code below is implementation of Calonder Descriptor and RTree Classifier
60 originally introduced by Michael Calonder.
62 The code was integrated into OpenCV by Alexey Latyshev
63 \****************************************************************************************/
68 //----------------------------
71 inline uchar* getData(IplImage* image)
73 return reinterpret_cast<uchar*>(image->imageData);
76 inline float* RandomizedTree::getPosteriorByIndex(int index)
78 return const_cast<float*>(const_cast<const RandomizedTree*>(this)->getPosteriorByIndex(index));
81 inline const float* RandomizedTree::getPosteriorByIndex(int index) const
83 return posteriors_[index];
86 inline uchar* RandomizedTree::getPosteriorByIndex2(int index)
88 return posteriors2_[index];
92 template < typename PointT >
93 cv::WImageView1_b extractPatch(cv::WImageView1_b const& image, PointT pt, int patch_sz = PATCH_SIZE)
95 const int offset = patch_sz / 2;
97 // TODO: WImage{C}.View really should have const version
98 cv::WImageView1_b &img_ref = const_cast< cv::WImageView1_b& >(image);
99 return img_ref.View(pt.x - offset, pt.y - offset, patch_sz, patch_sz);
102 template < typename PointT >
103 cv::WImageView3_b extractPatch3(cv::WImageView3_b const& image, PointT pt)
105 static const int offset = PATCH_SIZE / 2;
107 // TODO: WImage{C}.View really should have const version
108 cv::WImageView3_b &img_ref = const_cast< cv::WImageView3_b& >(image);
109 return img_ref.View(pt.x - offset, pt.y - offset,
110 PATCH_SIZE, PATCH_SIZE);
113 float *CSMatrixGenerator::cs_phi_ = NULL;
114 int CSMatrixGenerator::cs_phi_m_ = 0;
115 int CSMatrixGenerator::cs_phi_n_ = 0;
117 RandomizedTree::RandomizedTree()
118 : posteriors_(NULL), posteriors2_(NULL)
122 RandomizedTree::~RandomizedTree()
127 void RandomizedTree::createNodes(int num_nodes, cv::RNG &rng)
129 nodes_.reserve(num_nodes);
130 for (int i = 0; i < num_nodes; ++i) {
131 nodes_.push_back( RTreeNode(rng(PATCH_SIZE),
138 int RandomizedTree::getIndex(uchar* patch_data) const
141 for (int d = 0; d < depth_; ++d) {
142 int child_offset = nodes_[index](patch_data);
143 index = 2*index + 1 + child_offset;
145 return index - nodes_.size();
148 void RandomizedTree::train(std::vector<BaseKeypoint> const& base_set,
149 cv::RNG &rng, int depth, int views, size_t reduced_num_dim,
153 //CalonderPatchGenerator make_patch(NULL, rng);
154 PatchGenerator make_patch = PatchGenerator();
155 train(base_set, rng, make_patch, depth, views, reduced_num_dim, num_quant_bits);
158 void RandomizedTree::train(std::vector<BaseKeypoint> const& base_set,
159 cv::RNG &rng, PatchGenerator &make_patch,
160 int depth, int views, size_t reduced_num_dim,
163 init(base_set.size(), depth, rng);
167 // Estimate posterior probabilities using random affine views
168 std::vector<BaseKeypoint>::const_iterator keypt_it;
170 for (keypt_it = base_set.begin(); keypt_it != base_set.end(); ++keypt_it, ++class_id) {
171 for (int i = 0; i < views; ++i) {
174 make_patch(keypt_it->image, Point2f(keypt_it->x,keypt_it->y) ,patch, Size(PATCH_SIZE,PATCH_SIZE),rng);
176 IplImage _patch = patch;
177 addExample(class_id, getData(&_patch));
181 finalize(reduced_num_dim, num_quant_bits);
185 void RandomizedTree::allocPosteriorsAligned(int num_leaves, int num_classes)
190 posteriors_ = new float*[num_leaves]; //(float**) malloc(num_leaves*sizeof(float*));
191 for (int i=0; i<num_leaves; ++i) {
193 /* err_cnt += posix_memalign((void**)&posteriors_[i], 16, num_classes*sizeof(float));*/ posteriors_[i] = (float*)malloc(num_classes*sizeof(float));
194 memset(posteriors_[i], 0, num_classes*sizeof(float));
197 posteriors2_ = new uchar*[num_leaves];
198 for (int i=0; i<num_leaves; ++i) {
200 /* err_cnt += posix_memalign((void**)&posteriors2_[i], 16, num_classes*sizeof(uchar)); */posteriors2_[i] = (uchar*)malloc(num_classes*sizeof(uchar));
201 memset(posteriors2_[i], 0, num_classes*sizeof(uchar));
205 printf("Something went wrong in posix_memalign()! err_cnt=%i\n", err_cnt);
209 classes_ = num_classes;
212 void RandomizedTree::freePosteriors(int which)
214 if (posteriors_ && (which&1)) {
215 for (int i=0; i<num_leaves_; ++i) {
216 if (posteriors_[i]) {
217 free(posteriors_[i]); //delete [] posteriors_[i];
218 posteriors_[i] = NULL;
221 delete [] posteriors_;
225 if (posteriors2_ && (which&2)) {
226 for (int i=0; i<num_leaves_; ++i)
227 free(posteriors2_[i]);
228 delete [] posteriors2_;
235 void RandomizedTree::init(int num_classes, int depth, cv::RNG &rng)
238 num_leaves_ = 1 << depth; // 2**d
239 int num_nodes = num_leaves_ - 1; // 2**d - 1
241 // Initialize probabilities and counts to 0
242 allocPosteriorsAligned(num_leaves_, num_classes); // will set classes_ correctly
243 for (int i = 0; i < num_leaves_; ++i)
244 memset((void*)posteriors_[i], 0, num_classes*sizeof(float));
245 leaf_counts_.resize(num_leaves_);
247 for (int i = 0; i < num_leaves_; ++i)
248 memset((void*)posteriors2_[i], 0, num_classes*sizeof(uchar));
250 createNodes(num_nodes, rng);
253 void RandomizedTree::addExample(int class_id, uchar* patch_data)
255 int index = getIndex(patch_data);
256 float* posterior = getPosteriorByIndex(index);
257 ++leaf_counts_[index];
258 ++posterior[class_id];
261 // returns the p% percentile of data (length n vector)
262 static float percentile(float *data, int n, float p)
265 assert(p>=0 && p<=1);
266 std::vector<float> vec(data, data+n);
267 sort(vec.begin(), vec.end());
268 int ix = (int)(p*(n-1));
272 void RandomizedTree::finalize(size_t reduced_num_dim, int num_quant_bits)
274 // Normalize by number of patches to reach each leaf
275 for (int index = 0; index < num_leaves_; ++index) {
276 float* posterior = posteriors_[index];
277 assert(posterior != NULL);
278 int count = leaf_counts_[index];
280 float normalizer = 1.0f / count;
281 for (int c = 0; c < classes_; ++c) {
282 *posterior *= normalizer;
287 leaf_counts_.clear();
289 // apply compressive sensing
290 if ((int)reduced_num_dim != classes_)
291 compressLeaves(reduced_num_dim);
293 static bool notified = false;
295 // printf("\n[OK] NO compression to leaves applied, dim=%i\n", reduced_num_dim);
299 // convert float-posteriors to char-posteriors (quantization step)
300 makePosteriors2(num_quant_bits);
303 void RandomizedTree::compressLeaves(size_t reduced_num_dim)
305 static bool warned = false;
307 printf("\n[OK] compressing leaves with phi %i x %i\n", (int)reduced_num_dim, classes_);
311 static bool warned2 = false;
312 if ((int)reduced_num_dim == classes_) {
314 printf("[WARNING] RandomizedTree::compressLeaves: not compressing because reduced_dim == classes()\n");
319 // DO NOT FREE RETURNED POINTER
320 float *cs_phi = CSMatrixGenerator::getCSMatrix(reduced_num_dim, classes_, CSMatrixGenerator::PDT_BERNOULLI);
322 float *cs_posteriors = new float[num_leaves_ * reduced_num_dim]; // temp, num_leaves_ x reduced_num_dim
324 for (int i=0; i<num_leaves_; ++i)
326 //added (inside cycle)
327 //float *post = getPosteriorByIndex(i);
328 // float *prod = &cs_posteriors[i*reduced_num_dim];
329 // cblas_sgemv(CblasRowMajor, CblasNoTrans, reduced_num_dim, classes_, 1.f, cs_phi,
330 // classes_, post, 1, 0.f, prod, 1);
331 float *post = getPosteriorByIndex(i);
332 //Matrix multiplication
333 for (int idx = 0; idx < (int)reduced_num_dim; idx++)
335 cs_posteriors[i*reduced_num_dim+idx] = 0.0f;
336 for (int col = 0; col < classes_; col++)
338 cs_posteriors[i*reduced_num_dim+idx] += cs_phi[idx*reduced_num_dim + col] * post[col];
343 // copy new posteriors
345 allocPosteriorsAligned(num_leaves_, reduced_num_dim);
346 for (int i=0; i<num_leaves_; ++i)
347 memcpy(posteriors_[i], &cs_posteriors[i*reduced_num_dim], reduced_num_dim*sizeof(float));
348 classes_ = reduced_num_dim;
350 delete [] cs_posteriors;
353 void RandomizedTree::makePosteriors2(int num_quant_bits)
355 int N = (1<<num_quant_bits) - 1;
358 estimateQuantPercForPosteriors(perc);
360 assert(posteriors_ != NULL);
361 for (int i=0; i<num_leaves_; ++i)
362 quantizeVector(posteriors_[i], classes_, N, perc, posteriors2_[i]);
364 // printf("makePosteriors2 quantization bounds: %.3e, %.3e (num_leaves=%i, N=%i)\n",
365 // perc[0], perc[1], num_leaves_, N);
368 void RandomizedTree::estimateQuantPercForPosteriors(float perc[2])
370 // _estimate_ percentiles for this tree
371 // TODO: do this more accurately
372 assert(posteriors_ != NULL);
373 perc[0] = perc[1] = .0f;
374 for (int i=0; i<num_leaves_; i++) {
375 perc[0] += percentile(posteriors_[i], classes_, LOWER_QUANT_PERC);
376 perc[1] += percentile(posteriors_[i], classes_, UPPER_QUANT_PERC);
378 perc[0] /= num_leaves_;
379 perc[1] /= num_leaves_;
383 float* RandomizedTree::getPosterior(uchar* patch_data)
385 return const_cast<float*>(const_cast<const RandomizedTree*>(this)->getPosterior(patch_data));
388 const float* RandomizedTree::getPosterior(uchar* patch_data) const
390 return getPosteriorByIndex( getIndex(patch_data) );
393 uchar* RandomizedTree::getPosterior2(uchar* patch_data)
395 return getPosteriorByIndex2( getIndex(patch_data) );
398 void RandomizedTree::quantizeVector(float *vec, int dim, int N, float bnds[2], int clamp_mode)
400 float map_bnd[2] = {0.f,(float)N}; // bounds of quantized target interval we're mapping to
401 for (int k=0; k<dim; ++k, ++vec) {
402 *vec = float(int((*vec - bnds[0])/(bnds[1] - bnds[0])*(map_bnd[1] - map_bnd[0]) + map_bnd[0]));
403 // 0: clamp both, lower and upper values
404 if (clamp_mode == 0) *vec = (*vec<map_bnd[0]) ? map_bnd[0] : ((*vec>map_bnd[1]) ? map_bnd[1] : *vec);
405 // 1: clamp lower values only
406 else if (clamp_mode == 1) *vec = (*vec<map_bnd[0]) ? map_bnd[0] : *vec;
407 // 2: clamp upper values only
408 else if (clamp_mode == 2) *vec = (*vec>map_bnd[1]) ? map_bnd[1] : *vec;
410 else if (clamp_mode == 4) ; // yep, nothing
412 printf("clamp_mode == %i is not valid (%s:%i).\n", clamp_mode, __FILE__, __LINE__);
419 void RandomizedTree::quantizeVector(float *vec, int dim, int N, float bnds[2], uchar *dst)
421 int map_bnd[2] = {0, N}; // bounds of quantized target interval we're mapping to
423 for (int k=0; k<dim; ++k) {
424 tmp = int((*vec - bnds[0])/(bnds[1] - bnds[0])*(map_bnd[1] - map_bnd[0]) + map_bnd[0]);
425 *dst = (uchar)((tmp<0) ? 0 : ((tmp>N) ? N : tmp));
432 void RandomizedTree::read(const char* file_name, int num_quant_bits)
434 std::ifstream file(file_name, std::ifstream::binary);
435 read(file, num_quant_bits);
439 void RandomizedTree::read(std::istream &is, int num_quant_bits)
441 is.read((char*)(&classes_), sizeof(classes_));
442 is.read((char*)(&depth_), sizeof(depth_));
444 num_leaves_ = 1 << depth_;
445 int num_nodes = num_leaves_ - 1;
447 nodes_.resize(num_nodes);
448 is.read((char*)(&nodes_[0]), num_nodes * sizeof(nodes_[0]));
450 //posteriors_.resize(classes_ * num_leaves_);
452 //printf("[DEBUG] reading: %i leaves, %i classes\n", num_leaves_, classes_);
453 allocPosteriorsAligned(num_leaves_, classes_);
454 for (int i=0; i<num_leaves_; i++)
455 is.read((char*)posteriors_[i], classes_ * sizeof(*posteriors_[0]));
457 // make char-posteriors from float-posteriors
458 makePosteriors2(num_quant_bits);
461 void RandomizedTree::write(const char* file_name) const
463 std::ofstream file(file_name, std::ofstream::binary);
468 void RandomizedTree::write(std::ostream &os) const
471 printf("WARNING: Cannot write float posteriors (posteriors_ = NULL).\n");
475 os.write((char*)(&classes_), sizeof(classes_));
476 os.write((char*)(&depth_), sizeof(depth_));
478 os.write((char*)(&nodes_[0]), nodes_.size() * sizeof(nodes_[0]));
479 for (int i=0; i<num_leaves_; i++) {
480 os.write((char*)posteriors_[i], classes_ * sizeof(*posteriors_[0]));
485 void RandomizedTree::savePosteriors(std::string url, bool append)
487 std::ofstream file(url.c_str(), (append?std::ios::app:std::ios::out));
488 for (int i=0; i<num_leaves_; i++) {
489 float *post = posteriors_[i];
491 for (int i=0; i<classes_; i++) {
492 sprintf(buf, "%.10e", *post++);
493 file << buf << ((i<classes_-1) ? " " : "");
500 void RandomizedTree::savePosteriors2(std::string url, bool append)
502 std::ofstream file(url.c_str(), (append?std::ios::app:std::ios::out));
503 for (int i=0; i<num_leaves_; i++) {
504 uchar *post = posteriors2_[i];
505 for (int i=0; i<classes_; i++)
506 file << int(*post++) << (i<classes_-1?" ":"");
512 float* CSMatrixGenerator::getCSMatrix(int m, int n, PHI_DISTR_TYPE dt)
516 if (cs_phi_m_!=m || cs_phi_n_!=n || cs_phi_==NULL) {
517 if (cs_phi_) delete [] cs_phi_;
518 cs_phi_ = new float[m*n];
521 #if 0 // debug - load the random matrix from a file (for reproducability of results)
524 //const char *phi = "/u/calonder/temp/dim_red/kpca_phi.txt";
525 const char *phi = "/u/calonder/temp/dim_red/debug_phi.txt";
526 std::ifstream ifs(phi);
527 for (size_t i=0; i<m*n; ++i) {
529 printf("[ERROR] RandomizedTree::makeRandomMeasMatrix: problem reading '%s'\n", phi);
536 static bool warned=false;
538 printf("[NOTE] RT: reading %ix%i PHI matrix from '%s'...\n", m, n, phi);
545 float *cs_phi = cs_phi_;
548 // special case - set to 0 for safety
549 memset(cs_phi, 0, m*n*sizeof(float));
550 printf("[WARNING] %s:%i: square CS matrix (-> no reduction)\n", __FILE__, __LINE__);
555 // par is distr param, cf 'Favorable JL Distributions' (Baraniuk et al, 2006)
556 if (dt == PDT_GAUSS) {
557 float par = (float)(1./m);
560 for (int i=0; i<m*n; ++i)
562 *cs_phi++ = (float)_rng.gaussian((double)par);//sample_normal<float>(0., par);
565 else if (dt == PDT_BERNOULLI) {
566 float par = (float)(1./sqrt((float)m));
567 for (int i=0; i<m*n; ++i)
568 *cs_phi++ = (rng(2)==0 ? par : -par);
570 else if (dt == PDT_DBFRIENDLY) {
571 float par = (float)sqrt(3./m);
572 for (int i=0; i<m*n; ++i) {
575 *cs_phi++ = (_i==0 ? par : (_i==1 ? -par : 0.f));
579 throw("PHI_DISTR_TYPE not implemented.");
585 CSMatrixGenerator::~CSMatrixGenerator()
587 if (cs_phi_) delete [] cs_phi_;
592 //} // namespace features
594 //----------------------------
595 //rtree_classifier.cpp
596 //namespace features {
598 // Returns 16-byte aligned signatures that can be passed to getSignature().
599 // Release by calling free() - NOT delete!
601 // note: 1) for num_sig>1 all signatures will still be 16-byte aligned, as
602 // long as sig_len%16 == 0 holds.
603 // 2) casting necessary, otherwise it breaks gcc's strict aliasing rules
604 inline void RTreeClassifier::safeSignatureAlloc(uchar **sig, int num_sig, int sig_len)
606 assert(sig_len == 176);
609 // posix_memalign(&p_sig, 16, num_sig*sig_len*sizeof(uchar));
610 p_sig = malloc(num_sig*sig_len*sizeof(uchar));
611 *sig = reinterpret_cast<uchar*>(p_sig);
614 inline uchar* RTreeClassifier::safeSignatureAlloc(int num_sig, int sig_len)
617 safeSignatureAlloc(&sig, num_sig, sig_len);
621 inline void add(int size, const float* src1, const float* src2, float* dst)
624 *dst = *src1 + *src2;
625 ++dst; ++src1; ++src2;
629 inline void add(int size, const ushort* src1, const uchar* src2, ushort* dst)
632 *dst = *src1 + *src2;
633 ++dst; ++src1; ++src2;
637 RTreeClassifier::RTreeClassifier()
643 void RTreeClassifier::train(std::vector<BaseKeypoint> const& base_set,
644 cv::RNG &rng, int num_trees, int depth,
645 int views, size_t reduced_num_dim,
646 int num_quant_bits, bool print_status)
648 PatchGenerator make_patch = PatchGenerator();
649 train(base_set, rng, make_patch, num_trees, depth, views, reduced_num_dim, num_quant_bits, print_status);
652 // Single-threaded version of train(), with progress output
653 void RTreeClassifier::train(std::vector<BaseKeypoint> const& base_set,
654 cv::RNG &rng, PatchGenerator &make_patch, int num_trees,
655 int depth, int views, size_t reduced_num_dim,
656 int num_quant_bits, bool print_status)
658 if (reduced_num_dim > base_set.size()) {
661 printf("INVALID PARAMS in RTreeClassifier::train: reduced_num_dim{%i} > base_set.size(){%i}\n",
662 (int)reduced_num_dim, (int)base_set.size());
667 num_quant_bits_ = num_quant_bits;
668 classes_ = reduced_num_dim; // base_set.size();
669 original_num_classes_ = base_set.size();
670 trees_.resize(num_trees);
673 printf("[OK] Training trees: base size=%i, reduced size=%i\n", (int)base_set.size(), (int)reduced_num_dim);
679 printf("[OK] Trained 0 / %i trees", num_trees); fflush(stdout);
682 //BOOST_FOREACH( RandomizedTree &tree, trees_ ) {
683 //tree.train(base_set, rng, make_patch, depth, views, reduced_num_dim, num_quant_bits_);
684 //printf("\r[OK] Trained %i / %i trees", count++, num_trees);
686 for (int i=0; i<(int)trees_.size(); i++)
688 trees_[i].train(base_set, rng, make_patch, depth, views, reduced_num_dim, num_quant_bits_);
691 printf("\r[OK] Trained %i / %i trees", count++, num_trees);
704 void RTreeClassifier::getSignature(IplImage* patch, float *sig)
706 // Need pointer to 32x32 patch data
707 uchar buffer[PATCH_SIZE * PATCH_SIZE];
709 if (patch->widthStep != PATCH_SIZE) {
710 //printf("[INFO] patch is padded, data will be copied (%i/%i).\n",
711 // patch->widthStep, PATCH_SIZE);
712 uchar* data = getData(patch);
714 for (int i = 0; i < PATCH_SIZE; ++i) {
715 memcpy((void*)patch_data, (void*)data, PATCH_SIZE);
716 data += patch->widthStep;
717 patch_data += PATCH_SIZE;
722 patch_data = getData(patch);
725 memset((void*)sig, 0, classes_ * sizeof(float));
726 std::vector<RandomizedTree>::iterator tree_it;
729 float **posteriors = new float*[trees_.size()]; // TODO: move alloc outside this func
730 float **pp = posteriors;
731 for (tree_it = trees_.begin(); tree_it != trees_.end(); ++tree_it, pp++) {
732 *pp = tree_it->getPosterior(patch_data);
738 for (tree_it = trees_.begin(); tree_it != trees_.end(); ++tree_it, pp++)
739 add(classes_, sig, *pp, sig);
741 delete [] posteriors;
744 // full quantization (experimental)
746 int n_max = 1<<8 - 1;
747 int sum_max = (1<<4 - 1)*trees_.size();
749 while ((sum_max>>shift) > n_max) shift++;
751 for (int i = 0; i < classes_; ++i) {
752 sig[i] = int(sig[i] + .5) >> shift;
753 if (sig[i]>n_max) sig[i] = n_max;
756 static bool warned = false;
758 printf("[WARNING] Using full quantization (RTreeClassifier::getSignature)! shift=%i\n", shift);
762 // TODO: get rid of this multiply (-> number of trees is known at train
763 // time, exploit it in RandomizedTree::finalize())
764 float normalizer = 1.0f / trees_.size();
765 for (int i = 0; i < classes_; ++i)
766 sig[i] *= normalizer;
771 // sum up 50 byte vectors of length 176
772 // assume 5 bits max for input vector values
773 // final shift is 3 bits right
774 //void sum_50c_176c(uchar **pp, uchar *sig)
779 void RTreeClassifier::getSignature(IplImage* patch, uchar *sig)
781 // Need pointer to 32x32 patch data
782 uchar buffer[PATCH_SIZE * PATCH_SIZE];
784 if (patch->widthStep != PATCH_SIZE) {
785 //printf("[INFO] patch is padded, data will be copied (%i/%i).\n",
786 // patch->widthStep, PATCH_SIZE);
787 uchar* data = getData(patch);
789 for (int i = 0; i < PATCH_SIZE; ++i) {
790 memcpy((void*)patch_data, (void*)data, PATCH_SIZE);
791 data += patch->widthStep;
792 patch_data += PATCH_SIZE;
796 patch_data = getData(patch);
799 std::vector<RandomizedTree>::iterator tree_it;
802 if (posteriors_ == NULL)
804 posteriors_ = new uchar*[trees_.size()];
806 // posix_memalign((void **)&ptemp_, 16, classes_*sizeof(ushort));
807 ptemp_ = (ushort*)malloc(classes_*sizeof(ushort));
809 uchar **pp = posteriors_;
810 for (tree_it = trees_.begin(); tree_it != trees_.end(); ++tree_it, pp++)
811 *pp = tree_it->getPosterior2(patch_data);
814 #if 0 // SSE2 optimized code
815 sum_50t_176c(pp, sig, ptemp_); // sum them up
817 static bool warned = false;
819 memset((void*)sig, 0, classes_ * sizeof(sig[0]));
820 ushort *sig16 = new ushort[classes_]; // TODO: make member, no alloc here
821 memset((void*)sig16, 0, classes_ * sizeof(sig16[0]));
822 for (tree_it = trees_.begin(); tree_it != trees_.end(); ++tree_it, pp++)
823 add(classes_, sig16, *pp, sig16);
825 // squeeze signatures into an uchar
826 const bool full_shifting = true;
829 float num_add_bits_f = log((float)trees_.size())/log(2.f); // # additional bits required due to summation
830 int num_add_bits = int(num_add_bits_f);
831 if (num_add_bits_f != float(num_add_bits)) ++num_add_bits;
832 shift = num_quant_bits_ + num_add_bits - 8*sizeof(uchar);
833 //shift = num_quant_bits_ + num_add_bits - 2;
836 for (int i = 0; i < classes_; ++i)
837 sig[i] = (sig16[i] >> shift); // &3 cut off all but lowest 2 bits, 3(dec) = 11(bin)
840 printf("[OK] RTC: quantizing by FULL RIGHT SHIFT, shift = %i\n", shift);
843 printf("[ERROR] RTC: not implemented!\n");
848 printf("[WARNING] RTC: unoptimized signature computation\n");
854 void RTreeClassifier::getSparseSignature(IplImage *patch, float *sig, float thresh)
856 getFloatSignature(patch, sig);
857 for (int i=0; i<classes_; ++i, sig++)
858 if (*sig < thresh) *sig = 0.f;
861 int RTreeClassifier::countNonZeroElements(float *vec, int n, double tol)
865 res += (fabs(*vec++) > tol);
869 void RTreeClassifier::read(const char* file_name)
871 std::ifstream file(file_name, std::ifstream::binary);
876 void RTreeClassifier::read(std::istream &is)
879 is.read((char*)(&num_trees), sizeof(num_trees));
880 is.read((char*)(&classes_), sizeof(classes_));
881 is.read((char*)(&original_num_classes_), sizeof(original_num_classes_));
882 is.read((char*)(&num_quant_bits_), sizeof(num_quant_bits_));
884 if (num_quant_bits_<1 || num_quant_bits_>8) {
885 printf("[WARNING] RTC: suspicious value num_quant_bits_=%i found; setting to %i.\n",
886 num_quant_bits_, (int)DEFAULT_NUM_QUANT_BITS);
887 num_quant_bits_ = DEFAULT_NUM_QUANT_BITS;
890 trees_.resize(num_trees);
891 std::vector<RandomizedTree>::iterator tree_it;
893 for (tree_it = trees_.begin(); tree_it != trees_.end(); ++tree_it) {
894 tree_it->read(is, num_quant_bits_);
897 printf("[OK] Loaded RTC, quantization=%i bits\n", num_quant_bits_);
902 void RTreeClassifier::write(const char* file_name) const
904 std::ofstream file(file_name, std::ofstream::binary);
909 void RTreeClassifier::write(std::ostream &os) const
911 int num_trees = trees_.size();
912 os.write((char*)(&num_trees), sizeof(num_trees));
913 os.write((char*)(&classes_), sizeof(classes_));
914 os.write((char*)(&original_num_classes_), sizeof(original_num_classes_));
915 os.write((char*)(&num_quant_bits_), sizeof(num_quant_bits_));
916 printf("RTreeClassifier::write: num_quant_bits_=%i\n", num_quant_bits_);
918 std::vector<RandomizedTree>::const_iterator tree_it;
919 for (tree_it = trees_.begin(); tree_it != trees_.end(); ++tree_it)
923 void RTreeClassifier::saveAllFloatPosteriors(std::string url)
925 printf("[DEBUG] writing all float posteriors to %s...\n", url.c_str());
926 for (int i=0; i<(int)trees_.size(); ++i)
927 trees_[i].savePosteriors(url, (i==0 ? false : true));
928 printf("[DEBUG] done\n");
931 void RTreeClassifier::saveAllBytePosteriors(std::string url)
933 printf("[DEBUG] writing all byte posteriors to %s...\n", url.c_str());
934 for (int i=0; i<(int)trees_.size(); ++i)
935 trees_[i].savePosteriors2(url, (i==0 ? false : true));
936 printf("[DEBUG] done\n");
940 void RTreeClassifier::setFloatPosteriorsFromTextfile_176(std::string url)
942 std::ifstream ifs(url.c_str());
944 for (int i=0; i<(int)trees_.size(); ++i) {
945 int num_classes = trees_[i].classes_;
946 assert(num_classes == 176); // TODO: remove this limitation (arose due to SSE2 optimizations)
947 for (int k=0; k<trees_[i].num_leaves_; ++k) {
948 float *post = trees_[i].getPosteriorByIndex(k);
949 for (int j=0; j<num_classes; ++j, ++post)
956 //setQuantization(num_quant_bits_);
959 printf("[EXPERIMENTAL] read entire tree from '%s'\n", url.c_str());
963 float RTreeClassifier::countZeroElements()
967 int num_elem = trees_[0].classes();
968 for (int i=0; i<(int)trees_.size(); ++i)
969 for (int k=0; k<(int)trees_[i].num_leaves_; ++k) {
970 float *p = trees_[i].getPosteriorByIndex(k);
971 uchar *p2 = trees_[i].getPosteriorByIndex2(k);
972 assert(p); assert(p2);
973 for (int j=0; j<num_elem; ++j, ++p, ++p2) {
974 if (*p == 0.f) flt_zeros++;
975 if (*p2 == 0) ui8_zeros++;
978 num_elem = trees_.size()*trees_[0].num_leaves_*num_elem;
979 float flt_perc = 100.*flt_zeros/num_elem;
980 float ui8_perc = 100.*ui8_zeros/num_elem;
981 printf("[OK] RTC: overall %i/%i (%.3f%%) zeros in float leaves\n", flt_zeros, num_elem, flt_perc);
982 printf(" overall %i/%i (%.3f%%) zeros in uint8 leaves\n", ui8_zeros, num_elem, ui8_perc);
987 void RTreeClassifier::setQuantization(int num_quant_bits)
989 for (int i=0; i<(int)trees_.size(); ++i)
990 trees_[i].applyQuantization(num_quant_bits);
992 printf("[OK] signature quantization is now %i bits (before: %i)\n", num_quant_bits, num_quant_bits_);
993 num_quant_bits_ = num_quant_bits;
996 void RTreeClassifier::discardFloatPosteriors()
998 for (int i=0; i<(int)trees_.size(); ++i)
999 trees_[i].discardFloatPosteriors();
1000 printf("[OK] RTC: discarded float posteriors of all trees\n");
1003 //} // namespace features