OmniMotionDetecting.hh

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) Massimo Cora' 2005 <maxcvs@email.it>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #ifndef __OMNIMOTION_DETECTING__
00021 #define __OMNIMOTION_DETECTING__
00022 
00023 #include <cv.h>
00024 #include <highgui.h>
00025 
00026 #include <time.h>
00027 
00028 #include "OmniConfig.hh"
00029 #include "OmniConversion.hh"
00030 
00031 
00033 
00034 const double MHI_DURATION = 1;
00035 
00037 const double MAX_TIME_DELTA = 1;
00038 
00040 const double MIN_TIME_DELTA = 0.05;
00041 
00046 typedef void (on_window_trackable_wannabe_cb)(  IplImage* omni_frame, 
00047                                                                                                 int theta_start, 
00048                                                                                                 int theta_end, 
00049                                                                                                 int win_length, 
00050                                                                                                 void* callback_data );
00051 
00058 template <class ConverterT, class AngleT>
00059 class OmniMotionDetecting {
00060 public:
00070         OmniMotionDetecting( on_window_trackable_wannabe_cb *f_cb,
00071                                                  void* callback_data,
00072                                                  OmniConversion<ConverterT, AngleT, IplImage, CvPoint> *conv_table,
00073                                                  int ring_buf_length = 4 );
00074         virtual ~OmniMotionDetecting();
00075 
00080         void process_next_frame( IplImage *next_frame );
00081 
00091         void register_image_callbacks( on_create_image_context_cb* create_image_context,
00092                                                                    on_image_do_action_cb* image_show,
00093                                                                    on_destroy_image_context_cb* destroy_image_context,
00094                                                                    void* callback_data_on_image_cb );
00095         
00096 
00097 private:        // functions
00103         void fast_update_mhi( IplImage* img, int diff_threshold = 10 );
00104 
00108         on_window_trackable_wannabe_cb* f_on_window_trackable_wannabe_cb;
00109         
00111         on_create_image_context_cb* create_image_context;
00112         
00114         on_image_do_action_cb* image_show;
00115         
00117         on_destroy_image_context_cb* destroy_image_context;
00118         
00119 private:        // data
00120 
00121         void* _callback_data_on_window_trackable_wannabe_cb;
00122         void* _callback_data_on_image_cb;
00123         
00128         OmniConversion<ConverterT, AngleT, IplImage, CvPoint> *_conv_table;
00129 
00131         IplImage **_ring_buf;
00132 
00134         int _ring_buf_length;
00135         int _ring_last_indx;
00136 
00138 
00139         IplImage *_mhi;
00140         
00142         IplImage *_orient;
00143         
00145         IplImage *_mask;
00146         
00148         IplImage *_segmask;     
00149         
00151         CvMemStorage *_storage; 
00152 };
00153 
00154 
00155 
00159 
00160 
00161 template <class ConverterT, class AngleT>
00162 OmniMotionDetecting<ConverterT, AngleT>::OmniMotionDetecting( on_window_trackable_wannabe_cb *f_cb,
00163                                                                                  void* callback_data,
00164                                                                                  OmniConversion<ConverterT, AngleT, IplImage, CvPoint> *conv_table,
00165                                                                                  int ring_buf_length /* = 4 */ ) : _conv_table( conv_table ),
00166                                                                                         f_on_window_trackable_wannabe_cb( f_cb ),
00167                                                                                         _callback_data_on_window_trackable_wannabe_cb ( callback_data ),
00168                                                                                         _ring_buf_length( ring_buf_length ),
00169                                                                                         _ring_last_indx( 0 ),
00170                                                                                         _mhi( 0 ),              
00171                                                                                         _orient( 0 ),
00172                                                                                         _mask( 0 ),
00173                                                                                         _segmask( 0 ),
00174                                                                                         _storage( 0 )
00175 {
00176         // create the ring buffer
00177         _ring_buf = (IplImage**)malloc( _ring_buf_length * sizeof(_ring_buf[0]) );
00178     memset( _ring_buf, 0, _ring_buf_length * sizeof(_ring_buf[0]) );
00179         
00180         // set the default callbacks. They can be changed with register_callbacks () call.
00181         // callback data to NULL to avoid strange behaviour on pointers.
00182         register_image_callbacks( omnistuff_create_image_context, omnistuff_image_do_action, 
00183                                                           omnistuff_destroy_image_context, NULL );
00184 }
00185 
00186 
00187 //-------------------------------------------------------------------------
00188 //
00189 
00190 template <class ConverterT, class AngleT>
00191 OmniMotionDetecting<ConverterT, AngleT>::~OmniMotionDetecting() 
00192 {
00193         free( _ring_buf );
00194 }
00195 
00196 //-------------------------------------------------------------------------
00197 //
00198 template <class ConverterT, class AngleT>
00199 void OmniMotionDetecting<ConverterT, AngleT>::process_next_frame( IplImage *next_frame ) 
00200 {
00201         fast_update_mhi( next_frame );
00202 }
00203 
00204 //-------------------------------------------------------------------------
00205 //
00206 
00207 template <class ConverterT, class AngleT>
00208 void OmniMotionDetecting<ConverterT, AngleT>::fast_update_mhi( IplImage* img, int diff_threshold /* = 10 */) 
00209 {
00210         // get current time in seconds
00211     double timestamp = clock()/1000.; 
00212 
00213         // get current frame size
00214     CvSize size = cvSize(img->width,img->height); 
00215     int i, idx1 = _ring_last_indx, idx2;
00216     IplImage* silh;
00217     CvSeq* seq;
00218     CvRect comp_rect;
00219 
00220     // allocate images at the beginning or
00221     // reallocate them if the frame size is changed
00222     if( (!_mhi || _mhi->width != size.width) || (_mhi->height != size.height) ) {
00223         
00224         for( i = 0; i < _ring_buf_length; i++ ) {
00225             cvReleaseImage( &_ring_buf[i] );
00226                         _ring_buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
00227             cvZero( _ring_buf[i] );
00228         }
00229         cvReleaseImage( &_mhi );
00230         cvReleaseImage( &_orient );
00231         cvReleaseImage( &_segmask );
00232         cvReleaseImage( &_mask );
00233         
00234         _mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 );
00235 
00236                 // clear MHI at the beginning - the motion history -
00237         cvZero( _mhi ); 
00238         _orient = cvCreateImage( size, IPL_DEPTH_32F, 1 );
00239         _segmask = cvCreateImage( size, IPL_DEPTH_32F, 1 );
00240         _mask = cvCreateImage( size, IPL_DEPTH_8U, 1 );
00241     }
00242 
00243         // convert frame to grayscale
00244     cvCvtColor( img, _ring_buf[_ring_last_indx], CV_BGR2GRAY ); 
00245 
00246         // index of (last - (N-1))th frame
00247     idx2 = (_ring_last_indx + 1) % _ring_buf_length; 
00248     _ring_last_indx = idx2;
00249 
00250     silh = _ring_buf[idx2];
00251         // get difference between frames
00252     cvAbsDiff( _ring_buf[idx1], _ring_buf[idx2], silh ); 
00253 
00254         // and threshold it
00255     cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); 
00256 
00257         // update MHI
00258     cvUpdateMotionHistory( silh, _mhi, timestamp, MHI_DURATION ); 
00259 
00260         if( !_storage )
00261         _storage = cvCreateMemStorage( 0 );
00262     else
00263         cvClearMemStorage( _storage );
00264 
00265     // segment motion: get sequence of motion components
00266     // segmask is marked motion components map. It is not used further
00267     seq = cvSegmentMotion( _mhi, _segmask, _storage, timestamp, MAX_TIME_DELTA );
00268 
00269 
00270     // iterate through the motion components,
00271     // One more iteration (i == -1) corresponds to the null image (no motion)
00272     for( i = -1; i < seq->total; i++ ) {
00273 
00274         if( i < 0 ) { // case of the whole image
00275             comp_rect = cvRect( 0, 0, size.width, size.width );
00276         }
00277         else { // i-th motion component
00278             comp_rect = ((CvConnectedComp*)cvGetSeqElem( seq, i ))->rect;
00279 
00280                         // reject very small components. This is important
00281             if( comp_rect.width + comp_rect.height < 150 ) 
00282                 continue;
00283         }
00284 
00285                 CvPoint left_bottom = { comp_rect.x, comp_rect.y };
00286 
00287                 // take the middle motion-rectangle angle. 
00288                 float rad_angle = atan2f( left_bottom.y - ((float)_conv_table->get_omni_center_y()),
00289                         left_bottom.x - ((float)_conv_table->get_omni_center_x()));
00290 
00291                 // let's call our callback function to which we'll deliver frame and angle range
00292                 OmniAngle<int> angle_int;
00293                 OmniAngle<double> angle_double(rad_angle - FACE_TRACK_ANGLE_WINDOW, 
00294                                                                                  rad_angle + FACE_TRACK_ANGLE_WINDOW,
00295                                                                                  2 * FACE_TRACK_ANGLE_WINDOW);
00296 
00297                 _conv_table->angle_type_conversion( angle_double, angle_int );
00298 
00299                 f_on_window_trackable_wannabe_cb( img, angle_int.angle_start, 
00300                         angle_int.angle_end, angle_int.range, _callback_data_on_window_trackable_wannabe_cb );
00301     }
00302 
00303         if ( seq != NULL )
00304                 cvClearSeq( seq );
00305 }
00306 
00307 //-------------------------------------------------------------------------
00308 //
00309 
00310 template <class ConverterT, class AngleT>
00311 void OmniMotionDetecting<ConverterT, AngleT>::register_image_callbacks( 
00312                                                                    on_create_image_context_cb* create_image_context,
00313                                                                    on_image_do_action_cb* image_show,
00314                                                                    on_destroy_image_context_cb* destroy_image_context,
00315                                                                    void* callback_data_on_image_cb
00316                                                                   )
00317 {
00318         this->create_image_context = create_image_context;
00319         this->image_show = image_show;
00320         this->destroy_image_context = destroy_image_context;
00321         this->_callback_data_on_image_cb = callback_data_on_image_cb;
00322 }
00323 
00324 
00325 #endif /*__OMNIMOTION_DETECTING__ */
00326 

Generated on Tue Dec 26 10:32:38 2006 for Omnimeeting by  doxygen 1.4.7