Update the changelog
[opencv] / apps / StereoGR / DynGestServer.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/// DynGestServer.cpp: implementation of the CDynGestServer class.
41 //
42 //////////////////////////////////////////////////////////////////////
43
44 #include "stdafx.h"
45 #include "DynGestServer.h"
46 #include "StereoGR.h"
47
48 #include "math.h"
49 #include "assert.h"
50 #include "float.h"
51
52 #include "direct.h"
53
54
55
56 CDynGesture::CDynGesture( int num_states, int num_mix )
57 {
58     m_hmm = NULL;
59 #if 0
60     m_obsType  = OT_VELOCITY;
61 #else
62         m_obsType  = OT_VELOCITY_ORIENTATION;
63 #endif
64     m_trained = FALSE;
65     m_num_states = num_states;
66     m_num_mix = num_mix;      
67     m_vect_size = 6;            
68 }          
69
70 CDynGesture::~CDynGesture()
71 {
72     if ( m_hmm ) icvRelease1DHMM( &m_hmm );
73     
74     for ( int i = 0; i < m_Sequences.size() ; i++ )
75     {
76         cvReleaseObsInfo( &(m_Sequences[i]) );
77     }
78 }
79
80 void CDynGesture::AddSequence( float* vectors, int seq_size, int vect_size )
81 {
82     Cv1DObsInfo* obs_info;
83     obs_info = cvCreateObsInfo( cvSize( seq_size,1), vect_size );
84     
85     memcpy( obs_info->obs, vectors, seq_size * vect_size * sizeof(float) );
86     m_Sequences.push_back( obs_info );
87
88     m_trained = FALSE;
89     
90 }
91
92 void CDynGesture::Train()
93 {
94     ExtractObservations();
95
96     int num_seq = m_Sequences.size();
97
98     if ( !num_seq ) ASSERT(0); 
99     
100     //create HMM
101     if (!m_hmm) CreateHMM();
102     
103     for(int i = 0; i < num_seq; i++ )
104     {
105         icvUniform1DSegm( m_Sequences[i], m_hmm );
106         //printf("uniform segmentation performed\n");     
107     }
108     
109     icvInit1DMixSegm( &m_Sequences[0], num_seq, m_hmm );
110     //printf("Init 1D mix segmentation performed\n");
111     
112     int trained = 0;
113     float old_likelihood = 0;
114     
115     //printf("Begin training\n");
116     //wait_key(0);         
117     
118     while( !trained )
119     {            
120         icvEstimate1DHMMStateParams( &m_Sequences[0], num_seq, m_hmm );
121         //printf("HMMstate performed\n");
122         icvEstimate1DTransProb( &m_Sequences[0], num_seq, m_hmm );
123         //printf("Transprob performed\n"); 
124         float likelihood = 0;  
125         
126         for( int j = 0; j < num_seq; j++ )
127         {           
128             icvEstimate1DObsProb( m_Sequences[j], m_hmm );
129             likelihood += icvViterbi( m_Sequences[j], m_hmm );
130             //wait_key(0);        
131         }
132         //printf("likelihood %f\n", likelihood );
133         
134         icv1DMixSegmL2( &m_Sequences[0], num_seq, m_hmm );
135         //printf("1DMixSegm performed\n"); 
136         
137         trained = ( fabs(likelihood - old_likelihood) < 0.01 ); 
138         old_likelihood = likelihood;                   
139     }
140     //printf("%d hmm trained\n", h );
141
142     m_trained = TRUE;
143     
144 }
145 BOOL  CDynGesture::SaveHMM(const char* filename)
146 {
147     FILE* file;
148     
149     if (!m_hmm) return FALSE;
150     file = fopen( filename, "wt" );
151     if (!file) { assert(0); return false; }
152     
153     // write topology
154     fprintf(file, "%s %d\n", "<NumStates>", m_hmm->num_states );
155     fprintf(file, "%s ", "<NumMixtures>");
156     for( int i = 0; i < m_hmm->num_states; i++ )
157     {
158         fprintf(file, "%d ", m_hmm->u.state[i].num_mix );        
159     }
160     fprintf(file, "\n");
161     
162     fprintf(file, "%s %d\n", "<VecSize>", m_vect_size );
163     
164     //consequently write all hmms
165     CvEHMM* hmm = m_hmm;
166     if (hmm->level == 0 )
167     {
168         for ( int j = 0; j < hmm->num_states; j++ )
169         {
170             CvEHMMState* state = &(hmm->u.state[j]);
171             
172             fprintf(file, "%s %d\n", "<State>", j);
173             fprintf(file, "%s %d\n", "<NumMixes>", state->num_mix);
174             
175             float* mu = state->mu;
176             float* inv_var = state->inv_var;
177             
178             for( int m = 0; m < state->num_mix; m++)
179             {
180                 fprintf(file, "%s %d %s %f\n", "<Mixture>", m, "<Weight>", state->weight[m] );
181                 fprintf(file, "%s\n", "<Mean>");
182                 
183                 for (int k = 0; k <  m_vect_size; k++)
184                 {  
185                     fprintf(file, "%f ", mu[0]); 
186                     mu++;
187                 }            
188                 
189                 fprintf(file, "\n");
190                 fprintf(file, "%s\n", "<Inverted_Deviation>");
191                 
192                 for (k = 0; k <  m_vect_size; k++)
193                 {
194                     fprintf(file, "%f ", inv_var[0]);
195                     inv_var++;
196                 }
197                 fprintf(file, "\n");
198                 
199                 fprintf(file, "%s %f\n", "<LogVarVal>", state->log_var_val[m] );   
200             }
201         }
202     }
203     
204     //write the transition probability matrix
205         fprintf(file, "%s\n", "<TransP>" ); 
206         float* prob = hmm->transP;
207
208         for (int j = 0; j < hmm->num_states; j++)
209         {
210             for (int k = 0; k < hmm->num_states; k++)
211             {
212                 fprintf(file, "%f ", *prob);
213                 prob++;
214             }            
215             fprintf(file, "\n");
216         }
217                 
218     fclose(file);
219     return true;
220 }
221
222 BOOL CDynGesture::LoadHMM(const char* filename)
223 {   
224     FILE* file;
225     int num_states;
226     int num_mix[128];
227     char temp_char[128];
228     int vec_size;
229
230     if (m_hmm) icvRelease1DHMM( &m_hmm);
231
232     file = fopen( filename, "rt" );
233
234     if (!file) return false;
235
236     // read topology
237     fscanf(file, "%s %d\n", temp_char, &num_states);
238     fscanf(file, "%s ", temp_char); 
239     
240     //compute total number of internal states
241     int total_states = num_states;
242     
243     //read number of mixtures
244     //fscanf(file, "%s ", temp_char);
245     for( int i = 0; i < total_states; i++ )
246     {
247         fscanf(file, "%d ", &num_mix[i] );
248     }
249     fscanf(file, "\n");
250
251     fscanf(file, "%s %d\n", temp_char, &vec_size);
252
253
254     icvCreate1DHMM( &m_hmm, num_states, num_mix, vec_size);
255  
256     //create HMM with known parameters
257 //!!!    cvCreate2DHMM( &m_hmm, num_states, num_mix, m_vectSize);
258     if (!m_hmm ) return FALSE;
259     
260     //consequently read all hmms
261     CvEHMM* hmm = m_hmm;
262     int temp_int;
263     
264     for (int j = 0; j < num_states; j++)
265     {
266         CvEHMMState* state = &(hmm->u.state[j]);
267         
268         fscanf(file, "%s %d\n", temp_char, &temp_int); assert(temp_int == j);
269         
270         fscanf(file, "%s %d\n", temp_char, &temp_int); assert(temp_int == state->num_mix);
271         
272         float* mu = state->mu;
273         float* inv_var = state->inv_var;
274         
275         for( int m = 0; m < state->num_mix; m++)
276         {
277             int temp_int;
278             fscanf(file, "%s %d %s %f\n", temp_char, &temp_int, temp_char, &(state->weight[m]) );
279             assert( temp_int == m );
280             fscanf(file, "%s\n", temp_char );
281             
282             for (int k = 0; k < vec_size; k++)
283             {  
284                 fscanf(file, "%f ", mu); 
285                 mu++;
286             }            
287             
288             fscanf(file, "\n");
289             fscanf(file, "%s\n", temp_char);  //  <Inverted_Deviation>
290             
291             for (k = 0; k < vec_size; k++)
292             {
293                 fscanf(file, "%f ", inv_var);
294                 inv_var++;
295             }
296             fscanf(file, "\n");
297             
298             fscanf(file, "%s %f\n", temp_char, &(state->log_var_val[m]) );  // <LogVarVal>                   
299         }
300     }
301     
302     //read the transition probability matrix
303     fscanf(file, "%s\n", temp_char ); // <TransP>
304     float* prob = hmm->transP;
305     
306     for ( j = 0; j < hmm->num_states; j++)
307     {
308         for (int k = 0; k < hmm->num_states; k++)
309         {
310             fscanf(file, "%f ", prob);
311             prob++;
312         }            
313         fscanf(file, "\n");
314     }       
315     
316     
317     fclose(file); 
318     return TRUE;
319 }
320
321 int CDynGesture::GetSeqNumber()
322 {
323     return m_Params.size();
324
325
326 //////////////////////////////////////////////////////////////////////
327 // Construction/Destruction
328 //////////////////////////////////////////////////////////////////////
329
330 CDynGestServer::CDynGestServer()
331 {
332     m_fullTrained = FALSE;
333 }
334
335 CDynGestServer::~CDynGestServer()
336 {
337
338 }
339
340 CDynGesture* CDynGestServer::FindGesture( const char* name )
341 {
342     for( int i = 0; i < m_gestures.size() ; i++ )
343     {
344         CString exist_name = m_gestures[i]->GetName();
345         if ( name ==  exist_name ) return m_gestures[i];
346     }
347     return 0; 
348 }
349
350 CDynGesture* CDynGestServer::AddGesture( const char* name )
351 {
352     CDynGesture* new_gest = new CDynGesture( m_num_states, m_num_mix);
353     new_gest->SetName( name );
354     m_gestures.push_back( new_gest );
355
356     m_fullTrained = FALSE;
357     
358     return m_gestures.back();
359
360
361 BOOL CDynGestServer::AddGesture( CDynGesture* new_gest )
362 {
363     if ( FindGesture( new_gest->GetName() )  ) return FALSE;
364
365     m_gestures.push_back( new_gest );
366
367     m_fullTrained = FALSE;
368     
369     return TRUE;
370
371
372
373
374 void CDynGestServer::TrainAllGestures()
375 {
376         int size = m_gestures.size();
377     for( int i = 0; i < size; i++ )
378     {
379         m_gestures[i]->Train();
380     }  
381     m_fullTrained = TRUE;
382
383 }
384
385 void CDynGesture::CreateHMM()
386 {
387     int* numix = new int[m_num_states];
388     for( int i = 0; i < m_num_states; i++ )
389     {
390         numix[i] = m_num_mix;
391     }
392     
393     icvCreate1DHMM( &m_hmm, m_num_states, numix, 6 );
394         
395 }
396
397 BOOL CDynGesture::LoadFromFile(const char *obsFilename)
398 {   
399     ASSERT(0);
400
401     return TRUE;
402 }
403
404 BOOL CDynGesture::AddParams( vector<_gr_pose>& input_vect )
405 {
406         m_Params.push_back( input_vect );
407     m_trained = FALSE;
408
409         return TRUE;
410 }
411
412 BOOL CDynGesture::SaveParams(const char* path)
413 {
414     FILE* file;
415     CString filename;
416
417     _mkdir( path );
418
419     for ( int i = 0; i < m_Params.size(); i++ )
420     {
421         vector<_gr_pose> seq = m_Params[i];
422
423         // construct name
424         filename.Format( "%s\\%s_%03d%s", path, m_name, i,".obs" );
425         file = fopen( filename, "wt");
426
427
428         for(int i = 0; i < seq.size(); i++)
429         {               
430             const fvector& ref = seq[i];
431             CvHuMoments& hu = seq[i].pose;
432             __int64 time = seq[i].time;
433             __int64 time0 = seq[0].time;
434
435                     fprintf(file, "%d %s %f %f %f %f %f %f %f %f %f %f %f %f %f\n", 
436                             long(time - time0), "*.bmp"/*LPCTSTR(mask_name)*/, ref[0], ref[1], ref[2], 
437                                                                    ref[3], ref[4], ref[5],
438                                                                                (float)hu.hu1, (float)hu.hu2, 
439                                                                    (float)hu.hu3, (float)hu.hu4, 
440                                                                    (float)hu.hu5, (float)hu.hu6,
441                                                                    (float)hu.hu7);
442         }
443         fclose(file);
444         file = 0;
445     }
446
447     return TRUE;
448 }
449
450 BOOL CDynGesture::LoadParams(const char* path)
451 {
452     //check if path exist
453     if ( _chdir( path ) < 0 )
454         return FALSE;
455
456     BOOL end = FALSE;
457     int i = 0;
458     m_Params.clear();
459         
460     while (!end)
461     {
462         CString filename;
463         FILE* file;
464         //construct file name and load
465         filename.Format( "%s_%03d%s", path, i,".obs" );
466         file = fopen( filename, "r");
467
468         if ( !file ) { end = TRUE; continue; }
469
470         //Read file
471         vector<_gr_pose> positions;
472         positions.clear();
473
474         char bmpname[256];
475
476         _gr_pose pose;
477         pose.resize(6);//construct vector of 6 elements
478
479         int int_time;
480         float hu[7];
481         //compute number of observations
482         while(fscanf(file, "%d %s %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
483                      &int_time, bmpname,  
484                      &pose[0], &pose[1], &pose[2], 
485                      &pose[3], &pose[4], &pose[5],
486                      &hu[0], &hu[1], &hu[2], &hu[3],
487                      &hu[4], &hu[5], &hu[6] )!= EOF)
488         {   
489             pose.time = int_time;
490             pose.pose.hu1 = hu[0];
491             pose.pose.hu2 = hu[1];
492             pose.pose.hu3 = hu[2];
493             pose.pose.hu4 = hu[3];
494             pose.pose.hu5 = hu[4];
495             pose.pose.hu6 = hu[5];
496             pose.pose.hu7 = hu[6]; 
497
498             positions.push_back( pose );                        
499         }
500
501         fclose(file); 
502         m_Params.push_back( positions );
503         i++;
504     }
505     if ( i == 0 ) return FALSE; 
506
507     //goto parent directory
508     _chdir("..\\" );
509
510     return TRUE;
511 }
512
513 BOOL CDynGesture::LoadSequence( const char* filename )
514 {
515         FILE* file;
516         //construct file name and load
517         file = fopen( filename, "r");
518
519         if ( !file ) return FALSE;
520
521         //Read file
522         vector<_gr_pose> positions;
523         positions.clear();
524
525         char bmpname[256];
526
527         _gr_pose pose;
528         pose.resize(6);//construct vector of 6 elements
529
530         int int_time;
531         float hu[7];
532         //compute number of observations
533         while(fscanf(file, "%d %s %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
534                      &int_time, bmpname,  
535                      &pose[0], &pose[1], &pose[2], 
536                      &pose[3], &pose[4], &pose[5],
537                      &hu[0], &hu[1], &hu[2], &hu[3],
538                      &hu[4], &hu[5], &hu[6] )!= EOF)
539         {   
540             pose.time = int_time;
541             pose.pose.hu1 = hu[0];
542             pose.pose.hu2 = hu[1];
543             pose.pose.hu3 = hu[2];
544             pose.pose.hu4 = hu[3];
545             pose.pose.hu5 = hu[4];
546             pose.pose.hu6 = hu[5];
547             pose.pose.hu7 = hu[6]; 
548
549             positions.push_back( pose );                        
550         }
551
552         fclose(file); 
553         m_Params.push_back( positions );   
554
555         m_trained = FALSE;
556         
557     return TRUE;
558 }
559
560 void CDynGesture::CleanSequences()
561 {
562     for( int i = 0; i < m_Sequences.size(); i++ )
563     {
564         cvReleaseObsInfo( &m_Sequences[i] );
565     }
566     m_Sequences.clear();
567     m_trained = FALSE;
568 }
569
570 void CDynGesture::ExtractObservations()
571 {
572         //clean all observations
573         CleanSequences();
574
575         //extract observations from parameters
576         for( int i = 0; i < m_Params.size(); i++ )
577         {
578         vector<_gr_pose>& seq = m_Params[i];
579         int seq_size = seq.size();
580         Cv1DObsInfo* obs_info = NULL;
581         
582         switch ( m_obsType )
583             {
584             case OT_VELOCITY:
585                     {
586                 seq_size--; //velocities has 1 less observation than positions
587                             m_vect_size = 3;
588                 obs_info = cvCreateObsInfo( cvSize( seq_size, 1 ), m_vect_size );
589                 int counter = 0;
590                 //construct velocities
591                 for( int j = 0; j < seq_size; j++ )
592                 {                       
593                     fvector& cur_obs = seq[j];
594                     fvector& next_obs = seq[j+1];
595                     
596                     for( int k = 0; k < 3; k++ )
597                     { 
598                         obs_info->obs[counter] = 100.f * (next_obs[k] - cur_obs[k]);
599                         counter++;
600                     }
601                 }
602             }
603             break;
604
605             case OT_VELOCITY_ORIENTATION:
606                     {
607                 seq_size--; //velocities has 1 less observation than positions
608                             m_vect_size = 6;
609                 obs_info = cvCreateObsInfo( cvSize( seq_size, 1 ), m_vect_size );
610                 int counter = 0;
611                 //construct velocities
612                 for( int j = 0; j < seq_size; j++ )
613                 {                       
614                     fvector& cur_obs = seq[j];
615                     fvector& next_obs = seq[j+1];
616                     
617                     for( int k = 0; k < 3; k++ )
618                     { 
619                         obs_info->obs[counter] = 100.f * (next_obs[k] - cur_obs[k]);
620                         counter++;
621                     }
622                     for(; k < 6; k++ )
623                     { 
624                         obs_info->obs[counter] = 10.0f * (next_obs[k] - cur_obs[k]);
625                         counter++;
626                     }
627
628                 }
629             }
630             break;
631
632         default: ASSERT(0);
633         }//switch
634         
635         // push observations 
636         m_Sequences.push_back( obs_info );
637
638     }//for
639 }   
640
641 int CDynGestServer::RecognizeDynGesture(CDynGesture *gesture, float* likelihood)
642 {
643     float likelihoodproxy[256]; //256 gestures - maximum
644     if (!likelihood) likelihood = likelihoodproxy;
645     /* recognition stage */
646
647     int num_gestures = m_gestures.size();
648     
649     for( int i = 0; i < m_gestures.size(); i++ )
650     {
651         if ( !m_gestures[i]->m_trained )
652         {
653             //AfxMessageBox( "Not all Dynamic Gestures are trained! ", MB_ICONSTOP|MB_OK, 0 );
654             return -1;
655         }
656     }
657
658     //ASSERT( m_fullTrained );//all stored gestures must be trained
659     
660     float max_like = - FLT_MAX;
661     int recognized = INT_MAX;
662     
663     ASSERT( gesture->GetSeqNumber() == 1 );
664
665     Cv1DObsInfo** obs_arr = gesture->GetSequences();
666     Cv1DObsInfo* obs = obs_arr[0];
667         
668     for( int h = 0; h < num_gestures; h++ )
669     {                          
670         CvEHMM* hmm = m_gestures[h]->GetHMM(); 
671
672         icvEstimate1DObsProb( obs, hmm );
673         
674         likelihood[h] = icvViterbi( obs, hmm );
675         
676         if (likelihood[h] > max_like )
677         {
678             max_like = likelihood[h];
679             recognized = h;
680         }
681     }
682     
683     //printf("%d-th gesture recognized as %d\n", j, image );
684     return recognized;
685 }
686
687 CvImgObsInfo** CDynGesture::GetSequences()
688 {
689    return &(m_Sequences[0]);
690 }
691
692 BOOL CDynGestServer::LoadGestureBase(const char *filename)
693 {   
694     CleanAll();
695
696     FILE* file;
697     file = fopen( filename, "r" );
698
699     if (!file ) return FALSE;
700         
701     char gesture_name[256];
702
703     //read main file
704     while ( fscanf( file, "%s\n", gesture_name )!=EOF )
705     {
706         CDynGesture* gesture = new CDynGesture( m_num_states, m_num_mix );
707         gesture->SetName( gesture_name );
708         gesture->LoadParams( gesture_name );
709         
710         //try to load hmm
711         if ( ! _chdir( gesture->GetName() ) )
712         {
713             if ( gesture->LoadHMM(gesture->GetName() + ".hmm") )
714             {
715                 gesture->m_trained = TRUE;
716                 //change value of m_hmmParams control
717                 CStereoGRApp* app = (CStereoGRApp*)AfxGetApp();
718                 app->m_hmmParams->m_num_states = gesture->GetHMM()->num_states;
719                 app->m_hmmParams->m_num_mix = gesture->GetHMM()->u.state->num_mix;
720                 SetHMMParams( app->m_hmmParams->m_num_states,
721                               app->m_hmmParams->m_num_mix );
722
723             }
724         
725             _chdir( "..\\" );
726         }        
727                 
728         AddGesture( gesture );         
729     }                          
730     fclose( file );
731     m_loaded_base = filename;
732     return TRUE; 
733 }
734
735 BOOL CDynGestServer::SaveGestureBase(const char *name)
736 {   
737     FILE* file;
738     file = fopen( name, "wt" );
739
740     for( int i = 0; i < m_gestures.size(); i++ )
741     {
742         CDynGesture* gesture = m_gestures[i];
743         fprintf( file, "%s\n", gesture->GetName() );
744         gesture->SaveParams( gesture->GetName() );
745         if ( gesture->m_trained )
746         {
747             _chdir( gesture->GetName() );
748             gesture->SaveHMM(gesture->GetName() + ".hmm");
749             _chdir( "..\\" );            
750         }
751     } 
752
753     fclose( file );
754
755     m_loaded_base = name;
756  
757     return TRUE;   
758 }
759
760 void CDynGestServer::CleanAll()
761 {
762     for( int i = 0; i < m_gestures.size(); i++ )
763         delete m_gestures[i];
764     m_gestures.clear();
765
766     m_fullTrained = false;
767
768 }
769
770 void CDynGestServer::SetHMMParams( int num_state, int num_mix )
771 {
772     if ( m_num_states != num_state || m_num_mix != num_mix )
773     {
774         m_num_states = num_state;
775         m_num_mix    = num_mix;
776         //change every gesture params
777         for( int i = 0; i < m_gestures.size(); i++ )
778         {
779             m_gestures[i]->m_num_mix = num_mix;
780             m_gestures[i]->m_num_states = num_state;
781             m_gestures[i]->m_trained = FALSE;
782             m_gestures[i]->DestroyHMM();
783         }
784         m_fullTrained = FALSE;
785     }
786 }
787
788 BOOL CDynGestServer::RemoveGesture( const char* name )
789 {   
790     for( vector<CDynGesture*>::iterator it = m_gestures.begin(); it < m_gestures.end(); it++ )
791     {
792         if ( (*it)->GetName() == name )
793         {
794             m_gestures.erase( it );
795             return TRUE;
796         }
797     }
798     return FALSE;
799 }
800
801
802 void CDynGesture::DestroyHMM()
803 {
804     if (m_hmm) icvRelease1DHMM( &m_hmm );
805     m_trained = FALSE;
806 }   
807
808
809 void CDynGestServer::DeleteHMMInfo()
810 {
811     for( int i = 0; i < m_gestures.size(); i++ )
812     {
813         m_gestures[i]->DeleteHMM();
814         if( !_chdir( m_gestures[i]->GetName() ) )
815         {
816             remove( m_gestures[i]->GetName() + ".hmm" );
817             _chdir( "..\\" );
818         }                    
819     }
820     m_fullTrained = FALSE;
821 }
822
823 void CDynGesture::DeleteHMM()
824 {
825     icvRelease1DHMM( &m_hmm );
826     m_trained = FALSE;
827 }