KINECT STATS GENERATOR FOR SPORTS VISUALISATION
1.0
|
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