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

视频捕捉/采集

开发平台:

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: Scanner.cpp,v 1.48 2004/11/11 01:58:58 matz Exp $
  13. **/
  14. // Scanner scans across an image and finds matches for the 
  15. // classifier cascade.  There's also a Scanner_Train.cpp
  16. // implementation file that for training-only functions.
  17. //
  18. ////////////////////////////////////////////////////////////////////
  19. //
  20. // By downloading, copying, installing or using the software you 
  21. // agree to this license.  If you do not agree to this license, 
  22. // do not download, install, copy or use the software.
  23. //
  24. // Copyright (C) 2004, Mathias Kolsch, all rights reserved.
  25. // Third party copyrights are property of their respective owners.
  26. //
  27. // Redistribution and use in binary form, with or without 
  28. // modification, is permitted for non-commercial purposes only.
  29. // Redistribution in source, with or without modification, is 
  30. // prohibited without prior written permission.
  31. // If granted in writing in another document, personal use and 
  32. // modification are permitted provided that the following two
  33. // conditions are met:
  34. //
  35. // 1.Any modification of source code must retain the above 
  36. //   copyright notice, this list of conditions and the following 
  37. //   disclaimer.
  38. //
  39. // 2.Redistribution's in binary form must reproduce the above 
  40. //   copyright notice, this list of conditions and the following 
  41. //   disclaimer in the documentation and/or other materials provided
  42. //   with the distribution.
  43. //
  44. // This software is provided by the copyright holders and 
  45. // contributors "as is" and any express or implied warranties, 
  46. // including, but not limited to, the implied warranties of 
  47. // merchantability and fitness for a particular purpose are 
  48. // disclaimed.  In no event shall the copyright holder or 
  49. // contributors be liable for any direct, indirect, incidental, 
  50. // special, exemplary, or consequential damages (including, but not 
  51. // limited to, procurement of substitute goods or services; loss of 
  52. // use, data, or profits; or business interruption) however caused
  53. // and on any theory of liability, whether in contract, strict 
  54. // liability, or tort (including negligence or otherwise) arising 
  55. // in any way out of the use of this software, even if advised of 
  56. // the possibility of such damage.
  57. //
  58. ////////////////////////////////////////////////////////////////////
  59. #include "cubicles.hpp"
  60. #include "Scanner.h"
  61. #include "Cascade.h"
  62. #include <math.h>
  63. #include <iostream>
  64. #ifdef _DEBUG
  65. #ifdef USE_MFC
  66. #define new DEBUG_NEW
  67. #undef THIS_FILE
  68. static char THIS_FILE[] = __FILE__;
  69. #endif // USE_MFC
  70. #endif // _DEBUG
  71. // ----------------------------------------------------------------------
  72. // class CImageScanner
  73. // ----------------------------------------------------------------------
  74. CImageScanner::CImageScanner() 
  75. : m_is_active(true),
  76.   m_post_process(false)
  77. {
  78.   SetScanParameters();
  79. }
  80. CImageScanner::CImageScanner(const CImageScanner& src) 
  81. : m_is_active(src.m_is_active),
  82.   m_start_scale(src.m_start_scale),
  83.   m_stop_scale(src.m_stop_scale),
  84.   m_scale_inc_factor(src.m_scale_inc_factor),
  85.   m_translation_inc_x(src.m_translation_inc_x),
  86.   m_translation_inc_y(src.m_translation_inc_y),
  87.   m_scan_area(src.m_scan_area),
  88.   m_post_process(src.m_post_process),
  89.   m_min_scaled_template_width(-1),
  90.   m_max_scaled_template_width(-1),
  91.   m_min_scaled_template_height(-1),
  92.   m_max_scaled_template_height(-1),
  93.   m_integral(src.m_integral),
  94.   m_squared_integral(src.m_squared_integral)
  95. {
  96. }
  97. void CImageScanner::SetScanParameters(
  98.                                       double start_scale /* = 1.0 */,
  99.                                       double stop_scale /* = DBL_MAX */,
  100.                                       double scale_inc_factor /* = 1.25 */,
  101.                                       double translation_inc_x /* = 1.0 */,
  102.                                       double translation_inc_y /* = 1.0 */,
  103.                                       CRect scan_area /* = CRect(0, 0, INT_MAX, INT_MAX) */
  104.                                       )
  105. {
  106.   SetScanScales(start_scale, stop_scale);
  107.   m_scale_inc_factor = scale_inc_factor;
  108.   m_translation_inc_x = translation_inc_x;
  109.   m_translation_inc_y = translation_inc_y;
  110.   m_scan_area = scan_area;
  111.   m_min_scaled_template_width = -1;
  112.   m_max_scaled_template_width = -1;
  113.   m_min_scaled_template_height = -1;
  114.   m_max_scaled_template_height = -1;
  115. }
  116. void CImageScanner::GetScanParameters(
  117.     double* pStart_scale,
  118.     double* pStop_scale,
  119.     double* pScale_inc_factor,
  120.     double* pTranslation_inc_x,
  121.     double* pTranslation_inc_y,
  122.     CRect& scan_area,
  123.     bool* pPostProcessing,
  124.     bool* pIsActive
  125.     ) const
  126. {
  127.   *pStart_scale = m_start_scale;
  128.   *pStop_scale = m_stop_scale;
  129.   *pScale_inc_factor = m_scale_inc_factor;
  130.   *pTranslation_inc_x = m_translation_inc_x;
  131.   *pTranslation_inc_y = m_translation_inc_y;
  132.   *pPostProcessing = m_post_process;
  133.   *pIsActive = m_is_active;
  134.   scan_area = m_scan_area;
  135. }
  136. void CImageScanner::SetScanArea(const CRect& scan_area)
  137. {
  138.   m_scan_area = scan_area;
  139. }
  140. void CImageScanner::SetScanScales(double start_scale, double stop_scale)
  141. {
  142.   m_start_scale = start_scale;
  143.   m_stop_scale = stop_scale;
  144.   m_min_scaled_template_width = -1;
  145.   m_max_scaled_template_width = -1;
  146.   m_min_scaled_template_height = -1;
  147.   m_max_scaled_template_height = -1;
  148. }
  149. // must be called after the actual scan, and the behavior with
  150. // multiple active scanners is somewhat undetermined
  151. void CImageScanner::GetScaleSizes(int* min_width, int* max_width,
  152.   int* min_height, int* max_height) const
  153. {
  154.   *min_width = m_min_scaled_template_width;
  155.   *max_width = m_max_scaled_template_width;
  156.   *min_height = m_min_scaled_template_height;
  157.   *max_height = m_max_scaled_template_height;
  158. }
  159. void CImageScanner::SetAutoPostProcessing(bool on /*=true*/)
  160. {
  161.   m_post_process = on;
  162. }
  163. const CRect& CImageScanner::GetScanArea() const
  164. {
  165.   return m_scan_area;
  166. }
  167. int
  168. CImageScanner::Scan(const CClassifierCascade& cascade,
  169.     const CByteImage& image, CScanMatchVector& posClsfd) const
  170. {
  171.   if (!m_is_active) return -1;
  172.   // make integral of regular and squared image
  173.   CIntegralImage::CreateSimpleNSquaredFrom(image, m_integral,
  174.    m_squared_integral, m_scan_area);
  175.   return Scan(cascade, m_integral, m_squared_integral, posClsfd);
  176. }
  177. int
  178. CImageScanner::Scan(const CClassifierCascade& cascade,
  179.     const CIntegralImage& integral,
  180.                     const CIntegralImage& squared_integral,
  181.                     CScanMatchVector& posClsfd) const
  182. {
  183.   if (!m_is_active) return -1;
  184.   posClsfd.clear();  
  185.   CScaleParams sclprms;
  186.   InitScaleParams(cascade, sclprms);
  187.   m_min_scaled_template_width = sclprms.scaled_template_width;
  188.   m_min_scaled_template_height = sclprms.scaled_template_height;
  189.   double N = sclprms.scaled_template_width * sclprms.scaled_template_height;
  190.   
  191.   int width = integral.GetWidth();
  192.   int height = integral.GetHeight();
  193.   
  194.   CStringVector matches;
  195.   int scancnt=0;
  196.   while (sclprms.scaled_template_width<width && sclprms.scaled_template_height<height
  197.     && sclprms.base_scale<m_stop_scale) 
  198.   {
  199.     cascade.ScaleFeaturesEvenly(sclprms.actual_scale_x, 
  200. sclprms.actual_scale_y,
  201. sclprms.scaled_template_width, 
  202. sclprms.scaled_template_height);
  203.     // for each y-location in the image
  204.     int top_stop = min(m_scan_area.bottom, height)-sclprms.scaled_template_height;
  205.     for (int top=max(0, m_scan_area.top); top<top_stop; top+=(int)sclprms.translation_inc_y) {
  206.       int bottom = top+sclprms.scaled_template_height;
  207.       // for each x-location in the image
  208.       int left_stop = min(m_scan_area.right, width)-sclprms.scaled_template_width;
  209.       for (int left=max(0, m_scan_area.left); left<left_stop; left+=(int)sclprms.translation_inc_x) {
  210.         int right = left+sclprms.scaled_template_width;
  211.         double sum_x = 
  212.           integral.GetElement(right-1, bottom-1) 
  213.           - integral.GetElement(right-1, top-1)
  214.           - integral.GetElement(left-1, bottom-1)
  215.           + integral.GetElement(left-1, top-1);
  216.         double mean =
  217.           sum_x / N;
  218.         double sum_x2 = 
  219.           squared_integral.GetElement(right-1, bottom-1) 
  220.           - squared_integral.GetElement(right-1, top-1)
  221.           - squared_integral.GetElement(left-1, bottom-1)
  222.           + squared_integral.GetElement(left-1, top-1);
  223.         double stddev = sqrt(fabs(mean*mean - sum_x2/N));
  224.         //  double stddev_equal = sqrt(fabs(mean*mean - 2.0*sum_x*mean/N + sum_x2/N));
  225.         bool is_positive =
  226.           cascade.Evaluate(integral, mean, stddev, left, top, matches);
  227.         if (is_positive) {
  228.           for (int m=0; m<(int)matches.size(); m++) {
  229.             posClsfd.push_back(CScanMatch(left, top, right, bottom,
  230.                                           sclprms.base_scale,
  231.                                           sclprms.scale_x, sclprms.scale_y,
  232.                                           matches[m]));
  233.           }
  234.           matches.clear();
  235.         }
  236.         scancnt++;
  237.       }
  238.     }
  239.     m_max_scaled_template_width = sclprms.scaled_template_width;
  240.     m_max_scaled_template_height = sclprms.scaled_template_height;
  241.     NextScaleParams(sclprms);
  242.     ASSERT(N!=sclprms.scaled_template_width*sclprms.scaled_template_height);
  243.     N = sclprms.scaled_template_width * sclprms.scaled_template_height;
  244.   }
  245.   if (m_post_process) {
  246.     PostProcess(posClsfd);
  247.     return (int) posClsfd.size();
  248.   } else {
  249.     return scancnt;
  250.   }
  251. }
  252. bool intersect(const CScanMatch& a, const CScanMatch& b)
  253. {
  254. if (a.left<=b.left && b.left<=a.right ||
  255.   a.left<=b.right && b.right<=a.right ||
  256. a.top<=b.top && b.top<=a.bottom ||
  257. a.top<=b.bottom && b.bottom<=a.bottom ||
  258. b.left<=a.left && a.left<=b.right ||
  259.   b.left<=a.right && a.right<=b.right ||
  260. b.top<=a.top && a.top<=b.bottom ||
  261. b.top<=a.bottom && a.bottom<=b.bottom)
  262. {
  263. return true;
  264. } else {
  265. return false;
  266. }
  267. }
  268. /** throw out some positives if they overlap, pick the average
  269. * of each coordinate for every overlapping set
  270. */
  271. void CImageScanner::PostProcess(CScanMatchVector& posClsfd) const
  272. {
  273. int num_matches = (int)posClsfd.size();
  274. if (num_matches<2) return;
  275. // partition all matches into disjoint clusters
  276. CIntVector clustnums;
  277. clustnums.resize(num_matches);
  278. clustnums[0] = 0;
  279. int num_clusters = 1;
  280. for (int matchcnt=1; matchcnt<num_matches; matchcnt++) {
  281. clustnums[matchcnt] = -1;
  282. for (int prevcnt=0; prevcnt<matchcnt; prevcnt++) {
  283. if (intersect(posClsfd[prevcnt], posClsfd[matchcnt])) {
  284. if (clustnums[matchcnt]==-1) { 
  285. // prevcnt is first rectangle that matchcnt intersects with
  286. clustnums[matchcnt] = clustnums[prevcnt];
  287. } else {
  288. // prevcnt is not the first rectangle that matchcnt intersects with,
  289. // need to make sure that if prevcnt is from a different cluster
  290. // than the first one that we merge the two clusters
  291. if (clustnums[matchcnt]<clustnums[prevcnt]) {
  292. // need to merge cluster clustnums[prevcnt] int cluster clustnums[matchcnt]
  293. //int oldnum = clustnums[prevcnt];
  294. for (int patchcnt=0; patchcnt<matchcnt; patchcnt++) {
  295. if (clustnums[patchcnt]==clustnums[prevcnt]) {
  296. clustnums[patchcnt] = clustnums[matchcnt];
  297. }
  298. }
  299. /*
  300. if (oldnum!=num_clusters-1) {
  301. // we created a hole in the cluster numbering - fix it.
  302. for (int patchcnt=0; patchcnt<matchcnt; patchcnt++) {
  303. if (clustnums[patchcnt]>oldnum) {
  304. clustnums[patchcnt]--;
  305. }
  306. }
  307. }
  308. num_clusters--;
  309. */
  310. } else if (clustnums[prevcnt]<clustnums[matchcnt]) {
  311. // need to merge cluster clustnums[matchcnt] into cluster clustnums[prevcnt]
  312. //int oldnum = clustnums[matchcnt];
  313. for (int patchcnt=0; patchcnt<=matchcnt; patchcnt++) {
  314. if (clustnums[patchcnt]==clustnums[matchcnt]) {
  315. clustnums[patchcnt] = clustnums[prevcnt];
  316. }
  317. }
  318. /*
  319. if (oldnum!=num_clusters-1) {
  320. // we created a hole in the cluster numbering - fix it.
  321. for (int patchcnt=0; patchcnt<matchcnt; patchcnt++) {
  322. if (clustnums[patchcnt]>oldnum) {
  323. clustnums[patchcnt]--;
  324. }
  325. }
  326. }
  327. num_clusters--;
  328. */
  329. } else {
  330. // have the same cluster number already
  331. }
  332. }
  333. }
  334. }
  335. if (clustnums[matchcnt]==-1) {
  336. clustnums[matchcnt] = num_clusters;
  337. num_clusters++;
  338. }
  339. }
  340. // patch holes in cluster numbering
  341. CIntVector elements;
  342. elements.resize(num_clusters);
  343. for (int e=0; e<num_clusters; e++) elements[e] = 0;
  344. for (int mcnt=0; mcnt<num_matches; mcnt++) {
  345. elements[clustnums[mcnt]]++;
  346. }
  347. for (int ccnt=0; ccnt<num_clusters; ccnt++) {
  348. if (elements[ccnt]==0) {
  349. if (ccnt+1<num_clusters) {
  350. for (int mcnt=0; mcnt<num_matches; mcnt++) {
  351. if (clustnums[mcnt]>ccnt) {
  352. clustnums[mcnt]--;
  353. } else {
  354. ASSERT(clustnums[mcnt]!=ccnt);
  355. }
  356. }
  357. elements[ccnt] = elements[ccnt+1];
  358. ccnt--;
  359. }
  360. num_clusters--;
  361. }
  362. }
  363. // calculate mean for each corner of each cluster, do this in
  364. // a single pass over the match vector
  365. ASSERT(num_clusters>0);
  366. int seen_clustnum = 0;
  367. for (int mtchcnt=1; mtchcnt<num_matches; mtchcnt++) {
  368. int clustnum = clustnums[mtchcnt];
  369. if (clustnum<=seen_clustnum) {
  370. posClsfd[clustnum].left += posClsfd[mtchcnt].left;
  371. posClsfd[clustnum].top += posClsfd[mtchcnt].top;
  372. posClsfd[clustnum].right += posClsfd[mtchcnt].right;
  373. posClsfd[clustnum].bottom += posClsfd[mtchcnt].bottom;
  374. } else {
  375. // who knows what's in clustnum! put this one in
  376. posClsfd[clustnum].left = posClsfd[mtchcnt].left;
  377. posClsfd[clustnum].top = posClsfd[mtchcnt].top;
  378. posClsfd[clustnum].right = posClsfd[mtchcnt].right;
  379. posClsfd[clustnum].bottom = posClsfd[mtchcnt].bottom;
  380. seen_clustnum = clustnum;
  381. }
  382. }
  383. posClsfd.resize(num_clusters);
  384. for (int clustcnt=0; clustcnt<num_clusters; clustcnt++) {
  385. posClsfd[clustcnt].left /= elements[clustcnt];
  386. posClsfd[clustcnt].top /= elements[clustcnt];
  387. posClsfd[clustcnt].right /= elements[clustcnt];
  388. posClsfd[clustcnt].bottom /= elements[clustcnt];
  389. }
  390. }
  391. void CImageScanner::InitScaleParams(const CClassifierCascade& cascade,
  392.     CScaleParams& params) const
  393. {
  394.   ASSERT(m_start_scale>=1.0);
  395.   ASSERT(m_scale_inc_factor>1.0);
  396.   ASSERT(m_translation_inc_x>=1);
  397.   ASSERT(m_translation_inc_y>=1);
  398.   // run cascade for each large enough sub-image
  399.   params.template_width = cascade.GetTemplateWidth();
  400.   params.template_height = cascade.GetTemplateHeight();
  401.   double image_area_ratio = cascade.GetImageAreaRatio();
  402.   // depending on the size ratio of the image area to test, stretch template
  403.   // in height or width
  404.   double template_ratio = (double)params.template_width/(double)params.template_height;
  405.   if (image_area_ratio<template_ratio) { 
  406.     // image area is narrower than template, stretch template in height
  407.     params.scale_x = m_start_scale;
  408.     params.scale_y = m_start_scale*template_ratio/image_area_ratio;
  409.   } else { 
  410.     // stretch template width
  411.     params.scale_x = m_start_scale*image_area_ratio/template_ratio;
  412.     params.scale_y = m_start_scale;
  413.   }
  414.   ASSERT(params.scale_x>=1.0);
  415.   ASSERT(params.scale_y>=1.0);
  416.   params.base_scale = m_start_scale;
  417.   params.scaled_template_width = (int) (params.scale_x*params.template_width);
  418.   params.scaled_template_height = (int) (params.scale_y*params.template_height);
  419.   params.actual_scale_x = 
  420.     (double) params.scaled_template_width/(double)params.template_width;
  421.   params.actual_scale_y = 
  422.     (double) params.scaled_template_height/(double)params.template_height;
  423.   params.translation_inc_x = m_translation_inc_x;
  424.   params.translation_inc_y = m_translation_inc_y;
  425. }
  426. void CImageScanner::NextScaleParams(CScaleParams& params) const
  427. {
  428.   // floating point scaling
  429.   double old_actual_scale_x = params.actual_scale_x;
  430.   double old_actual_scale_y = params.actual_scale_y;
  431.   do {
  432.     params.scale_x *= m_scale_inc_factor;
  433.     params.scale_y *= m_scale_inc_factor;
  434.     params.base_scale *= m_scale_inc_factor;
  435.     params.translation_inc_x *= m_scale_inc_factor;
  436.     params.translation_inc_y *= m_scale_inc_factor;
  437.     params.scaled_template_width = (int) (params.scale_x*params.template_width);
  438.     params.scaled_template_height = (int) (params.scale_y*params.template_height);
  439.     params.actual_scale_x = 
  440.       (double) params.scaled_template_width/(double)params.template_width;
  441.     params.actual_scale_y = 
  442.       (double) params.scaled_template_height/(double)params.template_height;
  443.   } while (old_actual_scale_x==params.actual_scale_x 
  444.    || old_actual_scale_y==params.actual_scale_y);
  445. }
  446. ostream& operator<<(ostream& os, const CImageScanner& scanner)
  447. {
  448.   return scanner.output(os);
  449. }
  450. ostream& CImageScanner::output(ostream& os) const
  451. {
  452.   os << "start_scale " << m_start_scale
  453.     << ", stop_scale " << m_stop_scale
  454.     << ", scale_inc_factor " << m_scale_inc_factor
  455.     << ", inc_x " << m_translation_inc_x
  456.     << ", inc_y " << m_translation_inc_y << endl;
  457.   os << "area: left " << m_scan_area.left
  458.     << ", top " << m_scan_area.top
  459.     << ", right " << m_scan_area.right
  460.     << ", bottom " << m_scan_area.bottom << endl;
  461.   os << (m_is_active? "active" : "inactive") << endl;
  462.   return os;
  463. }