KINECT STATS GENERATOR FOR SPORTS VISUALISATION  1.0
BallPointsProcessing.cpp
Go to the documentation of this file.
00001 #include "BallPointsProcessing.h"
00002 #include <QMessageBox>
00003 /*
00004   LICENSING: You are free to use any part of this project provided I am informed about it via email
00005   at santoshwins@hotmail.com and referenced appropriately in your works
00006   */
00007 
00008 BallPointsProcessing::BallPointsProcessing()
00009 {
00010     m_entireTrackedDataPts.clear();
00011     m_playerAPts.clear();
00012     m_playerBPts.clear();
00013     m_playerADeepestPtIndices.clear();
00014     m_playerBDeepestPtIndices.clear();
00015 
00016     m_ballImpactDepthMaxThresh = 0.70; // to be decided after measuring with tape
00017     m_ballImpactDepthMinThresh = 0.60;
00018 
00019 }
00020 
00021 BallPointsProcessing::BallPointsProcessing(PlayerData *_playerA,PlayerData *_playerB):m_playerA(_playerA),m_playerB(_playerB)
00022 {
00023     m_entireTrackedDataPts.clear();
00024     m_playerAPts.clear();
00025     m_playerBPts.clear();
00026     m_playerADeepestPtIndices.clear();
00027     m_playerBDeepestPtIndices.clear();
00028 
00029     m_ballImpactDepthMaxThresh = 0.70; // to be decided after measuring with tape
00030     m_ballImpactDepthMinThresh = 0.60;
00031 
00032 }
00033 
00034 BallPointsProcessing::~BallPointsProcessing()
00035 {
00036     m_entireTrackedDataPts.clear();
00037     m_playerAPts.clear();
00038     m_playerBPts.clear();
00039     m_playerADeepestPtIndices.clear();
00040     m_playerBDeepestPtIndices.clear();
00041 }
00042 
00043 // pushes each tracked point into vector for later processing
00044 void BallPointsProcessing::setTrackedPoints(cv::Point3f _inputTrackedPoint)
00045 {
00046     m_entireTrackedDataPts.push_back(_inputTrackedPoint);
00047 }
00048 
00049 
00050 //when GENERATE STATS button is pressed or when atleast 10 pts have been tracked/ or when TRACKING is STOPPED
00051 // checks if collected data vector is empty, if not generate player specific data
00052 
00053 // traverses through the entire set of data and on the basis of X component classifies the data as
00054 // player A's or player B's
00055 
00056 // data comes in pixel coords...so -ve axis
00057 // simple cmparison enough
00058 // also world coords conversion shud be brought into this class
00059 
00060 void BallPointsProcessing::processTrackingData()
00061 {
00062     int _dataSetSize = m_entireTrackedDataPts.size();
00063 
00064     std::cout<<"DataSize is:"<<_dataSetSize<<"\n";
00065 
00066 
00067     int _rallyIncrementIndexLR = 0;
00068     int _rallyIncrementIndexRL = 0;
00069 
00070     bool _rightToLeft = false;
00071     bool _leftToRight = false;
00072 
00073 
00074     // initial initialization for the first sets of rally....
00075     m_playerAPts.push_back(std::vector<cv::Point3f> ());
00076     m_playerBPts.push_back(std::vector<cv::Point3f> ());
00077 
00078     m_playerADeepestPtIndices.push_back(std::vector<int> ());
00079     m_playerBDeepestPtIndices.push_back(std::vector<int> ());
00080 
00081     if(_dataSetSize != 0)
00082     {
00083         for(int i=0;(i+1)<_dataSetSize;i++) // we shud stop one element before the last as there wud be no next elt to compare it with
00084         {
00085 
00086             // Rally direction classification
00087 
00088             // notes to self:
00089 
00090             // equality condition not needed as 2 pts equal and next to each other is most probably
00091             // a redundant data rather than actual data as the ball when travelling
00092             // with high speed is getting detected twice at almost the same locaions
00093             // so one of the values can be safely ignored
00094             // so if i == i+1,it would be classified into a single rally once
00095 
00096             if((int)(m_entireTrackedDataPts[i].x) < (int)(m_entireTrackedDataPts[i+1].x)) // changed to <= as we have pasted it inverted
00097                                                                                // but the data is from 0,0 at the top right
00098             {
00099                  //player left to right ( when viwed in perspective of kinet's position)
00100                 // lesser pixels to greater pixels assuming 0,0 at top right of table
00101 
00102                 // if previously there was a rally from right to left,
00103                 // then there is a direction change now, hence it has come into this if
00104                 // hence we need to increment rally index and
00105                 // set the current direction to true as long as it comes into this if
00106                 if(_rightToLeft == true)
00107                 {
00108 
00109                     if(m_playerBDeepestPtIndices[_rallyIncrementIndexRL].size() == 0)
00110                     {
00111                         m_playerBDeepestPtIndices[_rallyIncrementIndexRL].push_back(-1);
00112 
00113                     }
00114 
00115                     // duplication of end points when direction changes
00116                     m_playerBPts[_rallyIncrementIndexRL].push_back(m_entireTrackedDataPts[i]);
00117 
00118                     _rallyIncrementIndexRL++;
00119                     m_playerBPts.push_back(std::vector<cv::Point3f> ());
00120                     m_playerBDeepestPtIndices.push_back(std::vector<int> ());
00121                     _rightToLeft = false;
00122 
00123 
00124                 }
00125 
00126 
00127 
00128 
00129                 m_playerAPts[_rallyIncrementIndexLR].push_back(m_entireTrackedDataPts[i]);
00130 
00131 
00132                 // Impact point classification
00133 
00134                 // if fortunately we have actually got a point beyond our impact point thrsh
00135                 // then this must be the impact point
00136                 if(m_entireTrackedDataPts[i].z > m_ballImpactDepthMaxThresh)
00137                 {
00138                     m_playerADeepestPtIndices[_rallyIncrementIndexLR].push_back((m_playerAPts[_rallyIncrementIndexLR].size() - 1));
00139                 }
00140 
00141                 // else we need to check for polarity change
00142                 // if there is a positive polarity(sign) in the difference among the depth values
00143                 // of 3 consecutively detected points then this is an impact point
00144 
00145                 // i.e. if sign of the difference in depth values between 1 and 2 is positive and
00146                 // sign of the difference in depth values between 2 and 3 is also positive
00147                 // then the ball must have pitched on the ground
00148                 else
00149                 {
00150                     // depth detected should atleast be > this min thresh
00151                     // else some points which has a depth of say 0.5 which is supposed to
00152                     // be not compared for polarity changes will be taken for comparison
00153                     // this will be useful when data points are low in number, and
00154                     // no data is actually valid for depth..this might not be useful
00155                     // if detection is proper
00156 
00157                     // first point wont fit into this condition as we need 3 points atleast
00158                     if((i !=0) && (m_entireTrackedDataPts[i].z > m_ballImpactDepthMinThresh) )
00159                     {
00160                         if(((m_entireTrackedDataPts[i].z - m_entireTrackedDataPts[i-1].z) > 0) && ((m_entireTrackedDataPts[i].z - m_entireTrackedDataPts[i+1].z) > 0))
00161                         {
00162                             // we need to push the index of this point
00163                             // so push the (current size - 1) of the ith rally which will refer to the current ball point
00164                             // as vector starts from 0
00165 
00166                             m_playerADeepestPtIndices[_rallyIncrementIndexLR].push_back((m_playerAPts[_rallyIncrementIndexLR].size() - 1));
00167                         }
00168                     }
00169                 }
00170 
00171                 // if next point is the last point
00172                 // then push the last point as part of the current rally
00173 
00174                 if((i+1) == (_dataSetSize -1))
00175                 {
00176                     //- for Rally Classification
00177 
00178                     //m_playerAPts.push_back(std::vector<cv::Point3f> ());
00179 
00180                     // next elt is the last elt..push it into the same player rally as the prev point
00181                     m_playerAPts[_rallyIncrementIndexLR].push_back(m_entireTrackedDataPts[i+1]);
00182 
00183                     //- for Impact Point Classification
00184 
00185                     // as this last point may actually be an impact point
00186                     // we cannot perform the other logic of polarity change, but
00187                     // we can atleast perform the depth thresh check
00188                     if(m_entireTrackedDataPts[i+1].z > m_ballImpactDepthMaxThresh)
00189                     {
00190                         m_playerADeepestPtIndices[_rallyIncrementIndexLR].push_back((m_playerAPts[_rallyIncrementIndexLR].size() - 1));
00191                     }
00192 
00193 
00194                 }
00195 
00196                 // if next point is the last point - for Depth classification
00197 
00198                 // in case there was no depth change detected until the last point
00199                 // then the last point will be automatically treated as an end point with regards to interpolation
00200                 // and there will be no impact point
00201 
00202                 _leftToRight = true;
00203             }
00204             else if ((int)(m_entireTrackedDataPts[i].x) > (int)(m_entireTrackedDataPts[i+1].x))
00205             {
00206                 //  player right to left as seen from kinects top view
00207                 // greater pixels to lesser pixels assuming 640,480 at left bottom of table
00208 
00209                 // if previously there was a rally from left to right,
00210                 // then there is a sirection change now, hence it has come into this else
00211                 // hence we need to increment rally index and
00212                 // set the current direction to true as long as it comes into this else
00213 
00214                 if(_leftToRight == true)
00215                 {
00216                     if(m_playerADeepestPtIndices[_rallyIncrementIndexLR].size() == 0)
00217                     {
00218                         m_playerADeepestPtIndices[_rallyIncrementIndexLR].push_back(-1);
00219 
00220                     }
00221 
00222                     // duplication of end points when direction changes
00223                     m_playerAPts[_rallyIncrementIndexLR].push_back(m_entireTrackedDataPts[i]);
00224 
00225                     _rallyIncrementIndexLR++;
00226                     m_playerAPts.push_back(std::vector<cv::Point3f> ());
00227                     m_playerADeepestPtIndices.push_back(std::vector<int> ());
00228                     _leftToRight = false;
00229                 }
00230 
00231 
00232 
00233 
00234                 m_playerBPts[_rallyIncrementIndexRL].push_back(m_entireTrackedDataPts[i]);
00235 
00236 
00237                 // Impact point classification
00238                 // same logic
00239 
00240                 if(m_entireTrackedDataPts[i].z > m_ballImpactDepthMaxThresh)
00241                 {
00242                     m_playerBDeepestPtIndices[_rallyIncrementIndexRL].push_back((m_playerBPts[_rallyIncrementIndexRL].size() - 1));
00243                 }
00244 
00245                 else
00246                 {
00247 
00248                     if((i !=0) && (m_entireTrackedDataPts[i].z > m_ballImpactDepthMinThresh) )
00249                     {
00250                         if(((m_entireTrackedDataPts[i].z - m_entireTrackedDataPts[i-1].z) > 0) && ((m_entireTrackedDataPts[i].z - m_entireTrackedDataPts[i+1].z) > 0))
00251                         {
00252                             m_playerBDeepestPtIndices[_rallyIncrementIndexRL].push_back((m_playerBPts[_rallyIncrementIndexRL].size() - 1));
00253                         }
00254                     }
00255                 }
00256 
00257                 // if next point is the last point
00258                 // same logic
00259 
00260                 if((i+1) == (_dataSetSize -1))
00261                 {
00262 
00263                     //- for Rally Classification
00264 
00265                     //m_playerBPts.push_back(std::vector<cv::Point3f> ());
00266 
00267                     // next elt is the last elt..push it into the same player rally as the prev point
00268                     m_playerBPts[_rallyIncrementIndexRL].push_back(m_entireTrackedDataPts[i+1]);
00269 
00270                     //- for Impact Point Classification
00271 
00272                     if(m_entireTrackedDataPts[i+1].z > m_ballImpactDepthMaxThresh)
00273                     {
00274                         m_playerBDeepestPtIndices[_rallyIncrementIndexRL].push_back((m_playerBPts[_rallyIncrementIndexRL].size() - 1));
00275                     }
00276                 }
00277 
00278                 // if next point is the last point for Depth classification
00279 
00280                 // in case there was no depth change detected until the last point
00281                 // then the last point will be automatically treated as an end point with regards to interpolation
00282                 // and there will be no impact point
00283 
00284                 _rightToLeft = true;
00285             }
00286 
00287 
00288         }
00289 
00290         // set the playerA vector and playerB vector into the respective instances
00291         // by calling their set() functions
00292 
00293 
00294         m_playerA->setPlayerBallPts(m_playerAPts);
00295         m_playerA->setPlayerImpactPtIndices(m_playerADeepestPtIndices);
00296 
00297         m_playerB->setPlayerBallPts(m_playerBPts);
00298         m_playerB->setPlayerImpactPtIndices(m_playerBDeepestPtIndices);
00299 
00300 
00301         int aRallies = 0;
00302         int bRallies = 0;
00303 
00304         for(int i = 0;i<m_playerAPts.size();i++)
00305         {
00306             for(int j=0;j<m_playerAPts[i].size();j++)
00307             {
00308                 if(j==0)
00309                 {
00310                     aRallies++;
00311                     std::cout<<"New rally starts....\n";
00312                 }
00313                 std::cout<<"PlayerA points are:"<<m_playerAPts[i][j]<<"\n";
00314             }
00315         }
00316 
00317         for(int i = 0;i<m_playerBPts.size();i++)
00318         {
00319             for(int j=0;j<m_playerBPts[i].size();j++)
00320             {
00321                 if(j==0)
00322                 {
00323                     bRallies++;
00324                     std::cout<<"New rally starts....\n";
00325                 }
00326                 std::cout<<"PlayerB points are:"<<m_playerBPts[i][j]<<"\n";
00327             }
00328         }
00329 
00330 
00331         // these are the proper rally counts
00332         // as we push an empty vector set each time there is a direction change into the
00333         // opposite direction's vectorofvector for the next anitcipated direction change
00334         // which may not get filled in as the anticipated next change of direction
00335         // might not have occured which leaves the last pushed vector set empty
00336         // hence the rally increment counter has to be incremented only when there is data in the
00337         // inner vector set..this increment is done in the above inner for loop
00338 
00339         std::cout<<"A rallies:\n"<<aRallies;
00340         std::cout<<"B rallies\n:"<<bRallies;
00341 
00342 
00343 
00344         for(int i = 0;i<m_playerADeepestPtIndices.size();i++)
00345         {
00346             for(int j=0;j<m_playerADeepestPtIndices[i].size();j++)
00347             {
00348                 std::cout<<"PlayerA Impact index are:"<<m_playerADeepestPtIndices[i][j]<<"\n";
00349 
00350                 std::cout<<"which is"<<m_playerAPts[i][m_playerADeepestPtIndices[i][j]]<<"\n";
00351             }
00352         }
00353 
00354         for(int i = 0;i<m_playerBDeepestPtIndices.size();i++)
00355         {
00356             for(int j=0;j<m_playerBDeepestPtIndices[i].size();j++)
00357             {
00358                 std::cout<<"PlayerB Impact index are:"<<m_playerBDeepestPtIndices[i][j]<<"\n";
00359 
00360                 std::cout<<"which is"<<m_playerBPts[i][m_playerBDeepestPtIndices[i][j]]<<"\n";
00361             }
00362         }
00363 
00364 
00365         // set the data processed flag for both the players as we have now filled all the points needed
00366         // for further stats calculation
00367         // this flag when set will be queried by the stats window to gather data from the player's
00368         // object
00369         m_playerA->setPlayerDataProcessedFlag();
00370         m_playerB->setPlayerDataProcessedFlag();
00371 
00372     }
00373     else
00374     {
00375 
00376         QString warningString("Oops.Enough data points not available. Relax!!! Start Tracking again and Play to generate new data!!!");
00377         QMessageBox * warning = new QMessageBox(QMessageBox::Warning,QString("NO DATA WARNING"),warningString,QMessageBox::Ok);
00378         warning->setModal(true);
00379         warning->setText(warningString);
00380         warning->show();
00381 
00382         // display this in message box
00383     }
00384 }
00385 
00386 void BallPointsProcessing::setBallImpactDepthMaxThreshold(double _impactPtDepthMaxThresh)
00387 {
00388     m_ballImpactDepthMaxThresh = (float)_impactPtDepthMaxThresh;
00389 }
00390 
00391 void BallPointsProcessing::setBallImpactDepthMinThreshold(double _impactPtDepthMinThresh)
00392 {
00393     m_ballImpactDepthMinThresh = (float)_impactPtDepthMinThresh;
00394 }
00395 
00396 
 All Classes Files Functions Variables Enumerations Enumerator