KINECT STATS GENERATOR FOR SPORTS VISUALISATION  1.0
KinectInterface.cpp
Go to the documentation of this file.
00001 /*
00002  * This file is part of the OpenKinect Project. http://www.openkinect.org
00003  *
00004  * Copyright (c) 2010 individual OpenKinect contributors. See the CONTRIB file
00005  * for details.
00006  *
00007  * This code is licensed to you under the terms of the Apache License, version
00008  * 2.0, or, at your option, the terms of the GNU General Public License,
00009  * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses,
00010  * or the following URLs:
00011  * http://www.apache.org/licenses/LICENSE-2.0
00012  * http://www.gnu.org/licenses/gpl-2.0.txt
00013  *
00014  * If you redistribute this file in source form, modified or unmodified, you
00015  * may:
00016  *   1) Leave this header intact and distribute it under the same terms,
00017  *      accompanying it with the APACHE20 and GPL20 files, or
00018  *   2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or
00019  *   3) Delete the GPL v2 clause and accompany it with the APACHE20 file
00020  * In all cases you must keep the copyright notice intact and include a copy
00021  * of the CONTRIB file.
00022  *
00023  * Binary distributions must follow the binary distribution requirements of
00024  * either License.
00025  */
00026 
00027 //----------------------------------------------------------------------------------------------------------------------
00031 //----------------------------------------------------------------------------------------------------------------------
00032 
00033 #include <KinectInterface.h>
00034 #include <QDebug>
00035 #include <cstdlib>
00036 #include <cmath>
00037 #include <cassert>
00038 //#include <boost/lexical_cast.hpp>
00039 
00040 
00041 
00042 //----------------------------------------------------------------------------------------------------------------------
00043 KinectInterface *KinectInterface::s_instance = 0;// initialize pointer
00044 //----------------------------------------------------------------------------------------------------------------------
00045 
00046 
00047 //----------------------------------------------------------------------------------------------------------------------
00048 void QKinectProcessEvents::run()
00049 {
00050     // loop while we are active and process the kinect event queue
00051     while(m_active)
00052     {
00053         //qDebug()<<"process thread\n";
00054         if(freenect_process_events(m_ctx) < 0)
00055         {
00056             throw std::runtime_error("Cannot process freenect events");
00057         }
00058     }
00059 }
00060 
00061 //----------------------------------------------------------------------------------------------------------------------
00063 //----------------------------------------------------------------------------------------------------------------------
00064 KinectInterface::~KinectInterface()
00065 {
00066         // dtor is not called directly
00067         if (s_instance)
00068         {
00069                 delete s_instance;
00070         }
00071 }
00072 //----------------------------------------------------------------------------------------------------------------------
00074 //----------------------------------------------------------------------------------------------------------------------
00075 KinectInterface* KinectInterface::instance()
00076 {
00077     // this is the main singleton code first check to see if we exist
00078     if (s_instance==0 )
00079     {
00080         // we do so create an instance (this will validate the pointer so other
00081         // methods called in the init function will have a valid pointer to use)
00082         s_instance = new KinectInterface;
00083         // now setup the actual class (with a valid pointer)
00085         if(s_instance->init() ==  false)
00086         {
00087             s_instance = 0;
00088         }
00089     }
00090     // otherwise return the existing pointer
00091     return s_instance;
00092 }
00093 
00094 
00095 //----------------------------------------------------------------------------------------------------------------------
00096 KinectInterface::KinectInterface() : QObject(0)
00097 {
00098     // nothing to see here we just need a valid object pointer the init
00099     // method does all the hard work
00100     qDebug()<<"ctor called \n";
00101 
00102     for( unsigned int i = 0 ; i < 640*480 ; ++i)
00103     {
00104         m_bufferDepthinM[i] = 0;
00105     }
00106 
00107 
00108 
00109 
00110 }
00111 //----------------------------------------------------------------------------------------------------------------------
00112 bool KinectInterface::init()
00113 {
00114     // first see if we can init the kinect
00115     if (freenect_init(&m_ctx, NULL) < 0)
00116     {
00117         qDebug()<<"freenect_init() failed\n";
00118         exit(EXIT_FAILURE);
00119     }
00121     freenect_set_log_level(m_ctx, FREENECT_LOG_DEBUG);
00123     int nr_devices = freenect_num_devices (m_ctx);
00124     qDebug()<<"Number of devices found: "<<nr_devices<<"\n";
00125 
00126     if(nr_devices < 1)
00127     {
00128         //delete s_instance;
00129         //s_instance = 0;
00130         return false;
00131     }
00133     m_userDeviceNumber = 0;
00134     // grab the buffer size and store for later use
00135     m_resolutionRGBBytes=freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM,FREENECT_VIDEO_RGB).bytes;
00136     m_bufferDepth=cvCreateMat(480,640,CV_8UC3);
00137 
00138     //m_bufferVideo.resize(m_resolutionRGBBytes);
00139 
00140     m_bufferVideo = cvCreateMat(480,640,CV_8UC3);
00141 
00142 //    m_nextBuffer = cvCreateMat(480,640,CV_8UC1);
00143 //    m_prevBuffer = cvCreateMat(480,640,CV_8UC1);
00144 //    m_diffBuffer = cvCreateMat(480,640,CV_8UC1);
00145 
00146     m_resolutionDepthBytes=freenect_find_depth_mode(FREENECT_RESOLUTION_MEDIUM,FREENECT_DEPTH_11BIT).bytes;
00147     //m_bufferDepthRaw.resize(m_resolutionDepthBytes);
00148     m_bufferDepthRaw16=cvCreateMat(480,640,CV_8UC1);
00149 
00150     m_bufferDepthRaw=cvCreateMat(480,640,CV_8UC1);
00151 
00152 
00153 
00154    // m_originalFrameDepth=NULL;
00155 
00156 
00157 
00158     m_gamma.resize(2048);
00162     if (freenect_open_device(m_ctx, &m_dev, m_userDeviceNumber) < 0)
00163     {
00164         qDebug()<<"Could not open device\n";
00165         exit(EXIT_FAILURE);
00166     }
00167 
00168 
00171 //    for (int i=0; i<2048; ++i)
00172 //    {
00173 //        float v = i/2048.0;
00174 //        v = std::pow(v, 3)* 6;
00175 //        m_gamma[i] = v*6*256;
00176 //    }
00177 
00178 
00179     // from opencv imaging imformation wiki page http://openkinect.org/wiki/Imaging_Information
00180     const float k1 = 1.1863;
00181     const float k2 = 2842.5;
00182     const float k3 = 0.1236;
00183     const float offset = 0.037;
00184     float depth = 0;
00185     for (size_t i=0; i<2048; i++)
00186     {
00187         depth = k3 * tanf(i/k2 + k1) - offset;
00188         m_gamma[i] = depth;
00189     }
00190 
00191 
00193     m_newRgbFrame=false;
00194     m_newDepthFrame=false;
00195     m_deviceActive=true;
00196 
00197     m_threshValue = 100;
00198 
00199 
00200     // set our video formats to RGB by default
00202     freenect_set_video_mode(m_dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_RGB));
00203     freenect_set_depth_mode(m_dev, freenect_find_depth_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_11BIT));
00204     // deprecated
00205     //freenect_set_video_format(m_dev, FREENECT_VIDEO_RGB);
00206     //freenect_set_depth_format(m_dev, FREENECT_DEPTH_11BIT);
00208     freenect_set_depth_callback(m_dev, depthCallback);
00209     freenect_set_video_callback(m_dev, videoCallback);
00210     // start the video and depth sub systems
00211     startVideo();
00212     startDepth();
00213     // set the thread to be active and start
00214     m_process = new QKinectProcessEvents(m_ctx);
00215     m_process->setActive();
00216     m_process->start();
00217 
00218     m_depthLower = 0.02;
00219     m_depthHigher = 1.02; // has to be just above the table (in meteres)
00220 
00221     //m_selectedBoxCoords = NULL;
00222 
00223     m_selectedBoxCoords = cv::Rect(0,0,0,0);
00224 
00225     m_toggleTracking = false;
00226     m_setBounds = false;
00227 
00228     return true;
00229 }
00230 
00231 //----------------------------------------------------------------------------------------------------------------------
00232 void KinectInterface::shutDownKinect()
00233 {
00235     m_process->setInActive();
00237     freenect_stop_depth(m_dev);
00238     freenect_stop_video(m_dev);
00239     // close down our devices
00240     freenect_close_device(m_dev);
00241     freenect_shutdown(m_ctx);
00242 
00243 }
00244 
00245 //----------------------------------------------------------------------------------------------------------------------
00246 void KinectInterface::setVideoMode(
00247                                                      int _mode
00248                                                     )
00249 {
00250     freenect_video_format vm=FREENECT_VIDEO_RGB;
00251     switch(_mode)
00252     {
00253         case 0 : { vm=FREENECT_VIDEO_RGB; break;}
00254         case 1 : { vm=FREENECT_VIDEO_YUV_RGB; break;}
00255         case 2 : { vm=FREENECT_VIDEO_IR_8BIT; break;}
00256         /*
00258         case 1 : { vm=FREENECT_VIDEO_BAYER; break;}
00259         case 2 : { vm=FREENECT_VIDEO_IR_8BIT; break;}
00260         case 3 : { vm=FREENECT_VIDEO_IR_10BIT; break;}
00261         case 4 : { vm=FREENECT_VIDEO_IR_10BIT_PACKED; break;}
00262         case 5 : { vm=FREENECT_VIDEO_YUV_RGB; break;}
00263         case 6 : { vm=FREENECT_VIDEO_YUV_RAW; break;}
00264         */
00265         default : qDebug()<<"index out of bounds for video mode\n";
00266                             vm=FREENECT_VIDEO_RGB;
00267         break;
00268     }
00270     freenect_stop_video(m_dev);
00271     freenect_set_video_mode(m_dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_RGB));
00272     //deprecated
00273     //  freenect_set_video_format(m_dev, vm);
00274     freenect_start_video(m_dev);
00275 }
00276 
00277 //----------------------------------------------------------------------------------------------------------------------
00278 bool KinectInterface::getRGB(cv::Mat &o_buffer)
00279 {
00280 
00281     //static int _frameCount = 1;
00284     QMutexLocker locker( &m_mutex );
00285     // do we have a new frame?
00286     if(m_newRgbFrame)
00287     {
00288 
00289         m_bufferVideo.copyTo(o_buffer);
00290         m_newRgbFrame = false;
00291         return true;
00292     }
00293     else
00294     {
00295     return false;
00296     }
00297 }
00298 
00299 
00300 //----------------------------------------------------------------------------------------------------------------------
00301 bool KinectInterface::getDepth(
00302                                                 cv::Mat &o_buffer
00303                                             )
00304 {
00305     // this fills the depth buffer, first lock our mutex
00306     QMutexLocker locker( &m_mutex );
00307     if(m_newDepthFrame)
00308     {
00309         // swap data
00310         m_bufferDepth.copyTo(o_buffer);
00311 
00312         m_newDepthFrame = false;
00313         return true;
00314     }
00315     else
00316     {
00317         return false;
00318     }
00319 }
00320 //----------------------------------------------------------------------------------------------------------------------
00321 bool KinectInterface::getDepth16Bit(
00322                                                          cv::Mat &o_buffer
00323                                                      )
00324 {
00326     QMutexLocker locker( &m_mutex );
00327     if(m_newDepthFrame)
00328     {
00329         // fill our buffer if avaliable
00330         m_bufferDepthRaw16.copyTo(o_buffer);
00331         m_newDepthFrame = false;
00332         return true;
00333     }
00334     else
00335     {
00336         return false;
00337     }
00338 }
00339 
00340 
00341 //----------------------------------------------------------------------------------------------------------------------
00342 bool KinectInterface::getDepthSliced(
00343                                                          cv::Mat &o_buffer
00344                                                      )
00345 {
00347     QMutexLocker locker( &m_mutex );
00348     if(m_newDepthFrame)
00349     {
00350         // fill our buffer if avaliable
00351         m_bufferDepthRaw.copyTo(o_buffer);
00352         m_newDepthFrame = false;
00353         return true;
00354     }
00355     else
00356     {
00357         return false;
00358     }
00359 }
00360 
00361 //----------------------------------------------------------------------------------------------------------------------
00362 bool KinectInterface::getDepthRaw(cv::Mat &o_buffer, float *o_depthinmBuffer)
00363 {
00364 
00365 
00366     QMutexLocker locker( &m_mutex );
00367     if(m_newDepthFrame)
00368     {
00369 
00370         m_bufferDepthRaw.copyTo(o_buffer);
00371         for( unsigned int i = 0 ; i < 640*480 ; ++i)
00372         {
00373             o_depthinmBuffer[i] = m_bufferDepthinM[i];
00374         }
00375         m_newDepthFrame = false;
00376         return true;
00377     }
00378     else
00379     {
00380         return false;
00381     }
00382 }
00383 //----------------------------------------------------------------------------------------------------------------------
00384 void KinectInterface::grabDepth(
00385                                                 void *_depth,
00386                                                 uint32_t _timestamp
00387                                              )
00388 {
00389 // this method fills all the different depth buffers at once
00390 // modifed from the sample code glview and cppview.cpp
00392 QMutexLocker locker( &m_mutex );
00393 // cast the void pointer to the unint16_t the data is actually in
00394 uint16_t* depth = static_cast<uint16_t*>(_depth);
00395 
00396 
00397 
00398 // now loop and fill data buffers
00399 for( unsigned int i = 0 ; i < 640*480 ; ++i)
00400 {
00401     // first our two raw buffers the first will lose precision and may well
00402     // be removed in the next iterations
00403 
00404     // now get the index into the gamma table
00405     float pval = m_gamma[depth[i]]; // my notes: so pval is in metres now..using cam caliberation values, we have converted depth values to metres
00406                                     // using open kinect forum formulae this (i,j,z) value can be transformed to (x,y,z)
00407 
00408 
00409 
00410 
00411 
00412     //m_bufferDepthinM.data[i] = m_gamma[depth[i]];
00413 
00414     //m_originalFrameDepth1[_frameCountGrab] = m_gamma[depth[i]];
00415 
00416 
00417     //std::cout<<"pval is"<<pval<<"\n";
00418 
00419     // a bounded volume as explained in rally keeper project to detect contours
00420     if (pval >= m_depthLower && pval <= m_depthHigher)
00421     {
00422         m_bufferDepthRaw.data[i]=255;
00423         m_bufferDepthRaw16.data[i]=255;
00424         m_bufferDepthinM[i] = depth[i];
00425     }
00426     else
00427     {
00428         m_bufferDepthRaw.data[i]=0;
00429         m_bufferDepthRaw16.data[i]=0;
00430     }
00431     if (pval <= 0.9)
00432     {
00433         m_bufferDepth.data[3*i+0] = 255;
00434         m_bufferDepth.data[3*i+1] = 0;
00435         m_bufferDepth.data[3*i+2] = 0;
00436 
00437     }
00438     else if (pval > 0.9 && pval <= 2)
00439     {
00440         m_bufferDepth.data[3*i+0] = 0;
00441         m_bufferDepth.data[3*i+1] = 255;
00442         m_bufferDepth.data[3*i+2] = 0;
00443 
00444     }
00445     else if (pval > 2)
00446     {
00447         m_bufferDepth.data[3*i+0] = 0;
00448         m_bufferDepth.data[3*i+1] = 0;
00449         m_bufferDepth.data[3*i+2] = 255;
00450 
00451     }
00452 }
00453 // flag we have a new frame
00454 m_newDepthFrame = true;
00455 }
00456 //----------------------------------------------------------------------------------------------------------------------
00457 void KinectInterface::grabVideo(
00458                                                 void *_video,
00459                                                 uint32_t _timestamp
00460                                              )
00461 {
00462     // lock our mutex and copy the data from the video buffer
00463     QMutexLocker locker( &m_mutex );
00464     uint8_t* rgb = static_cast<uint8_t*>(_video);
00465     //std::copy(rgb, rgb+m_resolutionRGBBytes, m_bufferVideo.begin());
00466     memcpy(  m_bufferVideo.data , rgb, m_resolutionRGBBytes);
00467 
00468     m_newRgbFrame = true;
00469 }
00470 
00471 //----------------------------------------------------------------------------------------------------------------------
00472 void KinectInterface::startVideo()
00473 {
00474     if(freenect_start_video(m_dev) < 0)
00475     {
00476         throw std::runtime_error("Cannot start RGB callback");
00477     }
00478 }
00479 //----------------------------------------------------------------------------------------------------------------------
00480 void KinectInterface::stopVideo()
00481 {
00482     if(freenect_stop_video(m_dev) < 0)
00483     {
00484         throw std::runtime_error("Cannot stop RGB callback");
00485     }
00486 }
00487 //----------------------------------------------------------------------------------------------------------------------
00488 void KinectInterface::startDepth()
00489 {
00490     if(freenect_start_depth(m_dev) < 0)
00491     {
00492         throw std::runtime_error("Cannot start depth callback");
00493     }
00494 }
00495 
00496 //----------------------------------------------------------------------------------------------------------------------
00497 void KinectInterface::stopDepth()
00498 {
00499     if(freenect_stop_depth(m_dev) < 0)
00500     {
00501         throw std::runtime_error("Cannot stop depth callback");
00502     }
00503 }
00504 
00505 //----------------------------------------------------------------------------------------------------------------------
00506 void KinectInterface::toggleVideoState(bool _mode)
00507 {
00508     if(_mode ==true)
00509     {
00510         startVideo();
00511     }
00512     else
00513     {
00514         stopVideo();
00515     }
00516 }
00517 //----------------------------------------------------------------------------------------------------------------------
00518 void KinectInterface::toggleDepthState(bool _mode)
00519 {
00520     if(_mode == true)
00521     {
00522         startDepth();
00523     }
00524     else
00525     {
00526         stopDepth();
00527     }
00528 }
00529 
00530 
00531 void KinectInterface::setDepthVolumeLower(double _inputLowerDepth)
00532 {
00533     m_depthLower = _inputLowerDepth;
00534 }
00535 
00536 void KinectInterface::setDepthVolumeHigher(double _inputHigherDepth)
00537 {
00538     m_depthHigher = _inputHigherDepth;
00539 }
00540 
00541 void KinectInterface::setBoxObject(int _topX, int _topY, int _width, int _height)
00542 {
00543     m_setBounds = true;
00544     m_selectedBoxCoords.x = _topX;
00545     m_selectedBoxCoords.y = _topY;
00546     m_selectedBoxCoords.width = _width;
00547     m_selectedBoxCoords.height = _height;
00548 
00549 }
00550 
00551 cv::Rect& KinectInterface::getBoxObject()
00552 {
00553     return m_selectedBoxCoords;
00554 }
00555 
00556 void KinectInterface::toggleTracking()
00557 {
00558     m_toggleTracking = !(m_toggleTracking);
00559 }
00560 
00561 bool KinectInterface::getTrackingFlag()
00562 {
00563     return m_toggleTracking;
00564 }
00565 
00566 bool KinectInterface::getBounds()
00567 {
00568     return m_setBounds;
00569 }
00570 
00571 void KinectInterface::setBoundsDefined(bool _isBoundsDefined)
00572 {
00573     m_setBounds = _isBoundsDefined;
00574 }
00575 
00576 
00577 //----------------------------------------------------------------------------------------------------------------------
 All Classes Files Functions Variables Enumerations Enumerator