Classifiers.cpp
上传用户:lijia5631
上传日期:2008-11-10
资源大小:1214k
文件大小:16k
源码类别:

视频捕捉/采集

开发平台:

MultiPlatform

  1. /**
  2.   * cubicles
  3.   *
  4.   * This is an implementation of the Viola-Jones object detection 
  5.   * method and some extensions.  The code is mostly platform-
  6.   * independent and uses only standard C and C++ libraries.  It
  7.   * can make use of MPI for parallel training and a few Windows
  8.   * MFC functions for classifier display.
  9.   *
  10.   * Mathias Kolsch, matz@cs.ucsb.edu
  11.   *
  12.   * $Id: Classifiers.cpp,v 1.57 2005/10/28 17:47:04 matz Exp $
  13. **/
  14. // Classifiers.cpp : implementation file for weak and strong
  15. // classifiers.  A weak classifier is an IntegralFeature and
  16. // a threshold.  A strong classifier is a linear combination
  17. // of weak classifiers.
  18. // Functions for reading from files are flex/bison generated from
  19. // CascadeFileScanner.lex and CascadeFileParser.yy.
  20. //
  21. ////////////////////////////////////////////////////////////////////
  22. //
  23. // By downloading, copying, installing or using the software you 
  24. // agree to this license.  If you do not agree to this license, 
  25. // do not download, install, copy or use the software.
  26. //
  27. // Copyright (C) 2004, Mathias Kolsch, all rights reserved.
  28. // Third party copyrights are property of their respective owners.
  29. //
  30. // Redistribution and use in binary form, with or without 
  31. // modification, is permitted for non-commercial purposes only.
  32. // Redistribution in source, with or without modification, is 
  33. // prohibited without prior written permission.
  34. // If granted in writing in another document, personal use and 
  35. // modification are permitted provided that the following two
  36. // conditions are met:
  37. //
  38. // 1.Any modification of source code must retain the above 
  39. //   copyright notice, this list of conditions and the following 
  40. //   disclaimer.
  41. //
  42. // 2.Redistribution's in binary form must reproduce the above 
  43. //   copyright notice, this list of conditions and the following 
  44. //   disclaimer in the documentation and/or other materials provided
  45. //   with the distribution.
  46. //
  47. // This software is provided by the copyright holders and 
  48. // contributors "as is" and any express or implied warranties, 
  49. // including, but not limited to, the implied warranties of 
  50. // merchantability and fitness for a particular purpose are 
  51. // disclaimed.  In no event shall the copyright holder or 
  52. // contributors be liable for any direct, indirect, incidental, 
  53. // special, exemplary, or consequential damages (including, but not 
  54. // limited to, procurement of substitute goods or services; loss of 
  55. // use, data, or profits; or business interruption) however caused
  56. // and on any theory of liability, whether in contract, strict 
  57. // liability, or tort (including negligence or otherwise) arising 
  58. // in any way out of the use of this software, even if advised of 
  59. // the possibility of such damage.
  60. //
  61. ////////////////////////////////////////////////////////////////////
  62. #include "cubicles.hpp"
  63. #include "Classifiers.h"
  64. #ifdef HAVE_FLOAT_H
  65. #include <float.h>
  66. #endif
  67. #include <iostream>
  68. #ifdef IMG_LIB_OPENCV
  69. #include <cxcore.h>
  70. #endif
  71. #ifdef _DEBUG
  72. #ifdef USE_MFC
  73. #define new DEBUG_NEW
  74. #undef THIS_FILE
  75. static char THIS_FILE[] = __FILE__;
  76. #endif // USE_MFC
  77. #endif // _DEBUG
  78. #include <math.h>
  79. #include <iomanip>    // for setprecision
  80. using std::ofstream;
  81. /////////////////////////////////////////////////////////////////////////////
  82. //
  83. // CWeakClassifier implementation
  84. //
  85. /////////////////////////////////////////////////////////////////////////////
  86. // "this->threshold" should lie within these boundaries:
  87. const double CWeakClassifier::MIN_THRESHOLD = -(DBL_MAX/10.0);
  88. const double CWeakClassifier::MAX_THRESHOLD = DBL_MAX/10.0;
  89. const double CWeakClassifier::EPSILON_THRESHOLD = 6.8e-07;
  90. const int CWeakClassifier::THRESHOLD_PRECISION = 6;
  91. /* round to "precision" digits after the comma
  92.  */
  93. double round(double d, int precision)
  94. {
  95.   for (int p=0; p<precision; p++) {
  96.     d *= 10.0;
  97.   }
  98. #ifdef IMG_LIB_OPENCV
  99.   double r = cvRound(d); // optimized
  100. #else
  101.   double r = round(d);
  102. #endif
  103.   for (int p=0; p<precision; p++) {
  104.     r /= 10.0;
  105.   }
  106.   return r;
  107. }
  108. CWeakClassifier::CWeakClassifier()
  109.   : feature(NULL),
  110.     sign_lt(true),
  111.     threshold(0),
  112.     train_error(DBL_MAX)
  113. {
  114. }
  115. CWeakClassifier::CWeakClassifier(CIntegralFeature* pFeature, 
  116.                                  bool is_lt, double thresh, double error)
  117.   : feature(pFeature),
  118.     sign_lt(is_lt),
  119.     train_error(error)
  120. {
  121.   SetThreshold(thresh);
  122. }
  123. CWeakClassifier::CWeakClassifier(const CWeakClassifier& frm)
  124.   : feature(NULL)
  125. {
  126.   CopyFrom(frm);
  127. }
  128. CWeakClassifier::~CWeakClassifier()
  129. {
  130.   delete feature;
  131.   feature = NULL;
  132. }
  133. void CWeakClassifier::CopyFrom(const CWeakClassifier& frm_classf, const CIntegralFeature& frm_feature)
  134. {
  135.   delete feature;
  136.   feature = frm_feature.Copy();
  137.   threshold = frm_classf.threshold;
  138.   sign_lt = frm_classf.sign_lt;
  139.   train_error = frm_classf.train_error;
  140. }
  141. void CWeakClassifier::CopyFrom(const CWeakClassifier& frm_classf)
  142. {
  143.   delete feature;
  144.   if (frm_classf.feature) {
  145.     feature = frm_classf.feature->Copy();
  146.   } else {
  147.     feature = NULL;
  148.   }
  149.   threshold = frm_classf.threshold;
  150.   sign_lt = frm_classf.sign_lt;
  151.   train_error = frm_classf.train_error;
  152. }
  153. CWeakClassifier& CWeakClassifier::operator=(const CWeakClassifier& frm)
  154. {
  155.   CopyFrom(frm);
  156.   return *this;
  157. }
  158. bool CWeakClassifier::operator==(const CWeakClassifier& from) const
  159. {
  160.   if (feature==NULL && from.feature==NULL) return true;
  161.   if (threshold!=from.threshold) return false;
  162.   if (sign_lt!=from.sign_lt) return false;
  163.   if (feature==NULL || from.feature==NULL) return false;
  164.   
  165.   return feature->Equals(*from.feature);
  166. }
  167. const CIntegralFeature& 
  168. CWeakClassifier::GetFeature() const
  169. {
  170. ASSERT(feature!=NULL);
  171. return *feature;
  172. }
  173. void CWeakClassifier::SetThreshold(double thresh)
  174. {
  175.   threshold = round(thresh, THRESHOLD_PRECISION);
  176. }
  177. bool CWeakClassifier::Evaluate(const CIntegralImage& image) const
  178. {
  179.   ASSERT(feature);
  180.   double feature_value = feature->Compute(image);
  181.   if (sign_lt) {
  182.     return feature_value<threshold;
  183.   } else {
  184.     return feature_value>=threshold;
  185.   }
  186. }
  187. bool CWeakClassifier::Evaluate(const CIntegralImage& image, double mean, double stddev, int left, int top) const
  188. {
  189.   ASSERT(feature);
  190.   double feature_value = feature->ComputeScaled(image, mean, left, top);
  191.   feature_value /= stddev;
  192. #if defined(II_TYPE_INT) || defined(II_TYPE_UINT)
  193.   feature_value /= stddev;
  194.   feature_value *= 127.5;
  195.   feature_value += 127.5;
  196. #endif
  197.   if (sign_lt) {
  198.     return feature_value<threshold;
  199.   } else {
  200.     return feature_value>=threshold;
  201.   }
  202. }
  203. #ifdef WITH_TRAINING
  204. bool CWeakClassifier::Evaluate(const ExampleList::const_iterator example) const
  205. {
  206.   ASSERT(feature);
  207.   if (sign_lt) {
  208.     return feature->Compute(example)<threshold;
  209.   } else {
  210.     return feature->Compute(example)>=threshold;
  211.   }
  212. }
  213. bool CWeakClassifier::IsValid() const
  214. {
  215.   bool finite;
  216. #ifdef HAVE_ISNAN
  217.   finite = !isnan(train_error);
  218. #else
  219. #error how to check for overflow on this platform?
  220. #endif
  221.   return (finite
  222.         && !(threshold>=CWeakClassifier::MAX_THRESHOLD)
  223.         && !(threshold<=CWeakClassifier::MIN_THRESHOLD)
  224.         && !(fabs(threshold)<CWeakClassifier::EPSILON_THRESHOLD));
  225. }
  226. #endif // WITH_TRAINING
  227. ostream& operator<<(ostream& os, const CWeakClassifier& clsf)
  228. {
  229. os << "[";
  230. if (clsf.feature) {
  231.   clsf.feature->output(os);
  232. } else {
  233.   os << "NULL";
  234. }
  235. os << "]" << (clsf.sign_lt?"<":">=");
  236. os << std::fixed
  237.    << std::setprecision (CWeakClassifier::THRESHOLD_PRECISION)
  238.    << clsf.threshold << " ";
  239. os << "(" << clsf.train_error << ")";
  240. return os;
  241. }
  242. void CWeakClassifier::ParseFrom(istream& is, int template_width, int template_height)
  243. {
  244.   delete feature;
  245.   feature = NULL;
  246.   char c, d, e, f;
  247.   is >> c;
  248.   if (c!='[') {
  249.     is.putback(c);
  250.     throw ITException(string("wrong character on input stream: '")+c+string("'"));
  251.   }
  252.   is >> c >> d >> e >> f;
  253.   if (c=='N' && d=='U' && e=='L' && f=='L') {
  254.     // feature = NULL;
  255.   } else {
  256.     is.putback(f), is.putback(e), is.putback(d), is.putback(c);
  257.     feature = CIntegralFeature::CreateFrom(is, template_width, template_height);
  258.   }
  259.   is >> c;
  260.   if (c!=']') {
  261.     is.putback(c);
  262.     throw ITException(string("wrong character on input stream: '")+c+string("'"));
  263.   }
  264.   is >> c >> d;
  265.   if (c=='<') {
  266.     sign_lt=true;
  267.     is.putback(d);
  268.   } else if (c=='>' && d=='=') {
  269.     sign_lt=false;
  270.   } else {
  271.     char buf[256];
  272.     sprintf(buf, "wrong characters on input stream (%c|%c)n", c, d);
  273.     throw ITException(buf);
  274.   }
  275.   double thresh;
  276.   is >> thresh;
  277.   SetThreshold(thresh);
  278.   is >> c >> train_error >> d;
  279.   if (c!='(' || d!=')') {
  280.     is.putback(d);
  281.     char s[32];
  282.     sprintf(s, "%f", train_error);
  283.     for (int i=0; i<(int)strlen(s); i++) is.putback(s[i]);
  284.     is.putback(c);
  285.     char buf[256];
  286.     sprintf(buf, "wrong character on input stream: '%c|%f|%c'n", 
  287.             c, (float)train_error, d);
  288.     throw ITException(buf);
  289.   }
  290. }
  291. void CWeakClassifier::ScaleFeatureEvenly(double scale_x, double scale_y,
  292.         int scaled_template_width, int scaled_template_height)
  293. {
  294.   feature->ScaleEvenly(scale_x, scale_y, 
  295.        scaled_template_width, scaled_template_height);
  296. }
  297. int CWeakClassifier::GetComputeCost() const
  298. {
  299.   ASSERT(feature);
  300.   return feature->GetComputeCost();
  301. }
  302. /////////////////////////////////////////////////////////////////////////////
  303. //
  304. //  CStrongClassifier implementation
  305. //
  306. /////////////////////////////////////////////////////////////////////////////
  307. CStrongClassifier::CStrongClassifier(const CStrongClassifier& from)
  308. : m_num_hyps(from.m_num_hyps),
  309. m_alphas_thresh(from.m_alphas_thresh),
  310. m_sum_alphas(from.m_sum_alphas),
  311.   m_pClassifiers(NULL),
  312.   m_alphas(NULL)
  313. {
  314.   if (m_num_hyps) {
  315.    m_pClassifiers = new CWeakClassifier*[m_num_hyps];
  316.   m_alphas = new double[m_num_hyps];
  317.   }
  318. double sum_alphas=0.0;
  319. for (int hcnt=0; hcnt<m_num_hyps; hcnt++) {
  320. m_pClassifiers[hcnt] = new CWeakClassifier(*from.m_pClassifiers[hcnt]);
  321. m_alphas[hcnt] = from.m_alphas[hcnt];
  322. sum_alphas += m_alphas[hcnt];
  323. }
  324. ASSERT(sum_alphas==m_sum_alphas);
  325. }
  326. CStrongClassifier::CStrongClassifier()
  327. : m_num_hyps(0),
  328. m_alphas_thresh(0.5),
  329.   m_pClassifiers(NULL),
  330.   m_alphas(NULL),
  331. m_sum_alphas(0.0)
  332. {
  333. }
  334. CStrongClassifier::~CStrongClassifier()
  335. {
  336. for (int hcnt=0; hcnt<m_num_hyps; hcnt++) {
  337. delete m_pClassifiers[hcnt];
  338. m_pClassifiers[hcnt] = NULL;
  339. }
  340.   delete[] m_pClassifiers;
  341. m_pClassifiers = NULL;
  342.   delete[] m_alphas;
  343.   m_alphas = NULL;
  344. }
  345. CStrongClassifier& CStrongClassifier::operator=(const CStrongClassifier& from)
  346. {
  347. this->~CStrongClassifier();
  348. m_num_hyps = from.m_num_hyps;
  349. m_alphas_thresh = from.m_alphas_thresh;
  350. m_sum_alphas = from.m_sum_alphas;
  351.   if (m_num_hyps) {
  352.    m_pClassifiers = new CWeakClassifier*[m_num_hyps];
  353.   m_alphas = new double[m_num_hyps];
  354.   } else {
  355.     m_pClassifiers = NULL;
  356.     m_alphas = NULL;
  357.   }
  358. double sum_alphas=0.0;
  359. for (int hcnt=0; hcnt<m_num_hyps; hcnt++) {
  360. m_pClassifiers[hcnt] = 
  361.                   new CWeakClassifier(*from.m_pClassifiers[hcnt]);
  362. m_alphas[hcnt] = from.m_alphas[hcnt];
  363. sum_alphas += m_alphas[hcnt];
  364. }
  365. ASSERT(sum_alphas==m_sum_alphas);
  366. return *this;
  367. }
  368. void 
  369. CStrongClassifier::AddWeakClassifier(CWeakClassifier* pClassifier, double alpha)
  370. {
  371. // save old array pointers
  372. CWeakClassifier** tmp_pClassifiers=m_pClassifiers;
  373. double* tmp_alphas=m_alphas;
  374. int old_num_hyps=m_num_hyps;
  375. m_num_hyps++;
  376. // create new arrays
  377. m_pClassifiers=new CWeakClassifier*[m_num_hyps];
  378. m_alphas=new double[m_num_hyps];
  379. // copy old to new
  380. int hcnt=0;
  381. for (; hcnt<old_num_hyps; hcnt++) {
  382. m_pClassifiers[hcnt]=tmp_pClassifiers[hcnt];
  383. m_alphas[hcnt]=tmp_alphas[hcnt];
  384. }
  385. // delete old
  386. delete[] tmp_pClassifiers;
  387. delete[] tmp_alphas;
  388. // insert new
  389. m_pClassifiers[hcnt]=new CWeakClassifier(*pClassifier);
  390. m_alphas[hcnt]=alpha;
  391. m_sum_alphas+=alpha;
  392. }
  393. int
  394. CStrongClassifier::RemoveLastWeakClassifier()
  395. {
  396.   if (m_num_hyps) {
  397.     m_num_hyps--;
  398.     delete m_pClassifiers[m_num_hyps];
  399.     m_pClassifiers[m_num_hyps] = NULL;
  400.     m_sum_alphas -= m_alphas[m_num_hyps];
  401.     return m_num_hyps;
  402.   } else {
  403.     return m_num_hyps;
  404.   }
  405. }
  406. const CWeakClassifier&
  407. CStrongClassifier::GetWeakClassifier(int num) const
  408. {
  409. ASSERT(num<m_num_hyps);
  410. return *m_pClassifiers[num];
  411. }
  412. void CStrongClassifier::ParseFrom(istream& is, int template_width, int template_height)
  413. {
  414.   // delete old, make consistent state
  415.   this->~CStrongClassifier();
  416.   m_num_hyps = 0;
  417.   string str, str2, str3;
  418.   char c;
  419.   int num_hyps;
  420.   is >> num_hyps >> str >> str2 >> str3 >> m_alphas_thresh >> c;
  421.   if (str!="weak" || str2!="classifiers," || str3!="threshold" || c!=':') {
  422.     throw ITException("expected 'n weak classsfiers, threshold f:'");
  423.   }
  424.   // we have to post-parse assign m_num_hyps, and we have to 
  425.   // do CWeakClassifier() allocation in a separate, early loop,
  426.   // because we might bail out with "return false" at any moment
  427.   // which would otherwise leave the StrongClassifier datastructure
  428.   // in an inconsistent state, which is hard to delete
  429.   m_num_hyps = num_hyps;
  430.   if (m_num_hyps) {
  431.     m_pClassifiers = new CWeakClassifier*[m_num_hyps];
  432.     m_alphas = new double[m_num_hyps];
  433.   } else {
  434.     m_pClassifiers = NULL;
  435.     m_alphas = NULL;
  436.   }
  437.   for (int hcnt=0; hcnt<m_num_hyps; hcnt++) {
  438.     double alpha=-1;
  439.     is >> alpha >> str;
  440.     if (str!="*") {
  441.       // check if all weak classifiers have numbers as alpha values
  442.       throw ITException("expected '*'");
  443.     }
  444.     m_pClassifiers[hcnt] = new CWeakClassifier();
  445.     m_pClassifiers[hcnt]->ParseFrom(is, template_width, template_height);
  446.     /*
  447.     ofstream out("c:\tmp\dump.txt", ios::out | ios::app);
  448.     out << *m_pClassifiers[hcnt] << endl;
  449.     out.flush();
  450.     out.close();
  451. */
  452.     m_alphas[hcnt]=alpha;
  453.     m_sum_alphas+=alpha;
  454.   }
  455. }
  456. ostream& operator<<(ostream& os, const CStrongClassifier& clsf)
  457. {
  458.   os << clsf.m_num_hyps << " weak classifiers, threshold " 
  459.      << clsf.m_alphas_thresh << ":" << endl;
  460.   for (int hcnt=0; hcnt<clsf.m_num_hyps; hcnt++) {
  461.     os << clsf.m_alphas[hcnt] << " * ";
  462.     os << *clsf.m_pClassifiers[hcnt];
  463.     os << "n";
  464.   }
  465.   return os;
  466. }
  467. bool CStrongClassifier::Evaluate(const CIntegralImage& image) const
  468. {
  469. double sum=0.0;
  470. for (int hcnt=0; hcnt<m_num_hyps; hcnt++) {
  471. sum += m_alphas[hcnt] * m_pClassifiers[hcnt]->Evaluate(image);
  472. }
  473. ASSERT(m_alphas_thresh); // this should be greater than zero, otherwise
  474. // the strong classifier doesn't do any classification.
  475. return (sum >= m_alphas_thresh*m_sum_alphas);
  476. }
  477. bool CStrongClassifier::Evaluate(const CIntegralImage& image, double mean, double stddev, int left, int top) const
  478. {
  479. double sum=0.0;
  480. for (int hcnt=0; hcnt<m_num_hyps; hcnt++) {
  481.   sum += 
  482.     m_alphas[hcnt] 
  483.     * m_pClassifiers[hcnt]->Evaluate(image, mean, stddev, left, top);
  484. }
  485. ASSERT(m_alphas_thresh); // this should be greater than zero, otherwise
  486. // the strong classifier doesn't do any classification.
  487. return (sum >= m_alphas_thresh*m_sum_alphas);
  488. }
  489. void CStrongClassifier::EvaluateThreshs(const CIntegralImage& image,
  490. double mean, double stddev,
  491. int left, int top,
  492. CIntVector& numMatches,
  493. const CDoubleVector& threshs) const
  494. {
  495.   double sum=0.0;
  496.   for (int hcnt=0; hcnt<m_num_hyps; hcnt++) {
  497.     sum += 
  498.       m_alphas[hcnt] 
  499.       * m_pClassifiers[hcnt]->Evaluate(image, mean, stddev, left, top);
  500.   }
  501.   // do the classification for each threshold
  502.   int num_threshs = (int) threshs.size();
  503.   for (int tcnt=0; tcnt<num_threshs; tcnt++) {
  504.     double thresh = threshs[tcnt];
  505.     if (sum >= thresh*m_sum_alphas) {
  506.       numMatches[tcnt]++;
  507.     }
  508.   }
  509. }
  510. void CStrongClassifier::ScaleFeaturesEvenly(double scale_x, double scale_y,
  511.     int scaled_template_width, 
  512.     int scaled_template_height)
  513. {
  514.   for (int hcnt=0; hcnt<m_num_hyps; hcnt++) {
  515.     m_pClassifiers[hcnt]->ScaleFeatureEvenly(scale_x, scale_y,
  516.                                              scaled_template_width, 
  517.      scaled_template_height);
  518.   }
  519. }
  520. int CStrongClassifier::GetComputeCost() const
  521. {
  522.   int sum = 0;
  523.   for (int hcnt=0; hcnt<m_num_hyps; hcnt++) {
  524.     sum += m_pClassifiers[hcnt]->GetComputeCost();
  525.   }
  526.   return sum;
  527. }