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

视频捕捉/采集

开发平台:

MultiPlatform

  1. /**
  2.   * HandVu - a library for computer vision-based hand gesture
  3.   * recognition.
  4.   * Copyright (C) 2004 Mathias Kolsch, matz@cs.ucsb.edu
  5.   *
  6.   * This program is free software; you can redistribute it and/or
  7.   * modify it under the terms of the GNU General Public License
  8.   * as published by the Free Software Foundation; either version 2
  9.   * of the License, or (at your option) any later version.
  10.   *
  11.   * This program is distributed in the hope that it will be useful,
  12.   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.   * GNU General Public License for more details.
  15.   *
  16.   * You should have received a copy of the GNU General Public License
  17.   * along with this program; if not, write to the Free Software
  18.   * Foundation, Inc., 59 Temple Place - Suite 330, 
  19.   * Boston, MA  02111-1307, USA.
  20.   *
  21.   * $Id: VisionConductor.cpp,v 1.23 2005/11/03 23:44:10 matz Exp $
  22. **/
  23. #include "Common.h"
  24. #include "VisionConductor.h"
  25. #include "FileHandling.h"
  26. #include <fstream>
  27. #ifdef HAVE_FLOAT_H
  28. #include <float.h>
  29. #endif
  30. #ifdef USE_MFC
  31. #ifdef _DEBUG
  32. #define new DEBUG_NEW
  33. #undef THIS_FILE
  34. static char THIS_FILE[] = __FILE__;
  35. #endif // _DEBUG
  36. #endif // USE_MFC
  37. #ifdef WIN32
  38. #if defined(GetMessage)
  39. #undef GetMessage
  40. #endif
  41. #else // WIN32
  42. // otherwise declared in Common.h
  43. void ReplaceAll(string& mangle, const string what, const string with);
  44. #endif //WIN32
  45. /////////////////////////////////////////////////////////////////////////////
  46. // VisionConductor
  47. VisionConductor::VisionConductor()
  48.   : m_is_loaded(false),
  49.     m_camera_calib(""),
  50.     m_adjust_exposure(false),
  51.   
  52.     // detection:
  53.     m_dt_radius(-1),
  54.     m_dt_cascades_start(-1),
  55.     m_dt_cascades_end(-1),
  56.     m_dt_min_match_duration(-1),
  57.     m_dt_min_color_coverage(-1),
  58.     
  59.     // tracking
  60.     m_tr_num_KLT_features(-1),
  61.     m_tr_min_KLT_features(-1),
  62.     m_tr_cascades_start(-1),
  63.     m_tr_cascades_end(-1),
  64.     m_tr_winsize_width(-1),
  65.     m_tr_winsize_height(-1),
  66.     m_tr_min_feature_distance(-1),
  67.     m_tr_type(VC_TT_UNDEF),
  68.     // recognition
  69.     m_rc_cascades_start(-1),
  70.     m_rc_cascades_end(-1),
  71.     m_rc_max_scan_width(-1),
  72.     m_rc_max_scan_height(-1),
  73.     m_rc_scale_tolerance(-1)
  74. {
  75. }
  76. VisionConductor::~VisionConductor()
  77. {
  78. }
  79. void VisionConductor::Load(string pathfile)
  80. {
  81.   // $IT_DATA environmet variable, NULL if not set
  82.   const char *it_data = getenv("IT_DATA");
  83.   string std_it_data;
  84.   if (it_data!=NULL) {
  85.     std_it_data = ConvertPathToStandard(it_data);
  86.   } else {
  87.     std_it_data = "";
  88.   }
  89.   // substitute $IT_DATA environment variable, if requested
  90.   string::size_type pos = pathfile.find("$IT_DATA");
  91.   if (pos!=string::npos) {
  92.     if (it_data==NULL) {
  93.       throw HVEFile(pathfile, "The filename requests the environment variable "
  94.         "$IT_DATA to be set.");
  95.     }
  96.     // substitute "$IT_DATA" for the value of that environment variable
  97.     ReplaceAll(pathfile, "$IT_DATA", std_it_data);
  98.   }
  99.   // all paths in the VisionConductor file "filename" are relative
  100.   // to the path of "filename".  so, let's cd to that directory, load
  101.   // all cascades etc., and in the end restore the previous cwd.
  102.   string old_cwd = GetCWD();
  103.   string vc_path, fname;
  104.   SplitPathFile(pathfile, vc_path, fname);
  105.   VERBOSE1(5, "HandVu: loading supplemental conductor files from path %s",
  106.     vc_path.c_str());
  107.   if (old_cwd!=vc_path) {
  108.     SetCWD(vc_path);
  109.   }
  110.   m_masks.clear();
  111.   m_orig_areas.clear();
  112.   try {
  113.     // the actual parsing function
  114.     ParseFromFile(fname);
  115.   } catch (HVException& hve) {
  116.     if (old_cwd!=vc_path) {
  117.       SetCWD(old_cwd);
  118.     }
  119.     throw HVException(hve.GetMessage() + "n" +
  120.       "note: paths in VisionConductor files are relative;n"
  121.       "in this case to " + vc_path);
  122.   }
  123.   if (old_cwd!=vc_path) {
  124.     SetCWD(old_cwd);
  125.   }
  126.   SanityCheckMasks();
  127.   m_is_loaded = true;
  128. }
  129. /** parsing function; do not call directly but 
  130. * call "Load" instead
  131. */
  132. void VisionConductor::ParseFromFile(const string& filename)
  133. {
  134.   ifstream file(filename.c_str());
  135.   if (!file) {
  136.     throw HVEFileNotFound(filename);
  137.   }
  138.   // $IT_DATA environmet variable, NULL if not set
  139.   const char *it_data = getenv("IT_DATA");
  140.   string std_it_data;
  141.   if (it_data!=NULL) {
  142.     std_it_data = ConvertPathToStandard(it_data);
  143.   } else {
  144.     std_it_data = "";
  145.   }
  146.   string line;
  147.   do {
  148.     getline(file, line);
  149.   } while (line=="" || line[0]=='#');
  150.   if (line==HV_CONDUCTOR_VERSION_1_5_STRING) {
  151.   // version 1.5
  152.     do {
  153.       getline(file, line);
  154.     } while (line=="" || line[0]=='#');
  155.     {
  156.       char* buf = new char[line.length()];
  157.       int scanned = sscanf(line.c_str(), "camera calibration: %s", buf);
  158.       if (scanned!=1) {
  159.         throw HVEFile(filename, string("expected camera calibration file, found: ")+line);
  160.       }  
  161.       m_camera_calib = string(buf);
  162.       delete[] buf;
  163.       // substitute $IT_DATA environment variable, if requested
  164.       string::size_type pos = m_camera_calib.find("$IT_DATA");
  165.       if (pos!=string::npos) {
  166.         if (it_data==NULL) {
  167.           throw HVEFile(filename, "The file requests the environment variable "
  168.             "$IT_DATA to be set.");
  169.         }
  170.         // substitute "$IT_DATA" for the value of that environment variable
  171.         ReplaceAll(m_camera_calib, "$IT_DATA", std_it_data);
  172.       }
  173.       if (m_camera_calib!="-") {
  174.         FILE* fp = fopen(m_camera_calib.c_str(), "rb");
  175.         if (!fp) {
  176.           throw HVEFile(filename, string("can not find file: ")+m_camera_calib);
  177.         }
  178.       } else {
  179.         m_camera_calib = "";
  180.       }
  181.     }
  182.     // what sort of camera exposure control is desired
  183.     do {
  184.       getline(file, line);
  185.     } while (line=="" || line[0]=='#');
  186.     {
  187.       char* buf = new char[line.length()];
  188.       int scanned = sscanf(line.c_str(), "camera exposure: %s", buf);
  189.       if (scanned!=1) {
  190.         throw HVEFile(filename, string("expected camera exposure control setting, found: ")+line);
  191.       }
  192.       if (strcmp(buf, "camera")==0) {
  193.         m_adjust_exposure = false;
  194.       } else if (strcmp(buf, "software")==0) {
  195.         m_adjust_exposure = true;
  196.       } else {
  197.         throw HVEFile(filename, string("expected camera exposure control setting ("camera" or "software"), found: ")+line);
  198.       }
  199.       delete[] buf;
  200.     }
  201.     // detection parameters
  202.     do {
  203.       getline(file, line);
  204.     } while (line=="" || line[0]=='#');
  205.     float coverage;
  206.     float radius;
  207.     int scanned = sscanf(line.c_str(), "detection params: coverage %f, duration %d, radius %f",
  208.       &coverage, &m_dt_min_match_duration, &radius);
  209.     if (scanned!=3) {
  210.       throw HVEFile(filename, string("expected detection params, found: ")+line);
  211.     }  
  212.     m_dt_min_color_coverage = coverage;
  213.     if (radius>1) {
  214.       HVEFile(filename, "radius must be width-relative");
  215.     }
  216.     m_dt_radius = radius;
  217.     // tracking parameters
  218.     do {
  219.       getline(file, line);
  220.     } while (line=="" || line[0]=='#');
  221.     float min_dist;
  222.     float max_err;
  223.     scanned = sscanf(line.c_str(), "tracking params: num_f %d, min_f %d, win_w %d, win_h %d, min_dist %f, max_err %f",
  224.       &m_tr_num_KLT_features, &m_tr_min_KLT_features, &m_tr_winsize_width, &m_tr_winsize_height, &min_dist, &max_err);
  225.     if (scanned!=6) {
  226.       throw HVEFile(filename, string("expected tracking params, found: ")+line);
  227.     }  
  228.     m_tr_min_feature_distance = min_dist;
  229.     if (max_err<=0) {
  230.       m_tr_max_feature_error = DBL_MAX;  // DBL_MAX switches this off
  231.     } else {
  232.       m_tr_max_feature_error = max_err;
  233.     }
  234.     // tracking style
  235.     do {
  236.       getline(file, line);
  237.     } while (line=="" || line[0]=='#');
  238.     string::size_type pos = line.find("tracking style: ");
  239.     if (pos==string::npos) {
  240.       throw HVEFile(filename, string("expected tracking style, found: ")+line);
  241.     }
  242.     string style = line.substr(strlen("tracking style: "));
  243.     if (style=="OPTICAL_FLOW_ONLY") {
  244.       m_tr_type = VC_TT_OPTICAL_FLOW_ONLY;
  245.     } else if (style=="OPTICAL_FLOW_COLOR") {
  246.       m_tr_type = VC_TT_OPTICAL_FLOW_COLOR;
  247.     } else if (style=="OPTICAL_FLOW_FLOCK") {
  248.       m_tr_type = VC_TT_OPTICAL_FLOW_FLOCK;
  249.     } else if (style=="OPTICAL_FLOW_COLORFLOCK") {
  250.       m_tr_type = VC_TT_OPTICAL_FLOW_COLORFLOCK;
  251.     } else if (style=="CAMSHIFT_HSV") {
  252.       m_tr_type = VC_TT_CAMSHIFT_HSV;
  253.     } else if (style=="CAMSHIFT_LEARNED") {
  254.       m_tr_type = VC_TT_CAMSHIFT_LEARNED;
  255.     } else {
  256.       throw HVEFile(filename, string("wrong tracking style: ")+style);
  257.     }
  258.     // recognition params
  259.     do {
  260.       getline(file, line);
  261.     } while (line=="" || line[0]=='#');
  262.     float max_scan_width;
  263.     float max_scan_height;
  264.     scanned = sscanf(line.c_str(), "recognition params: max_scan_width %f, max_scan_height %f",
  265.       &max_scan_width, &max_scan_height);
  266.     if (scanned!=2) {
  267.       throw HVEFile(filename, string("expected recognition params, found: ")+line);
  268.     }  
  269.     m_rc_max_scan_width = max_scan_width;
  270.     m_rc_max_scan_height = max_scan_height;
  271.     m_rc_scale_tolerance = 1.75;  // magic!
  272.     int num;
  273.     // detection cascades
  274.     m_dt_cascades_start = 0;
  275.     num = ReadScannerData(file, filename, "detection");
  276.     m_dt_cascades_end = m_dt_cascades_start+num;
  277.     // tracking cascades
  278.     m_tr_cascades_start = m_dt_cascades_end;
  279.     num = ReadScannerData(file, filename, "tracking");
  280.     m_tr_cascades_end = m_tr_cascades_start+num;
  281.     
  282.     // recognition cascades
  283.     m_rc_cascades_start = m_tr_cascades_end;
  284.     num = ReadScannerData(file, filename, "recognition");
  285.     m_rc_cascades_end = m_rc_cascades_start+num;
  286.     //
  287.     // load masks
  288.     //
  289.     do {
  290.       getline(file, line);
  291.     } while (line=="" || line[0]=='#');
  292.     scanned = sscanf(line.c_str(), "%d masks", &num);
  293.     if (scanned!=1) {
  294.       throw HVEFile(filename, string("expected number of masks, found: ")+line);
  295.     }
  296.     for (int mcnt=0; mcnt<num; mcnt++) {
  297.       Mask mask;
  298.       string mask_filename;
  299.       do {
  300.         getline(file, mask_filename);
  301.       } while (mask_filename=="" || mask_filename[0]=='#');
  302.       // substitute $IT_DATA environment variable, if requested
  303.       string::size_type pos = mask_filename.find("$IT_DATA");
  304.       if (pos!=string::npos) {
  305.         if (it_data==NULL) {
  306.           throw HVEFile(filename, "The file requests the environment variable "
  307.             "$IT_DATA to be set.");
  308.         }
  309.         // substitute "$IT_DATA" for the value of that environment variable
  310.         ReplaceAll(mask_filename, "$IT_DATA", std_it_data);
  311.       }
  312.       mask.ParseFrom(ConvertPathToWindows(mask_filename).c_str());
  313.       if (m_masks.find(mask.GetName())!=m_masks.end()) {
  314.         throw HVException(string("mask '")+mask.GetName()+string("' exists already!"));
  315.       }
  316.       m_masks[mask.GetName()] = mask;
  317.     }
  318.   } else {
  319.     throw HVEFile(filename, string("Unknown or no conductor file version: ")+line);
  320.   }
  321. }
  322. void VisionConductor::SanityCheckMasks()
  323. {
  324.   for (int cc=0; cc<m_rc_cascades_end; cc++) {
  325.     CuCascadeProperties cp;
  326.     CuCascadeID id = (CuCascadeID) cc;
  327.     cuGetCascadeProperties(id, cp);
  328.     for (int nm=0; nm<(int)cp.names.size(); nm++) {
  329.       if (m_masks.find(cp.names[nm])==m_masks.end()) {
  330.         throw HVException(string("no mask for cascade '")+cp.names[nm]+string("'."));
  331.       }
  332.       ConstMaskIt mask = m_masks.find(cp.names[nm]);
  333.       if ((*mask).second.GetWidth()!=cp.template_width
  334.           || (*mask).second.GetHeight()!=cp.template_height)
  335.       {
  336.         throw HVException(string("mask size does not match cascade size ('")
  337.                           + cp.names[nm] + string("')."));
  338.       }
  339.       double m = (*mask).second.GetImageAreaRatio();
  340.       double c = cp.image_area_ratio;
  341.       if (fabs(m-c)>0.00001)
  342.       {
  343.         throw HVException(string("mask ratio does not match cascade ratio ('")
  344.                           + cp.names[nm]+string("')."));
  345.       }
  346.     }
  347.   }
  348. }
  349. /* reads file names C and M and settings from the file, then
  350. * loads cascade and mask from the file corresponding to C and M;
  351. * adds the results to m_cascades and m_masks
  352. */
  353. int VisionConductor::ReadScannerData(ifstream& file, const string filename, const string type) 
  354. {
  355.   // $IT_DATA environmet variable, NULL if not set
  356.   const char *it_data = getenv("IT_DATA");
  357.   string std_it_data;
  358.   if (it_data!=NULL) {
  359.     std_it_data = ConvertPathToStandard(it_data);
  360.   } else {
  361.     std_it_data = "";
  362.   }
  363.   string line;
  364.   do {
  365.     getline(file, line);
  366.   } while (line=="" || line[0]=='#');
  367.   int num;
  368.   int scanned = sscanf(line.c_str(), (string("%d")
  369.                                       +type+string(" cascades")).c_str(), &num);
  370.   if (scanned!=1) {
  371.     throw HVEFile(filename, string("expected number of ")
  372.                   +type+string(" cascades, found: ")+line);
  373.   }
  374.   for (int cs=0; cs<num; cs++) {
  375.     CuCascadeID cascadeID;
  376.     //
  377.     // load cascade
  378.     //
  379.     {
  380.       string cascade_filename;
  381.       do {
  382.         getline(file, cascade_filename);
  383.       } while (cascade_filename=="" || cascade_filename[0]=='#');
  384.       // substitute $IT_DATA environment variable, if requested
  385.       string::size_type pos = cascade_filename.find("$IT_DATA");
  386.       if (pos!=string::npos) {
  387.         if (it_data==NULL) {
  388.           throw HVEFile(filename, "The file requests the environment variable "
  389.             "$IT_DATA to be set.");
  390.         }
  391.         // substitute "$IT_DATA" for the value of that environment variable
  392.         ReplaceAll(cascade_filename, "$IT_DATA", std_it_data);
  393.       }
  394.       cuLoadCascade(ConvertPathToWindows(cascade_filename).c_str(), &cascadeID);
  395.     }
  396.     //
  397.     // read configuration of scanners
  398.     //
  399.     {
  400.       float left, top, right, bottom;
  401.       do {
  402.         getline(file, line);
  403.       } while (line=="" || line[0]=='#');
  404.       scanned = 
  405.         sscanf(line.c_str(), "area: left %f, top %f, right %f, bottom %f", 
  406.         &left, &top, &right, &bottom);
  407.       if (scanned!=4) {
  408.         throw HVEFile(filename, string("expected area, found: ")+line);
  409.       }
  410.       if (!(0<=left && left<=1) || !(0<=top && top<=1)
  411.           || !(0<=right && right<=1) || !(0<=bottom && bottom<=1)) 
  412.       {
  413.         throw HVEFile(filename, "areas must have relative coordinates");
  414.       }
  415.       do {
  416.         getline(file, line);
  417.       } while (line=="" || line[0]=='#');
  418.       float start_scale, stop_scale, scale_inc_factor;
  419.       scanned = sscanf(line.c_str(), 
  420.         "params scaling: start %f, stop %f, inc_factor %f",
  421.         &start_scale, &stop_scale, &scale_inc_factor);
  422.       if (scanned!=3) {
  423.         throw HVEFile(filename, string("expected params, found: ")+line);
  424.       }
  425.       float translation_inc_x, translation_inc_y;
  426.       do {
  427.         getline(file, line);
  428.       } while (line=="" || line[0]=='#');
  429.       int post_process;
  430.       scanned = sscanf(line.c_str(), 
  431.         "params misc: translation_inc_x %f, translation_inc_y %f, post_process %d",
  432.         &translation_inc_x, &translation_inc_y, &post_process);
  433.       if (scanned!=3) {
  434.         throw HVEFile(filename, string("expected params, found: ")+line);
  435.       } 
  436.       CQuadruple orig_area(left, top, right, bottom);
  437.       m_orig_areas.push_back(orig_area);
  438.       CuScannerParameters sp;
  439.       sp.active = false;
  440.       sp.left = sp.top = sp.right = sp.bottom = -1;
  441.       sp.start_scale = start_scale;
  442.       sp.stop_scale = stop_scale;
  443.       sp.scale_inc_factor = scale_inc_factor;
  444.       sp.translation_inc_x = translation_inc_x;
  445.       sp.translation_inc_y = translation_inc_y;
  446.       sp.post_process = (post_process==1);
  447.       cuSetScannerParameters(cascadeID, sp);
  448.     }
  449.   }
  450.   return num;
  451. }
  452. bool VisionConductor::IsLoaded() const
  453. {
  454.   return m_is_loaded;
  455. }
  456. #pragma warning (disable:4786)
  457. ConstMaskIt VisionConductor::GetMask(const string& name) const
  458. {
  459.   ConstMaskIt it = m_masks.find(name);
  460.   if (it==m_masks.end()) {
  461.     throw HVException(string("no mask for name ")+name);
  462.   }
  463.   return it;
  464. }
  465. #pragma warning (default:4786)
  466. CRect CQuadruple::toRect(double scale_x, double scale_y) const
  467. {
  468.   return CRect((int)(left*scale_x), 
  469.                (int)(top*scale_y),
  470.                (int)(right*scale_x),
  471.                (int)(bottom*scale_y));
  472. }
  473. void CQuadruple::fromRect(const CRect& rect, double scale_x, double scale_y) 
  474. {
  475.   left = (double)rect.left/scale_x;
  476.   top = (double)rect.top/scale_y;
  477.   right = (double)rect.right/scale_x;
  478.   bottom = (double)rect.bottom/scale_y;
  479. }