OpticalFlowPredict.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: OpticalFlowPredict.cpp,v 1.10 2005/08/16 00:09:55 matz Exp $
  22. **/
  23. #include "Common.h"
  24. #include "Skincolor.h"
  25. #include "OpticalFlow.h"
  26. #include "Exceptions.h"
  27. /** Initialize the Condensation data structure and state dynamics
  28. */
  29. void OpticalFlow::InitCondensation(int condens_num_samples)
  30. {
  31.   // initialize Condensation data structure and set the
  32.   // system dynamics
  33.   m_sample_confidences.resize(condens_num_samples);
  34.   if (m_pConDens) {
  35.     cvReleaseConDensation(&m_pConDens);
  36.   }
  37.   m_pConDens = cvCreateConDensation(OF_CONDENS_DIMS, OF_CONDENS_DIMS, condens_num_samples);
  38.   CvMat dyn = cvMat(OF_CONDENS_DIMS, OF_CONDENS_DIMS, CV_32FC1, m_pConDens->DynamMatr);
  39. //  CvMat dyn = cvMat(OF_CONDENS_DIMS, OF_CONDENS_DIMS, CV_MAT3x3_32F, m_pConDens->DynamMatr);
  40.   cvmSetIdentity(&dyn);
  41.   cvmSet(&dyn, 0, 1, 0.0);
  42.   cvmSet(&dyn, 2, 3, 0.0);
  43.   // initialize bounds for state
  44.   float lower_bound[OF_CONDENS_DIMS];
  45.   float upper_bound[OF_CONDENS_DIMS];
  46.   // velocity bounds highly depend on the frame rate that we will achieve,
  47.   // increase the factor for lower frame rates;
  48.   // it states how much the center can move in either direction in a single
  49.   // frame, measured in terms of the width or height of the initial match size
  50.   double velocity_factor = .25; 
  51.   double cx = (m_condens_init_rect.left+m_condens_init_rect.right)/2.0;
  52.   double cy = (m_condens_init_rect.top+m_condens_init_rect.bottom)/2.0;
  53.   double width = (m_condens_init_rect.right-m_condens_init_rect.left)*velocity_factor;
  54.   double height = (m_condens_init_rect.bottom-m_condens_init_rect.top)*velocity_factor;
  55.   lower_bound[0] = (float) (cx-width);
  56.   upper_bound[0] = (float) (cx+width);
  57.   lower_bound[1] = (float) (-width);
  58.   upper_bound[1] = (float) (+width);
  59.   lower_bound[2] = (float) (cy-height);
  60.   upper_bound[2] = (float) (cy+height);
  61.   lower_bound[3] = (float) (-height);
  62.   upper_bound[3] = (float) (+height);
  63.   lower_bound[4] = (float) (-10.0*velocity_factor*M_PI/180.0);
  64.   upper_bound[4] = (float) (+10.0*velocity_factor*M_PI/180.0);
  65.   CvMat lb = cvMat(OF_CONDENS_DIMS, 1, CV_MAT3x1_32F, lower_bound);
  66.   CvMat ub = cvMat(OF_CONDENS_DIMS, 1, CV_MAT3x1_32F, upper_bound);
  67.   cvConDensInitSampleSet(m_pConDens, &lb, &ub);
  68.   // set the state that will later be computed by condensation to
  69.   // the currently observed state
  70.   m_condens_state.x = cx;
  71.   m_condens_state.y = cy;
  72.   m_condens_state.vx = 0;
  73.   m_condens_state.vy = 0;
  74.   m_condens_state.angle = 0;
  75.   // debugging:
  76. //  DbgSetModuleLevel(LOG_CUSTOM1, 3);
  77. }
  78. void OpticalFlow::UpdateCondensation(IplImage* /*rgbImage*/,
  79.                                      int prev_indx, int curr_indx)
  80. {
  81.   //VERBOSE5(3, "m_condens_state x %f, y %f, vx %f, vy %f, a %f", 
  82.   //  m_condens_state.x, m_condens_state.y, m_condens_state.vx, m_condens_state.vy, m_condens_state.angle);
  83.   // for each condensation sample, predict the feature locations,
  84.   // compare to the observed KLT tracking, and check the probmask
  85.   // at each predicted location. The combination of these yields the
  86.   // confidence in this sample's estimate.
  87.   int num_ft = (int) m_features[prev_indx].size();
  88.   CPointVector predicted;
  89.   predicted.resize(num_ft);
  90.   CDoubleVector probs_locations;
  91.   CDoubleVector probs_colors;
  92.   probs_locations.reserve(m_pConDens->SamplesNum);
  93.   probs_colors.reserve(m_pConDens->SamplesNum);
  94.   double sum_probs_locations = 0.0;
  95.   double sum_probs_colors = 0.0;
  96.   CDoubleVector old_lens;
  97.   CDoubleVector old_d_angles;
  98.   // prepare data structures so that prediction based on centroid
  99.   // is fast
  100.   PreparePredictFeatureLocations(m_condens_state, m_features[prev_indx], old_lens, old_d_angles);
  101.   CvPoint2D32f avg_obs, avg_prev;
  102.   GetAverage(m_features[curr_indx], avg_prev);
  103. //  GetAverage(m_features[prev_indx], avg_prev);
  104.   GetAverage(m_features[curr_indx]/*_observation*/, avg_obs);
  105.   double dvx = avg_obs.x - avg_prev.x;
  106.   double dvy = avg_obs.y - avg_prev.y;
  107.   // for each sample
  108.   for (int scnt=0; scnt<m_pConDens->SamplesNum; scnt++) {
  109.     // hack - todo
  110.     if (scnt==m_pConDens->SamplesNum-1) {
  111.       m_pConDens->flSamples[scnt][0] = avg_obs.x;
  112.       m_pConDens->flSamples[scnt][2] = avg_obs.y;
  113.       m_pConDens->flSamples[scnt][1] = (float) dvx;
  114.       m_pConDens->flSamples[scnt][3] = (float) dvy;
  115.     }
  116.     // the Condensation sample's guess:
  117.     CondensState sample_state;
  118.     sample_state.x = m_pConDens->flSamples[scnt][0];
  119.     sample_state.y = m_pConDens->flSamples[scnt][2];
  120.     sample_state.vx = m_pConDens->flSamples[scnt][1];
  121.     sample_state.vy = m_pConDens->flSamples[scnt][3];
  122.     sample_state.angle = 0;//m_pConDens->flSamples[scnt][4];
  123.     ASSERT(!isnan(sample_state.x) && !isnan(sample_state.y) && !isnan(sample_state.angle));
  124.     
  125.     double fac = (m_condens_init_rect.right-m_condens_init_rect.left)/3.0;
  126.     double dx = avg_obs.x - sample_state.x;
  127.     double dy = avg_obs.y - sample_state.y;
  128.     double probloc = dx*dx+dy*dy;
  129.     probloc = fac/(fac+probloc);
  130.     probs_locations.push_back(probloc);
  131.     sum_probs_locations += probloc;
  132. #if 0
  133.     PredictFeatureLocations(old_lens, old_d_angles, sample_state, predicted);
  134.     // probability of predicted feature locations given the KLT observation
  135.     int discard_num_distances = (int)(0.15*(double)num_ft);
  136.     double probloc = EstimateProbability(predicted, m_features[curr_indx]/*_observation*/, discard_num_distances);
  137.     probs_locations.push_back(probloc);
  138.     sum_probs_locations += probloc;
  139.     // probability of predicted feature locations given the outside probability map (color)
  140.     double probcol = EstimateProbability(predicted, rgbImage);
  141.     probs_colors.push_back(probcol);
  142.     sum_probs_colors += probcol;
  143. #endif
  144.   } // end for each sample
  145. //  ASSERT(!isnan(sum_probs_locations) && sum_probs_locations>0);
  146.   //
  147.   // normalize the individual probabilities and set sample confidence
  148.   //
  149.   int best_sample_indx = -1;
  150.   double best_confidence = 0;
  151.   for (int scnt=0; scnt<m_pConDens->SamplesNum; scnt++) {
  152.     double norm_prob_locations = probs_locations[scnt]/sum_probs_locations;
  153. //    double norm_prob_colors    = probs_colors[scnt]/sum_probs_colors;
  154.     double confidence;
  155.     if (sum_probs_colors>0) {
  156.  //     confidence = norm_prob_locations*norm_prob_colors;
  157.       confidence = norm_prob_locations;
  158.     } else {
  159.       confidence = norm_prob_locations;
  160.     }
  161.     m_pConDens->flConfidence[scnt] = (float) confidence;
  162.     m_sample_confidences[scnt] = confidence;
  163.     if (confidence>best_confidence) {
  164.       best_confidence = confidence;
  165.       best_sample_indx = scnt;
  166.     }
  167.   }
  168. //  for (int scnt=0; scnt<m_pConDens->SamplesNum; scnt++) {
  169. //    VERBOSE2(3, "%d: %f ", scnt, m_sample_confidences[scnt]);
  170. //  }
  171.   ASSERT(best_sample_indx!=-1);
  172.   ASSERT(best_sample_indx==m_pConDens->SamplesNum-1);
  173.  
  174.   CondensState best_sample_state;
  175.   best_sample_state.x = m_pConDens->flSamples[best_sample_indx][0];
  176.   best_sample_state.y = m_pConDens->flSamples[best_sample_indx][2];
  177.   best_sample_state.vx = m_pConDens->flSamples[best_sample_indx][1];
  178.   best_sample_state.vy = m_pConDens->flSamples[best_sample_indx][3];
  179.   best_sample_state.angle = m_pConDens->flSamples[best_sample_indx][4];
  180.   //VERBOSE3(3, "sample_state %f, %f, %f", 
  181.   // sample_state.x, sample_state.y, sample_state.angle);
  182.   //    VERBOSE4(3, "sample_state %f, %f, %f, %f"), 
  183.   //      sample_state.x, sample_state.y, sample_state.vx, sample_state.vy);
  184.   ASSERT(!isnan(best_sample_state.x) && !isnan(best_sample_state.y) && !isnan(best_sample_state.angle));
  185.   // probability of predicted feature locations given the KLT observation
  186.   m_tmp_predicted.resize(m_features[0].size());
  187.   PredictFeatureLocations(old_lens, old_d_angles, best_sample_state, m_tmp_predicted);
  188.   //
  189.   // do one condensation step, then get the state prediction from Condensation;
  190.   //
  191.   cvConDensUpdateByTime(m_pConDens);
  192. #if 0
  193.   if (false) { // todo
  194.     m_condens_state.x = max(0, min(rgbImage->width-1, m_pConDens->State[0]));
  195.     m_condens_state.y = max(0, min(rgbImage->height-1, m_pConDens->State[2]));
  196.     m_condens_state.vx = m_pConDens->State[1];
  197.     m_condens_state.vy = m_pConDens->State[3];
  198.     m_condens_state.angle = m_pConDens->State[4];
  199.   } else 
  200. #endif
  201.   {
  202.     m_condens_state.x = best_sample_state.x;
  203.     m_condens_state.y = best_sample_state.y;
  204.     m_condens_state.vx = best_sample_state.vx;
  205.     m_condens_state.vy = best_sample_state.vy ;
  206.     m_condens_state.angle = best_sample_state.angle;
  207.   }
  208.   ASSERT(!isnan(m_condens_state.x) && !isnan(m_condens_state.y) && !isnan(m_condens_state.angle));
  209.   ASSERT(!isnan(m_condens_state.vx) && !isnan(m_condens_state.vy));
  210.   // now move the current features to where Condensation thinks they should be;
  211.   // the observation is no longer needed
  212. #if 0
  213.   if (false) { // todo
  214.     PredictFeatureLocations(old_lens, old_d_angles, m_condens_state, m_tmp_predicted);
  215.     FollowObservationForSmallDiffs(m_tmp_predicted, m_features[curr_indx]/*observation*/, 
  216.                                   m_features[curr_indx]/*output*/, 2.0);
  217.   } else 
  218. #endif
  219.   {
  220.     PredictFeatureLocations(old_lens, old_d_angles, m_condens_state, m_features[curr_indx]);
  221.   }
  222.   {
  223.     // initialize bounds for state
  224.     float lower_bound[OF_CONDENS_DIMS];
  225.     float upper_bound[OF_CONDENS_DIMS];
  226.     // velocity bounds highly depend on the frame rate that we will achieve,
  227.     // increase the factor for lower frame rates;
  228.     // it states how much the center can move in either direction in a single
  229.     // frame, measured in terms of the width or height of the initial match size
  230.     double velocity_factor = .25; 
  231.     CvPoint2D32f avg;
  232.     GetAverage(m_features[curr_indx]/*_observation*/, avg);
  233.     double cx = avg.x;
  234.     double cy = avg.y;
  235.     double width = (m_condens_init_rect.right-m_condens_init_rect.left)*velocity_factor;
  236.     double height = (m_condens_init_rect.bottom-m_condens_init_rect.top)*velocity_factor;
  237.     lower_bound[0] = (float) (cx-width);
  238.     upper_bound[0] = (float) (cx+width);
  239.     lower_bound[1] = (float) (-width);
  240.     upper_bound[1] = (float) (+width);
  241.     lower_bound[2] = (float) (cy-height);
  242.     upper_bound[2] = (float) (cy+height);
  243.     lower_bound[3] = (float) (-height);
  244.     upper_bound[3] = (float) (+height);
  245.     lower_bound[4] = (float) (-10.0*velocity_factor*M_PI/180.0);
  246.     upper_bound[4] = (float) (+10.0*velocity_factor*M_PI/180.0);
  247.     CvMat lb = cvMat(OF_CONDENS_DIMS, 1, CV_MAT3x1_32F, lower_bound);
  248.     CvMat ub = cvMat(OF_CONDENS_DIMS, 1, CV_MAT3x1_32F, upper_bound);
  249.     cvConDensInitSampleSet(m_pConDens, &lb, &ub);
  250.   }
  251. }
  252. /** if the distance between the predicted ("pred") and the observed feature
  253. * location is smaller than diff, use the observation as "corrected" feature,
  254. * otherwise use the "pred" location
  255. */
  256. void OpticalFlow::FollowObservationForSmallDiffs(const CPointVector& pred, 
  257.                                                  const CPointVector& obs, 
  258.                                                  CPointVector& corrected,
  259.                                                  double diff)
  260. {
  261.   int num_ft = (int) obs.size();
  262.   ASSERT(num_ft);
  263.   ASSERT((int)pred.size()==num_ft);
  264.   ASSERT((int)corrected.size()==num_ft);
  265.   for (int ft=0; ft<num_ft; ft++) {
  266.     double dx = pred[ft].x-obs[ft].x;
  267.     double dy = pred[ft].y-obs[ft].y;
  268.     double len = sqrt(dx*dx+dy*dy);
  269.     if (len<diff) {
  270.       corrected[ft].x = obs[ft].x;
  271.       corrected[ft].y = obs[ft].y;
  272.     } else {
  273.       corrected[ft].x = pred[ft].x;
  274.       corrected[ft].y = pred[ft].y;
  275.     }
  276.   }
  277. }
  278. /* compute and store the relative location of each feature versus
  279. * the base_state; save it as distance and angle from base_state
  280. */
  281. void OpticalFlow::PreparePredictFeatureLocations(const CondensState& base_state,
  282.                                                  const CPointVector& base,
  283.                                                  CDoubleVector& old_lens,
  284.                                                  CDoubleVector& old_d_angles)
  285. {
  286.   int num_ft = (int) base.size();
  287.   ASSERT(num_ft);
  288.   old_lens.reserve(num_ft);
  289.   old_d_angles.reserve(num_ft);
  290.   for (int ft=0; ft<num_ft; ft++) {
  291.     double old_dx = base[ft].x-base_state.x;
  292.     double old_dy = base[ft].y-base_state.y;
  293.     double old_len = sqrt(old_dx*old_dx+old_dy*old_dy);
  294.     double old_angle = atan(old_dy/old_dx);
  295.     if (old_dx<0) old_angle += M_PI;
  296.     double old_d_angle = old_angle-base_state.angle;
  297.     old_lens.push_back(old_len);
  298.     old_d_angles.push_back(old_d_angle);
  299.   }
  300. }
  301. /** given a (predicted) state, where do the features end up?
  302. * This requires that PreparePredict.. has been called before
  303. * to obtain an intermediate feature representation that is free
  304. * of the the old state.
  305. */
  306. void OpticalFlow::PredictFeatureLocations(const CDoubleVector& old_lens,
  307.                                           const CDoubleVector& old_d_angles,
  308.                                           const CondensState& predicted_state,
  309.                                           CPointVector& prediction)
  310. {
  311.   int num_ft = (int)prediction.size();
  312.   ASSERT((int)old_lens.size()==num_ft);
  313.   ASSERT((int)old_d_angles.size()==num_ft);
  314.   for (int ft=0; ft<num_ft; ft++) {
  315.     double old_d_angle = old_d_angles[ft];
  316.     double new_angle = predicted_state.angle+old_d_angle;
  317.     double old_len = old_lens[ft];
  318.     double new_dx = old_len*cos(new_angle);
  319.     double new_dy = old_len*sin(new_angle);
  320.     prediction[ft].x = (float) (predicted_state.x+new_dx);
  321.     prediction[ft].y = (float) (predicted_state.y+new_dy);
  322. //    VERBOSE2(3, "predicted %f, %f", 
  323. //      prediction[ft].x, prediction[ft].y);
  324.   }
  325. }
  326. /* estimate the likelihood that the given prediction is correct,
  327. * given the observation and discarding the furthest-away features
  328. */
  329. double OpticalFlow::EstimateProbability(const CPointVector& prediction, 
  330.                                         const CPointVector& observation,
  331.                                         int discard_num_furthest)
  332. {
  333.   int num_ft = (int) prediction.size();
  334.   ASSERT((int)observation.size()==num_ft);
  335.   ASSERT(num_ft>discard_num_furthest);
  336.   vector<double> furthest; // will be sorted highest to smallest
  337.   furthest.resize(discard_num_furthest);
  338.   double cum_dist = 0.0;
  339.   for (int ft=0; ft<num_ft; ft++) {
  340.     double dx = prediction[ft].x-observation[ft].x;
  341.     double dy = prediction[ft].y-observation[ft].y;
  342.     double dist = sqrt(dx*dx+dy*dy);
  343.     // check if it's a far-away feature, update "furthest" vector if so.
  344.     // only add the distance if it's not too far away
  345.     for (int f=0; f<discard_num_furthest; f++) {
  346.       if (dist>furthest[f]) {
  347.         // add smallest "furthest" dist to the sum before we kick it out
  348.         // of the vector
  349.         cum_dist += furthest[discard_num_furthest-1];
  350.         for (int s=f; s<discard_num_furthest-1; s++) {
  351.           furthest[s+1] = furthest[s];
  352.         }
  353.         furthest[f] = dist;
  354.         break;
  355.       }
  356.     }
  357.     cum_dist += dist;
  358.   }
  359.   double prob = 1.0/(1.0+cum_dist);
  360.   return prob;
  361. }
  362. /** given the locations of features for a predicted state,
  363. * do they fall on skin-colored pixels?
  364. */
  365. double OpticalFlow::EstimateProbability(const CPointVector& prediction,
  366.                                         IplImage* rgbImage)
  367. {
  368.   int num_ft = (int) prediction.size();
  369.   ASSERT(num_ft);
  370.   int max_x = rgbImage->width-1;
  371.   int max_y = rgbImage->height-1;
  372.   double prob = 0;
  373.   for (int ft=0; ft<num_ft; ft++) {
  374.     int x = (int) prediction[ft].x;
  375.     int y = (int) prediction[ft].y;
  376.     x = max(0, min(x, max_x));
  377.     y = max(0, min(y, max_y));
  378.     ColorBGR* color;
  379.     GetPixel(rgbImage, x, y, &color);
  380.     double p = m_pProbDistrProvider->LookupProb(*color);
  381.     prob += p;
  382.   }
  383.   prob = prob/(double)num_ft;
  384.   return prob;
  385. }