Move the sources to trunk
[opencv] / apps / HMMDemo / FaceBase.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*/// FaceBase.cpp: implementation of the CFaceBase class.
41 //
42 //////////////////////////////////////////////////////////////////////
43
44 #include "stdafx.h"
45 #include "MainFrm.h"
46
47 #include "HMMDemo.h"
48 #include "FaceBase.h"
49 #include "direct.h"
50 #include <math.h>
51 #include <float.h>
52 #include <process.h>
53
54 #ifdef _DEBUG
55 #undef THIS_FILE
56 static char THIS_FILE[]=__FILE__;
57 #define new DEBUG_NEW
58 #endif
59
60 // globals
61 static const char* base_signature = "FACE DATABASE\n";
62 static const char* person_signature = "PERSONAL INFO\n";
63
64 void ConvertNameToFolder( const char* name, char* folder )
65 {
66     int i, j = 0;
67     int len = strlen(name);
68
69     for( i = 0; i < len; i++ )
70     {
71         if( name[i] == ' ' )
72         {
73             if( j == 0 || folder[j-1] != '.' )
74             {
75                 folder[j++] = '.';
76             }
77         }
78         else
79         {
80             folder[j++] = name[i];
81         }
82     }
83
84     folder[j] = '\0';
85 }
86
87
88 /***************************************************************************************\
89                Face data base structure:
90
91     <root_folder>\
92         <person_folder_1>\
93              <image_11>
94              <image_12>
95              <image_13>
96              ...
97              info.txt
98         <person_folder_2>\
99              <image_21>
100              <image_22>
101              <image_23>
102              ...
103              info.txt
104         <person_folder_3>\
105              <image_21>
106              <image_22>
107              <image_23>
108              ...
109              info.txt
110         ...
111         <index_file>
112
113    ( names in <> brackets can be arbitrary ).
114    e.g.
115
116      NNBase\
117         Abrosimov.Dmirty\
118             ad_1.bmp
119             ad_near_window.bmp
120             ad_smiling.bmp
121             index.txt
122         Oblomov.Sergey\
123             serg.bmp
124             photo_3.bmp
125             index.txt
126         NNBaseIndex.txt
127
128     Main base index file contains name of the base followed by list of personal folders.
129     Format is the following:
130
131     line            content
132     --------------------------------
133      1           FACE DATABASE           (signature)
134      2           base name/description
135      3           <empty line>
136      4           <person_folder1>
137      5           <person_folder2>
138     ...                ...
139
140     In every personal folder there is a file with predefined name: info.txt
141     It contains person name followed by list of images for that person.
142
143     line            content
144     --------------------------------
145      1           PERSONAL INFO           (signature)
146      2           person name/description
147      3           <empty line>
148      4           <image_name1>
149      5           [<roi1>]
150      6           <image_name2>
151      7           [<roi2>]
152     ...          ...
153
154     Every image name may be followed by four numbers which are represent coordinates of
155     top-left corner of the face rectangle in the image and width and height
156     of the rectnagle, if no roi is specified, the entire image is considered as a face.
157
158     lines, started with #, are comments, and skipped when file is readed.
159
160 \***************************************************************************************/
161
162 static char* chomp( char* str )
163 {
164     int l = strlen( str );
165     if( l > 0 && str[l-1] == '\n' )
166     {
167         str[l-1] = '\0';
168     }
169     return str;
170 }
171
172 const int STR_BUF_SIZE = 1000;
173
174 /****************************************************************************************\
175 *                                  CFaceBase  class                                      *
176 \****************************************************************************************/
177
178 // CFaceBase
179 CFaceBase::CFaceBase()
180 {
181     //default parameters
182     m_stnum[0] = 5;
183     m_stnum[1] = 3;
184     m_stnum[2] = 6;
185     m_stnum[3] = 6;
186     m_stnum[4] = 6;
187     m_stnum[5] = 3;
188     for( int i = 0; i < 128; i++ )
189     {
190         m_mixnum[i] = 3;
191     }
192         
193     m_modified = false;
194     m_trained_index = -1;
195     m_base_view = 0;
196     SetImageSize( CSize(100,120) );
197
198     m_delta = cvSize(4,4);
199     m_obsSize = cvSize(3,3);
200     m_dctSize = cvSize(12,12);
201
202     m_useWidth = FALSE;
203     m_useHeight = FALSE;
204     m_scaleWidth = 0;
205     m_scaleHeight = 0;
206     m_suppress_intensity = FALSE;
207         
208 }
209
210 CFaceBase::~CFaceBase()
211 {
212     Unload();
213 }
214
215
216 void  CFaceBase::SetFileName( const CString& filename )
217 {
218     m_filename = filename;
219     SetModified();
220 }
221
222
223 void  CFaceBase::SetName( const CString& name )
224 {
225     m_basename = name;
226     SetModified();
227 }
228
229
230 void  CFaceBase::GetRootFolder( char* root_folder, int* root_path_len )
231 {
232     char buffer[STR_BUF_SIZE];
233     
234     // construct root folder path
235     _splitpath( m_filename, root_folder, buffer, 0, 0 );
236     strcat( root_folder, buffer );
237     if( root_path_len ) *root_path_len = strlen( root_folder );
238 }
239
240
241 bool  CFaceBase::GetPersonFolder( const char* root_folder, int root_folder_len,
242                                   const char* person_folder, char* folder )
243 {
244     char buffer[STR_BUF_SIZE];
245     char drive[STR_BUF_SIZE];
246     int  len;
247
248     strcpy( buffer, person_folder );
249
250     len = strlen( buffer );
251     if( len == 0 ) return false;
252     
253     // add slash (if absent)
254     if( buffer[len-1] != '\\')
255     {
256         buffer[len] = '\\';
257         buffer[len+1] = '\0';
258     }
259
260     _splitpath( buffer, drive, 0, 0, 0 );
261     if( strlen( drive ) > 0 ) return false;
262
263     if( root_folder != folder )
264     {
265         strcpy( folder, root_folder );
266     }
267
268     strcpy( folder + root_folder_len, buffer );
269     return true;
270 }
271
272
273 void  CFaceBase::GetPersonSubFolder( const char* folder, char* subfolder )
274 {
275     char buffer[STR_BUF_SIZE];
276     char name[STR_BUF_SIZE];
277     char ext[STR_BUF_SIZE];
278
279     strcpy( buffer, folder );
280     
281     ASSERT( buffer[strlen(buffer)-1] == '\\' );
282
283     // delete slash
284     buffer[strlen(buffer)-1] = '\0';
285
286     _splitpath( buffer, 0, 0, name, ext );
287     
288     strcpy( subfolder, name );
289     strcat( subfolder, ext );
290 }
291
292
293 bool  CFaceBase::Load()
294 {
295     FILE* f = 0;
296     char buffer[STR_BUF_SIZE];
297     char root_folder[STR_BUF_SIZE];
298     int  root_path_len;
299     bool error = false;
300
301     if( m_filename.GetLength() == 0 ) return false;
302
303     f = fopen( m_filename, "rt" );
304     if( !f ) return false;
305     
306     m_base.RemoveAll();
307     
308     if( !fgets( buffer, STR_BUF_SIZE, f ) || strcmp( buffer, base_signature ))
309         return false;
310
311     // read header
312     if( !fgets( buffer, STR_BUF_SIZE, f )) return false;
313
314     m_basename = chomp( buffer );
315
316     // construct root folder path
317     GetRootFolder( root_folder, &root_path_len );
318
319     // skip one line after the base name
320     fgets( buffer, STR_BUF_SIZE, f );
321
322     // load all the people data
323     for(;;)
324     {
325         CPerson* person;
326         if( !fgets( buffer,STR_BUF_SIZE, f )) break;
327
328         if( strlen(buffer) == 0 || buffer[0] == '#' ) continue;
329         chomp( buffer );
330
331         if( !GetPersonFolder( root_folder, root_path_len, buffer, root_folder ))
332             continue;
333
334         person = new CPerson( this );
335
336         person->SetFolder( root_folder );
337         if( !person->Load() )
338         {
339             delete person;
340             error = true;
341             continue;
342         }
343         m_base.AddTail( person );
344     }    
345
346     fclose(f);
347     SetModified( error );
348     return true;
349 }
350
351
352 void  CFaceBase::Unload()
353 {
354     Save();
355     while( !m_base.IsEmpty() )
356     {
357         CPerson* person = m_base.RemoveHead();
358         delete person;
359     }
360 }
361
362 bool  CFaceBase::Save()
363 {
364     if( m_filename.GetLength() > 0 )
365     {
366         POSITION pos = m_base.GetHeadPosition();
367         while( pos )
368         {
369             CPerson* person = m_base.GetNext( pos );
370             person->Save();
371         }
372
373         if( IsModified() )
374         {
375             FILE* f = fopen( m_filename, "wt" );
376             char  subfolder[STR_BUF_SIZE];
377             if( !f ) return false;
378
379             fputs( base_signature, f );
380             fputs( m_basename, f );
381             fputs( "\n\n", f );
382
383             pos = m_base.GetHeadPosition();
384
385             while( pos )
386             {
387                 CPerson* person = m_base.GetNext( pos );
388                 const CString& str = person->GetFolder();
389                 GetPersonSubFolder( str, subfolder );
390                 fprintf( f, "%s\n", subfolder );
391             }
392             fclose(f);
393         }
394         SetModified(false);
395
396         //save config file 
397         CString cfg_name;
398         cfg_name = GetFileName();
399         cfg_name.Replace( ".txt", "CFG.txt" );
400             
401         //save parameters (HMM, Sampling etc.) for whole application
402         CHMMDemoApp* app = (CHMMDemoApp*)AfxGetApp();
403         
404         //check if any trained person
405         BOOL save_config = TRUE;//FALSE;
406         /*for( int i = 0; i < m_base.GetPersonList().GetCount(); i++ )
407         {
408             CPerson* person = m_base.GetPerson(i);
409             if ( person->IsTrained() )
410             {
411                 save_config = TRUE;
412                 break;
413             }
414         }*/
415         if ( save_config ) app->SaveConfig( cfg_name );
416         else remove( cfg_name ); 
417
418
419     }
420     return true;
421 }
422
423
424 CPerson*  CFaceBase::AddPerson( const char* name, const char* folder, bool import_data )
425 {
426     char temp_folder[STR_BUF_SIZE];
427     char root_folder[STR_BUF_SIZE];
428     CPerson* person = 0;
429     int len;
430
431     if( !import_data )
432     {
433         ASSERT( strlen( name ) > 0 );
434         if( !folder )
435         {
436             ConvertNameToFolder( name, temp_folder );
437             folder = temp_folder;
438         }
439     }
440     else
441     {
442         ASSERT( strlen( folder ) > 0 && name == 0 );
443     }
444     
445     GetRootFolder( root_folder, &len );
446     GetPersonFolder( root_folder, len, folder, root_folder );
447
448     person = new CPerson( this );
449     person->SetFolder( root_folder );
450     if( import_data )
451     {
452         if( !person->Load())
453         {
454             delete person;
455             person = 0;
456         }
457     }
458     else
459     {
460         _mkdir( root_folder );
461         person->SetName( name );
462         person->SetModified();
463     }
464
465     if( person )
466     {
467         m_base.AddTail( person );
468         SetModified();
469     }
470     return person;
471 }
472
473
474 void  CFaceBase::RemovePerson( POSITION pos )
475 {
476     CPerson* person = m_base.GetAt( pos );
477     if( person )
478     {
479         person->Unload();
480         m_base.RemoveAt( pos );
481         delete person;
482         SetModified();
483     }
484 }
485
486
487 void  CFaceBase::SetImageSize( CSize size )
488 {
489     m_baseImgSize = size;
490     SetModified();
491 }
492
493
494 CPerson*  CFaceBase::GetPerson( int index )
495 {
496     ASSERT( index >= 0 );
497     POSITION pos = m_base.FindIndex( index );
498     return pos ? m_base.GetAt( pos ) : 0;
499 }
500
501
502 CPerson*  CFaceBase::FindPersonByName( const CString& name )
503 {
504     POSITION pos = m_base.GetHeadPosition();
505
506     while( pos )
507     {
508         CPerson* person = m_base.GetNext(pos);
509         if( person && name.CompareNoCase( person->GetName()) == 0 ) return person;
510     }
511     return 0;
512 }
513
514
515 int  CFaceBase::GetPersonIndex( CPerson* person )
516 {
517     POSITION pos = m_base.GetHeadPosition();
518     int i;
519
520     for( i = 0; pos != 0; i++ )
521     {
522         CPerson* p = m_base.GetNext(pos);
523         if( p == person ) return i;
524     }
525
526     return -1;
527 }
528
529
530 void  CFaceBase::Draw( int index, CImage& img, SIZE win_size, int y_pos,
531                        SIZE base_size, SIZE delta )
532 {
533     ASSERT( delta.cx > base_size.cx && delta.cy > base_size.cy );
534     
535     int  nx = MAX((win_size.cx + delta.cx - base_size.cx)/delta.cx,1);
536     int  row = y_pos/delta.cy;
537     int  idx0 = row*nx;
538     int  x, y;
539     POSITION pos;
540     CPersonImgList* list = 0;
541     int  count;
542
543     if( index >= 0 )
544     {
545         CPerson* person = GetPerson( index );
546         if( !person ) return;
547
548         list = &person->GetImgList();
549         count = list->GetCount();
550     }
551     else
552     {
553         count = m_base.GetCount();
554     }
555
556     if( !img.GetImage() || idx0 >= count ) return;
557
558     if( list )
559     {
560         pos = list->FindIndex( idx0 );
561     }
562     else
563     {
564         pos = m_base.FindIndex( idx0 );
565     }
566
567     for( y = row*delta.cy - y_pos + (delta.cy - base_size.cy)/2;
568          y < win_size.cy ; y += delta.cy )
569     {
570         for( x = (delta.cx - base_size.cx)/2; ; )
571         {
572             CPersonImage* src_img = 0;
573             if( list )
574             {
575                 src_img = list->GetNext( pos );
576             }
577             else
578             {
579                 CPerson* person = m_base.GetNext( pos );
580                 if( person )
581                 {
582                     CPersonImgList& l = person->GetImgList();
583                     if( !l.IsEmpty())
584                     {
585                         src_img = l.GetHead();
586                     }
587                 }
588             }
589             
590             if( src_img )
591             {
592                 src_img->Draw( img, win_size, CPoint( x, y ), base_size );
593             }
594             if( !pos ) return;
595
596             x += delta.cx;
597             if( x + base_size.cx > win_size.cx ) break;
598         }
599     }
600 }
601
602
603 void  CFaceBase::UpdateTrainedImage()
604 {
605     if( m_base_view )
606     {
607         m_base_view->InvalidateRect(0);
608         m_base_view->UpdateWindow();
609     }
610 }
611
612
613 void  CFaceBase::DeleteHMMInfo()
614 {
615     POSITION pos = m_base.GetHeadPosition();
616
617     while( pos )
618     {
619         CPerson* person = m_base.GetNext(pos);
620         if( person )
621         {
622             person->DeleteHMMInfo();
623         }
624     }
625 }
626
627
628 /****************************************************************************************\
629 *                                  CPerson class                                         *
630 \****************************************************************************************/
631
632 CPerson::CPerson( CFaceBase* parent )
633 {
634     m_modified = false;
635     m_trained  = false;
636     m_parent = parent;
637     ASSERT( parent != 0 );
638 }
639
640 CPerson::~CPerson()
641 {
642     Unload();
643 }
644
645
646 void   CPerson::SetName( const CString& name )
647 {
648     m_name = name;
649     SetModified();
650 }
651
652
653 void  CPerson::SetFolder( const CString& folder )
654 {
655     m_folder = folder;
656     SetModified();
657 }
658
659
660 bool  CPerson::GetPersonFullImageName( const char* root, int root_len,
661                                        const char* image, char* full_image_name )
662 {
663     char buffer[STR_BUF_SIZE];
664     char drive[STR_BUF_SIZE];
665     int  len;
666
667     strcpy( buffer, image );
668
669     len = strlen( buffer );
670     if( len == 0 ) return false;
671     
672     _splitpath( buffer, drive, 0, 0, 0 );
673     if( strlen( drive ) > 0 ) return false;
674
675     if( root != full_image_name )
676     {
677         strcpy( full_image_name, root );
678     }
679
680     strcpy( full_image_name + root_len, buffer );
681     return true;
682 }
683
684
685 void  CPerson::ExtractPersonImageName( const char* full_image_name, char* image )
686 {
687     char buffer[STR_BUF_SIZE];
688     char name[STR_BUF_SIZE];
689     char ext[STR_BUF_SIZE];
690
691     strcpy( buffer, full_image_name );
692     
693     _splitpath( buffer, 0, 0, name, ext );
694     
695     strcpy( image, name );
696     strcat( image, ext );
697 }
698
699
700 bool  CPerson::Load()
701 {
702     FILE* f = 0;
703     char buffer[STR_BUF_SIZE];
704     char root[STR_BUF_SIZE];
705     int  root_len;
706     bool error = false;
707     CPersonImage* image = 0;
708     RECT roi;
709     bool already_read = false;
710
711     strcpy( root, m_folder );
712     root_len = m_folder.GetLength();
713     strcpy( root + root_len, "info.txt" );
714
715     f = fopen( root, "rt" );
716     if( !f ) return false;
717     
718     m_imgs.RemoveAll();
719     
720     // read header
721     if( !fgets( buffer, STR_BUF_SIZE, f ) || strcmp(buffer,person_signature))
722         return false;
723
724     if( !fgets( buffer, STR_BUF_SIZE, f ))
725         return false;
726
727     m_name = chomp( buffer );
728
729     // skip one line after the base name
730     fgets( buffer, STR_BUF_SIZE, f );
731
732     // create image list for the person and load the first image
733     for(;;)
734     {
735         if( !already_read && !fgets( buffer,STR_BUF_SIZE, f )) break;
736
737         already_read = false;
738         if( strlen(buffer) == 0 || buffer[0] == '#' ) continue;
739         chomp( buffer );
740
741         if( !GetPersonFullImageName( root, root_len, buffer, root ))
742             continue;
743
744         image = new CPersonImage;
745         image->SetFileName( root );
746
747         /* read ROI coordinates */
748         while( fgets( buffer,STR_BUF_SIZE, f ))
749         {
750             if( strlen(buffer) > 0 && buffer[0] == '#' ) continue;
751             already_read = true;
752             if( sscanf( buffer, "%u%u%u%u", &roi.left, &roi.top,
753                         &roi.right, &roi.bottom ) == 4 )
754             {
755                 roi.right += roi.left;
756                 roi.bottom += roi.top;
757                 image->SetRoiInFile( roi );
758                 already_read = false;
759             }
760             break;
761         }
762
763         if( m_imgs.IsEmpty() && !image->Load() )
764         {
765             delete image;
766             error = true;
767             continue;
768         }
769         m_imgs.AddTail( image );
770     }
771
772     fclose(f);
773
774     //load hmm if present
775     strcpy( root + root_len, "hmm.txt" );
776     f = fopen(root,"rt");
777     if( !f ) m_trained = false;
778     else
779     {
780         fclose(f);
781         SetModified( error );
782         m_trained = m_hmm.Load( root );
783     }
784
785     return true;
786 }
787
788
789 void  CPerson::Unload()
790 {
791     Save();
792     while( !m_imgs.IsEmpty() )
793     {
794         CPersonImage* image = m_imgs.RemoveHead();
795         delete image;
796     }
797 }
798
799
800 bool  CPerson::Save()
801 {
802     if( IsModified() )
803     {
804         char buffer[STR_BUF_SIZE];
805
806         POSITION pos = m_imgs.GetHeadPosition();
807         while( pos )
808         {
809             CPersonImage* image = m_imgs.GetNext( pos );
810             image->Save();
811         }
812
813         strcpy( buffer, m_folder );
814         strcat( buffer, "info.txt" );
815     
816         FILE* f = fopen( buffer, "wt" );
817         if( !f ) return false;
818
819         fputs( person_signature, f );
820         fputs( m_name, f );
821         fputs( "\n\n", f );
822
823         pos = m_imgs.GetHeadPosition();
824
825         // write image names and ROI coordinates
826         while( pos )
827         {
828             CPersonImage* image = m_imgs.GetNext( pos );
829             const CString& str = image->GetFileName();
830             CRect r = image->GetRoiInFile();
831             ExtractPersonImageName( str, buffer );
832             fprintf( f, "%s\n", buffer );
833             if( !r.IsRectEmpty() )
834             {
835                 fprintf(f, "%5u%5u%5u%5u\n", r.left, r.top, r.Width(), r.Height() );
836             }
837         }
838         fclose(f);
839     }
840
841     if (IsTrained())
842     {
843         char buffer[STR_BUF_SIZE];
844
845         //save hmm         
846         strcpy( buffer, m_folder );
847         strcat( buffer, "hmm.txt" );
848         
849         m_hmm.Save( buffer );
850     }
851     else
852     {
853        char buffer[STR_BUF_SIZE];
854        strcpy( buffer, m_folder );
855        strcat( buffer, "hmm.txt" );        
856        remove( buffer );
857     }
858
859     SetModified(false);
860
861     return true;
862 }
863
864
865 void  CPerson::LoadRest()
866 {
867     // load all the face images starting from second (first is always loaded)
868     POSITION pos = m_imgs.FindIndex(1);
869
870     while( pos )
871     {
872         POSITION tmp_pos = pos;
873         CPersonImage* image = m_imgs.GetNext( pos );
874         if( !image->Load())
875         {
876             m_imgs.RemoveAt(tmp_pos);
877             SetModified();
878             delete image;
879         }
880     }
881 }
882
883
884 void  CPerson::UnloadRest()
885 {
886     // load all the face images starting from second (first is always loaded)
887     POSITION pos = m_imgs.FindIndex(1);
888
889     while( pos )
890     {
891         CPersonImage* image = m_imgs.GetNext( pos );
892         image->Unload();
893     }
894 }
895
896
897 void  CPerson::GenerateFileName( const char* base, char* filename )
898 {
899     char path[STR_BUF_SIZE];
900     int base_len = base ? strlen(base) : 0;
901     int i = 0;
902
903     if( base_len > 0 )
904     {
905         strcpy( filename, base );
906     }
907     else
908     {
909         char ext[STR_BUF_SIZE];
910         strcpy( path, m_folder );
911         // remove slash
912         path[m_folder.GetLength()-1] = '\0';
913         // use folder name as a base
914         _splitpath( path, 0, 0, filename, ext );
915         strcat( filename, ext );
916         base_len = strlen( filename );
917     }
918     
919     for(;;)
920     {
921         FILE* f = 0;
922         for( ; i < 10000; i++ )
923         {
924             GetPersonFullImageName( m_folder, m_folder.GetLength(), filename, path );
925             sprintf( path + strlen(path), "%04d.bmp", i );
926             f = fopen( path, "rb" );
927             if( !f ) break;
928             fclose(f);
929         }
930         if( i == 10000 )
931         {
932             ASSERT(0);
933             return;
934         }
935
936         // try to open for writing. If success, output name
937         f = fopen( path, "wb" );
938         if( !f ) continue;
939
940         fclose(f);
941         remove( path );
942         strcpy( filename, path );
943         break;
944     }
945 }
946
947 void NormalizeIntensity(IplImage* ipl_image, int level)
948 {
949     CvSize roi;
950     int step;
951     uchar* img;
952     
953     ASSERT( (level>0) && (level <=255) );
954     cvGetImageRawData(ipl_image, &img, &step, &roi);
955     
956     int width = roi.width;
957     int height = roi.height;
958
959     int mean = (int)cvMean( ipl_image );
960     // normalize to 128
961     for( int i = 0; i < height; i++, img+=step )
962     {
963         for( int j = 0; j < width; j++ )
964         {
965             int newval = img[j] + level - mean;
966             newval = (newval < 0) ? 0 : newval;
967             newval = (newval > 255) ? 255 : newval;                                          
968             img[j] = newval;
969         }
970     }  
971 }
972
973 void NormalizeImageForHMM( IplImage* ipl_scaled, IplImage* normalized_image )
974 {
975         //iplFixedFilter( ipl_scaled, normalized_image, IPL_SOBEL_3x3_H );
976 }
977
978 void ExtractDCT( float* src, float* dst, int num_vec, int dst_len )
979 {
980     float* src_ = src+1;
981     float* dst_ = dst;
982
983     for( int i = 0; i < num_vec; i++ )
984     {
985         memcpy( dst_, src_, dst_len * sizeof(float) );
986         src_+= dst_len+1;
987         dst_+= dst_len;
988     }
989 }                            
990                 
991
992 void  CPerson::AddImage( const char* filename, CImage* import_image, CRect rect )
993 {
994     char root[STR_BUF_SIZE];
995     CPersonImage* image;
996     int root_len;
997
998     strcpy( root, m_folder );
999     root_len = m_folder.GetLength();
1000
1001     if( !filename )
1002     {
1003         ASSERT( import_image != 0 );
1004         GenerateFileName( 0, root );
1005     }
1006     else
1007     {
1008         GetPersonFullImageName( root, root_len, filename, root );
1009     }
1010
1011     image = new CPersonImage;
1012     image->SetFileName( root );
1013
1014     if( import_image )
1015     {
1016         CImage& dst_img = image->GetImage();
1017         IplImage* src_img = import_image->GetImage();
1018         IplROI* temp_roi;
1019         IplROI  roi;
1020         ASSERT( src_img != 0 );
1021
1022         temp_roi = src_img->roi;
1023     
1024         if( rect.IsRectEmpty() )
1025         {
1026             src_img->roi = 0;
1027         }
1028         else
1029         {
1030             src_img->roi = &roi;
1031             roi = RectToROI( rect );
1032         }
1033
1034         dst_img.CopyOf( *import_image, 0 );
1035         src_img->roi = temp_roi;
1036         image->SetRoiInFile( CRect(0,0,0,0));
1037         image->SetModified();
1038
1039         // to reserve file name
1040         image->Save();
1041     }
1042     else
1043     {
1044         image->SetRoiInFile( rect );
1045         image->Load();
1046     }
1047
1048     m_imgs.AddTail( image );
1049     SetModified();
1050 }
1051
1052
1053 void  CPerson::RemoveImage( POSITION pos )
1054 {
1055     CPersonImage* image = m_imgs.GetAt( pos );
1056     if( image )
1057     {
1058         m_imgs.RemoveAt( pos );
1059         image->Unload();
1060         remove( image->GetFileName() );
1061         delete image;
1062         SetModified();
1063     }
1064 }
1065
1066
1067 void  CPerson::MoveToTop( POSITION pos )
1068 {
1069     CPersonImage* image = m_imgs.GetAt( pos );
1070     if( image )
1071     {
1072         m_imgs.RemoveAt( pos );
1073         CPersonImage* old_head = m_imgs.GetHead();
1074         if( old_head ) old_head->Unload();
1075         m_imgs.AddHead( image );
1076         image->Load();
1077         SetModified( true );
1078     }
1079 }
1080
1081
1082 void CPerson::DeleteHMMInfo()
1083 {
1084     m_trained = false;
1085     CString str = GetFolder() + "hmm.txt";
1086     remove( str );
1087 }
1088
1089 void LightingCorrection(IplImage* ipl_image)
1090 {
1091     CvSize roi;
1092     int step;
1093     uchar* img;
1094     
1095     cvGetImageRawData(ipl_image, &img, &step, &roi);
1096     
1097     int i, j;
1098     int width = roi.width;
1099     int height = roi.height;
1100     
1101     float x1, x2, y1, y2;
1102     int f[3] = {0, 0, 0};
1103     float a[3] = {0, 0, 0};
1104     
1105     float h1;
1106     float h2;
1107     
1108     float c1,c2;
1109     
1110     float min = FLT_MAX;
1111     float max = -FLT_MAX;
1112     float correction;
1113     
1114     float* float_img = (float*)malloc( width * height * sizeof(float) );
1115     
1116     x1 = width * (width + 1) / 2.0f; // Sum (1, ... , width)
1117     x2 = width * (width + 1 ) * (2 * width + 1) / 6.0f; // Sum (1^2, ... , width^2)
1118     y1 = height * (height + 1)/2.0f; // Sum (1, ... , width)
1119     y2 = height * (height + 1 ) * (2 * height + 1) / 6.0f; // Sum (1^2, ... , width^2)
1120     
1121     
1122     // extract grayvalues
1123     for (i = 0; i < height; i++)
1124     {
1125         for (j = 0; j < width; j++)
1126         {
1127             f[2] = f[2] + j * img[i*step + j];
1128             f[1] = f[1] + i * img[i*step + j];
1129             f[0] = f[0] +     img[i*step + j];
1130         }
1131     }
1132     
1133     h1 = (float)f[0] * (float)x1 / (float)width;
1134     h2 = (float)f[0] * (float)y1 / (float)height;
1135     
1136     a[2] = ((float)f[2] - h1) / (float)(x2*height - x1*x1*height/(float)width);
1137     a[1] = ((float)f[1] - h2) / (float)(y2*width - y1*y1*width/(float)height);
1138     a[0] = (float)f[0]/(float)(width*height) - (float)y1*a[1]/(float)height - 
1139         (float)x1*a[2]/(float)width;
1140     
1141     for (i = 0; i < height; i++) 
1142     {    
1143         for (j = 0; j < width; j++)
1144         {
1145             
1146             correction = a[0] + a[1]*(float)i + a[2]*(float)j;
1147             
1148             float_img[i*width + j] = img[i*step + j] - correction;
1149             
1150             if (float_img[i*width + j] < min) min = float_img[i*width+j];
1151             if (float_img[i*width + j] > max) max = float_img[i*width+j];
1152         }
1153     }
1154     
1155     //rescaling to the range 0:255
1156     c2 = 0;
1157     if (max == min)
1158         c2 = 255.0f;
1159     else
1160         c2 = 255.0f/(float)(max - min);
1161     
1162     c1 = (-(float)min)*c2;
1163     
1164     for (i = 0; i < height; i++)
1165     {
1166         for (j = 0; j < width; j++)
1167         {
1168             int value = (int)floor(c2*float_img[i*width + j] + c1);
1169             if (value < 0) value = 0;
1170             if (value > 255) value = 255;
1171             img[i*step + j] = (uchar)value;
1172         }
1173     }
1174     
1175     free( float_img );
1176     
1177 }
1178
1179 void CPerson::TrainHMM()
1180 {
1181
1182     int color[24] = { RGB(255,128,128), RGB(255,255,128), RGB(128,255,128), RGB(128,255,255), RGB(0,128,255),
1183                       RGB(255,128,255), RGB(255,0,0), RGB(255,128,0), RGB(0,128,0), RGB(0,0,0), RGB(255,255,128),
1184                       RGB(255,0,128), RGB(255,128,128), RGB(255,255,128),RGB(128,255,128), RGB(128,255,255),
1185                       RGB(0,128,255),RGB(255,128,255),RGB(255,0,0),RGB(255,128,0),RGB(0,128,0), 
1186                       RGB(0,0,0),RGB(255,255,128), RGB(255,0,128)  };
1187
1188     //training loop can be not converged
1189     const int max_iterations = 80;    
1190
1191     CFaceBase* parent = GetParentBase();
1192     //CImage& segmentation = parent->GetTrainedImage();
1193     //segmentation.Create( 320, 320, 24 );
1194
1195     int vect_len = parent->m_obsSize.height*parent->m_obsSize.width;
1196
1197     //suppress first DCT coefficient
1198     if( parent->m_suppress_intensity)
1199     {
1200         vect_len--;
1201     }
1202
1203     CvEHMM* hmm = m_hmm.GetIppiEHMM();
1204     if (!hmm) m_hmm.CreateHMM( parent->m_stnum, parent->m_mixnum, vect_len );
1205
1206     hmm = m_hmm.GetIppiEHMM();
1207
1208     //Create observation info
1209     int num_img = m_imgs.GetCount();
1210
1211     
1212     CArray< CvImgObsInfo* , CvImgObsInfo* > obs_info;   
1213     obs_info.SetSize( num_img );
1214
1215     CvImgObsInfo** obs_info_array = obs_info.GetData();
1216
1217     for( int i = 0; i < num_img; i++ )
1218     {
1219         POSITION pos = m_imgs.FindIndex(i);
1220         IplImage* ipl = m_imgs.GetAt(pos)->GetImage().GetImage();
1221
1222         bool doRescale = false;
1223         
1224         int new_height = 0;
1225         int new_width = 0;
1226  
1227         if ( parent->m_useWidth )
1228         {
1229             doRescale = true;
1230             new_width = parent->m_scaleWidth;
1231         }
1232         if ( parent->m_useHeight )
1233         {
1234             doRescale = true;
1235             new_height = parent->m_scaleHeight;
1236         }
1237         //recompute width or height if any is absent
1238         IplImage* ipl_scaled;
1239       
1240         CvSize image_roi = cvSize( ipl->roi ? ipl->roi->width : ipl->width, 
1241                                    ipl->roi ? ipl->roi->height : ipl->height );
1242
1243         if ( doRescale )
1244         {
1245             if ( !new_width )
1246             {
1247                 new_width  = new_height * image_roi.width / image_roi.height;
1248             }
1249             else if ( !new_height ) 
1250             {
1251                 new_height  = new_width * image_roi.height / image_roi.width;
1252             }
1253
1254             //rescale
1255             ipl_scaled = cvCreateImage( cvSize(new_width, new_height), IPL_DEPTH_8U, 1 );
1256                 
1257             cvResize(ipl, ipl_scaled, /*ipl_scaled->width, ipl->width, 
1258                       ipl_scaled->height, ipl->height,*/ CV_INTER_NN);
1259                 
1260         }
1261         else
1262             ipl_scaled = ipl;
1263
1264         CvSize roi = cvSize( ipl_scaled->roi ? ipl_scaled->roi->width : ipl_scaled->width,
1265                                ipl_scaled->roi ? ipl_scaled->roi->height : ipl_scaled->height);
1266
1267
1268         CvSize num_obs;
1269
1270         CV_COUNT_OBS( &roi, &(parent->m_dctSize), &(parent->m_delta), &num_obs ); 
1271
1272               
1273         obs_info_array[i] = cvCreateObsInfo( num_obs, vect_len );
1274
1275         CvImgObsInfo* info = obs_info_array[i];
1276                
1277         //IplImage* normalized_image = cvCreateImage( roi, IPL_DEPTH_8U, 1 );
1278         //NormalizeImageForHMM( ipl_scaled, normalized_image );
1279
1280         if( parent->m_suppress_intensity )
1281         {
1282             float* observations = (float*)malloc( num_obs.height * num_obs.width * (vect_len+1) * sizeof(float) );
1283             cvImgToObs_DCT( /*normalized_image*/ipl_scaled, observations, parent->m_dctSize, parent->m_obsSize, parent->m_delta );
1284             ExtractDCT( observations, info->obs, num_obs.height * num_obs.width, vect_len );
1285             free( observations);
1286         }
1287         else
1288         {
1289             cvImgToObs_DCT( /*normalized_image*/ipl_scaled, info->obs, parent->m_dctSize, parent->m_obsSize, parent->m_delta );
1290         }
1291         
1292         if ( doRescale )
1293         {
1294             cvReleaseImage( &ipl_scaled );
1295         }
1296
1297                 //cvReleaseImage( &normalized_image );
1298
1299         cvUniformImgSegm( info, hmm );
1300
1301     }                                              
1302
1303     cvInitMixSegm( obs_info_array, num_img, hmm );
1304
1305     bool trained = false;
1306     float old_likelihood = 0;
1307     
1308     
1309     int counter = 0;
1310
1311     while( (!trained) && (counter < max_iterations) )
1312     { 
1313         counter++;
1314
1315         int j;
1316 #if 0
1317
1318         //segment images
1319         for( j = 0; j < 1; j++ )
1320         {       
1321             IplImage* ipl_segm = segmentation.GetImage();
1322             CvImgObsInfo* obs = obs_info_array[j];
1323
1324             int counter=0;
1325             for(int k = 0; k < obs->obs_y; k++ )
1326             {
1327                 for(int m = 0; m < obs->obs_x; m++,counter++ )
1328                 {                       
1329                     cvCircle( ipl_segm, cvPoint( (parent->m_dctSize.width>>1) + 
1330                                                (parent->m_delta.width)* m ,
1331                                                (parent->m_dctSize.height>>1) + 
1332                                                (parent->m_delta.height)* k ), 3,
1333                                                color[obs->state[counter*2+1]], 1 );
1334                 }
1335             } 
1336
1337             parent->SetTrainedIndex(j);
1338             parent->UpdateTrainedImage();
1339             
1340         }        
1341
1342 #endif            
1343
1344         cvEstimateHMMStateParams( obs_info_array, num_img, hmm);
1345
1346         cvEstimateTransProb( obs_info_array, num_img, hmm); 
1347          
1348         float likelihood = 0;     
1349         for( j = 0; j < num_img; j++ )
1350         {           
1351             cvEstimateObsProb( obs_info_array[j], hmm );
1352             likelihood += cvEViterbi( obs_info_array[j], hmm );
1353         }
1354         likelihood /= num_img*obs_info_array[0]->obs_size;
1355
1356         cvMixSegmL2( obs_info_array, num_img, hmm);
1357
1358         trained = ( fabs(likelihood - old_likelihood) < 0.01 ); 
1359         old_likelihood = likelihood;                   
1360    }
1361
1362    for(i = 0; i < num_img; i++ )
1363    {
1364         cvReleaseObsInfo( &(obs_info_array[i]) );
1365    }
1366    
1367    obs_info.RemoveAll();  
1368 //   segmentation.Destroy();
1369  
1370
1371    m_trained = true;
1372    Save();
1373    
1374 }
1375           
1376 /****************************************************************************************\
1377 *                              CPersonImage class                                        *
1378 \****************************************************************************************/
1379
1380 CPersonImage::CPersonImage()
1381 {
1382     m_modified = false;
1383     m_roi_in_file = CRect(0,0,0,0);
1384 }
1385
1386
1387 CPersonImage::~CPersonImage()
1388 {
1389     Unload();    
1390 }
1391
1392
1393 bool  CPersonImage::Load()
1394 {
1395     bool res = m_img.LoadRect( m_filename, 0, m_roi_in_file ); // load as a grayscale image
1396     SetModified( false );
1397     return res;
1398 }
1399
1400
1401 void  CPersonImage::Unload()
1402 {
1403     Save(); 
1404     m_img.Destroy();
1405 }
1406
1407
1408 bool  CPersonImage::Save()
1409 {
1410     bool res = true;
1411     if( IsModified() )
1412     {
1413         res = m_img.Save( m_filename );
1414         SetModified( false );
1415     }
1416     return res;
1417 }
1418
1419
1420 void  CPersonImage::SetFileName( const CString& filename )
1421 {
1422     m_filename = filename;
1423     SetModified( m_img.Width() != 0 );
1424 }
1425
1426
1427 void  CPersonImage::SetRoiInFile( CRect r )
1428 {
1429     m_roi_in_file = r;
1430     SetModified( m_img.Width() != 0 );
1431 }
1432
1433
1434 void  CPersonImage::CalcRect( SIZE win_size, POINT pos, SIZE base_size,
1435                               CRect& src_rect, CRect& dst_rect )
1436 {
1437     IplImage* src = m_img.GetImage();
1438     int  w, h;
1439     int  mul_k, div_k;
1440     CRect sr, dr;
1441
1442     src_rect = dst_rect = CRect(0,0,0,0);
1443     
1444     w = src->width;
1445     h = src->height;
1446
1447     sr.left = sr.top = 0;
1448     sr.right = w;
1449     sr.bottom = h;
1450
1451     // calc scaling coefficients
1452     if( w*base_size.cy > h*base_size.cx )
1453     {
1454         mul_k = base_size.cx;
1455         div_k = w;
1456     }
1457     else
1458     {
1459         mul_k = base_size.cy;
1460         div_k = h;
1461     }
1462
1463     // calc resultant width & height
1464     dr.right = w * mul_k/div_k;
1465     dr.bottom = h * mul_k/div_k;
1466
1467     // calculate top-left coordinates
1468     dr.left = pos.x + (base_size.cx - dr.right)/2;
1469     dr.top = pos.y + (base_size.cy - dr.bottom)/2;
1470
1471     // calculate bottom-right coordinates
1472     dr.right += dr.left;
1473     dr.bottom += dr.top;
1474
1475     // rough clipping
1476     if( !(dr.right < 0 || dr.bottom < 0 || dr.left > win_size.cx || dr.top > win_size.cy))
1477     {
1478         // fine clipping
1479         if( dr.left < 0 )
1480         {
1481             sr.left = -dr.left * div_k/mul_k;
1482             dr.left = 0;
1483         }
1484
1485         if( dr.top < 0 )
1486         {
1487             sr.top = -dr.top * div_k/mul_k;
1488             dr.top = 0;
1489         }
1490
1491         if( dr.right > win_size.cx )
1492         {
1493             sr.right -= (dr.right - win_size.cx) * div_k/mul_k;
1494             dr.right = win_size.cx;
1495         }
1496
1497         if( dr.bottom > win_size.cy )
1498         {
1499             sr.bottom -= (dr.bottom - win_size.cy) * div_k/mul_k;
1500             dr.bottom = win_size.cy;
1501         }
1502
1503         if( !(sr.Width() <= 0 || sr.Height() <= 0 ||
1504               dr.Width() <= 0 || dr.Height() <= 0))
1505         {
1506             src_rect = sr;
1507             dst_rect = dr;
1508         }
1509     }
1510 }
1511
1512
1513 void  CPersonImage::Draw( CImage& img, SIZE win_size, POINT pos, SIZE base_size )
1514 {
1515     IplImage* dst = img.GetImage();
1516     IplImage* src = m_img.GetImage();
1517     IplROI *src_roi_tmp, *dst_roi_tmp;
1518     IplROI  src_roi, dst_roi;
1519     ASSERT( dst != 0 );
1520     CRect sr, dr;
1521
1522     if( !src ) return;
1523
1524     src_roi_tmp = src->roi;
1525     dst_roi_tmp = dst->roi;
1526     
1527     src->roi = &src_roi;
1528     dst->roi = &dst_roi;
1529
1530     CalcRect( win_size, pos, base_size, sr, dr );
1531
1532     if( !sr.IsRectEmpty() && !dr.IsRectEmpty())
1533     {
1534         // set ROIs
1535         src_roi = RectToROI( sr );
1536         dst_roi = RectToROI( dr );
1537
1538         cvResize( src, dst, CV_INTER_LINEAR );
1539     }
1540     
1541     src->roi = src_roi_tmp;
1542     dst->roi = dst_roi_tmp;
1543 }
1544
1545
1546
1547
1548
1549 void CFaceBase::TrainPerson(int index, bool loaded)
1550 {
1551     CPerson* person = GetPerson( index );
1552     
1553     ASSERT( person );
1554     if (!person) return;
1555
1556     if (person->IsTrained() ) return;
1557
1558     CPersonImgList& imgs = person->GetImgList();
1559
1560     int num_img = imgs.GetCount();
1561
1562     if ( !loaded )
1563     {
1564         person->LoadRest();
1565         person->TrainHMM();
1566         person->UnloadRest();         
1567     }
1568     else
1569         person->TrainHMM(); 
1570 }
1571
1572 void CFaceBase::TrainAll(int flag)
1573 {
1574
1575     for( POSITION pos = m_base.GetHeadPosition(); pos ; )
1576     {
1577         CPerson* person = m_base.GetNext(pos);
1578         if ((flag == TRAIN_UNTRAINED) && person->IsTrained() ) continue;
1579         
1580         person->LoadRest();
1581         person->TrainHMM();
1582         person->UnloadRest();
1583     }
1584     Save();
1585 }
1586
1587 int CFaceBase::RecognizeBatch(CStringList* image_list)
1588 {   
1589     int images_processed = 0;
1590     int right_recognized = 0;
1591     int wrong_recognized = 0;
1592
1593     POSITION pos = image_list->GetHeadPosition();
1594     while( pos )
1595     {
1596         CString path = image_list->GetNext(pos);
1597         
1598         //check if person exists in base
1599         char drive[1024], dir[1024], fname[256], ext[32];
1600         _splitpath( path, drive, dir, fname, ext );
1601        
1602         CString input_name = fname;
1603         input_name.Delete( input_name.GetLength() - 4,  4 );
1604         //find person with such name
1605         if ( !FindPersonByName( input_name ) ) continue;
1606
1607         CImage img;
1608         img.Load( path, 0 );
1609         
1610         //do recognition
1611         int pers_ind[2048];
1612         int num = RecognizePerson( img, CRect(0,0,0,0), pers_ind );
1613
1614         ASSERT( num );
1615         
1616         CPerson* person = GetPerson( pers_ind[0] );
1617         ASSERT( person );
1618         CString person_name = person->GetName();
1619         
1620         //compare recognized person name and input file name
1621         if( person_name == input_name )
1622         {
1623             right_recognized++;
1624         }
1625         else
1626         {
1627             wrong_recognized++;
1628         }
1629         images_processed++;
1630     }
1631
1632     //output results
1633     CString message;
1634     message.Format("Total images processed %d\nRight recognized %d\nReco rate is %.1f%% ",
1635                    images_processed, right_recognized, 100*(float)right_recognized/(float)images_processed );
1636     
1637     MessageBox( 0, message, "Batch recognition results", MB_OK );
1638
1639     return 1;
1640
1641 }
1642
1643
1644
1645
1646 int CFaceBase::RecognizePerson(CImage& image, CRect rect, int* three_first)
1647 {       
1648     if ( rect == CRect( 0,0,0,0 ) )
1649     {
1650         rect.bottom = image.Height();
1651         rect.right = image.Width();
1652     }
1653
1654     float like_array[1000]; ASSERT( m_base.GetCount() < 1000 );
1655     
1656     CImage gray_img;
1657     gray_img.CopyOf( image, 0 );
1658              
1659     IplImage* ipl = gray_img.GetImage();
1660     
1661     cvSetImageROI( ipl, RectToCvRect( rect ));
1662     int code = 1;
1663
1664       bool doRescale = false;
1665         
1666         int new_height = 0;
1667         int new_width = 0; 
1668  
1669         if ( m_useWidth )
1670         {
1671             doRescale = true;
1672             new_width = m_scaleWidth;
1673         }
1674         if ( m_useHeight )
1675         {
1676             doRescale = true;
1677             new_height = m_scaleHeight;
1678         }
1679         //recompute width or height if any is absent
1680         IplImage* ipl_scaled;
1681         if ( doRescale )
1682         {
1683             if ( !new_width )
1684             {
1685                 new_width  = new_height * ipl->roi->width / ipl->roi->height;
1686             }
1687             else if ( !new_height ) 
1688             {
1689                 new_height  = new_width * ipl->roi->height / ipl->roi->width;
1690             }
1691
1692             //rescale
1693             ipl_scaled = cvCreateImage( cvSize( new_width, new_height ), IPL_DEPTH_8U, 1 );
1694                 
1695             cvResize(ipl, ipl_scaled, /*ipl_scaled->width, ipl->width, 
1696                       ipl_scaled->height, ipl->height,*/ CV_INTER_NN);
1697                 
1698         }
1699         else
1700             ipl_scaled = ipl;
1701
1702     
1703         CvSize cvroi = cvSize( ipl_scaled->roi ? ipl_scaled->roi->width : ipl_scaled->width,
1704                                ipl_scaled->roi ? ipl_scaled->roi->height : ipl_scaled->height);
1705     
1706     CvSize num_obs;
1707     CvImgObsInfo* info;
1708     
1709     CV_COUNT_OBS( &cvroi, &m_dctSize, &m_delta, &num_obs ); 
1710
1711     int vect_len = m_obsSize.height*m_obsSize.width;
1712
1713     if( m_suppress_intensity )
1714     {
1715         vect_len--;
1716     }
1717
1718     info = cvCreateObsInfo( num_obs, vect_len );
1719
1720     
1721     if( m_suppress_intensity )
1722     {
1723         float* observations = (float*)malloc( num_obs.height * num_obs.width * (vect_len+1) * sizeof(float) );
1724         cvImgToObs_DCT( /*normalized_image*/ipl_scaled, observations, m_dctSize, m_obsSize, m_delta );
1725         ExtractDCT( observations, info->obs, num_obs.height * num_obs.width, vect_len );
1726         free( observations);
1727     }
1728     else
1729     {
1730     
1731         //IplImage* normalized_image = cvCreateImage( cvroi, IPL_DEPTH_8U, 1 );
1732         //NormalizeImageForHMM( ipl_scaled, normalized_image );
1733     
1734         cvImgToObs_DCT( /*normalized_image*/ipl_scaled, info->obs, m_dctSize, m_obsSize, m_delta );
1735
1736         //cvReleaseImage(&normalized_image);
1737     }
1738
1739     if ( doRescale )
1740     {
1741         cvReleaseImage( &ipl_scaled );
1742     }
1743     
1744     float max_like = -100000000; 
1745     //int recognized = -1;
1746     for( int i = 0 ; i < m_base.GetCount(); i++ )
1747     {
1748         CPerson* person = m_base.GetAt( m_base.FindIndex(i) );
1749         CvEHMM* hmm = 0;
1750
1751         if( !person->IsTrained() )
1752         {
1753             code = 0;
1754             break;
1755         }
1756
1757         hmm = person->GetHMM().GetIppiEHMM();
1758
1759         if (!hmm) //person not trained
1760         {
1761             code = 0;
1762             break;
1763         }
1764
1765         cvEstimateObsProb( info, hmm );
1766         like_array[i] = cvEViterbi( info, hmm );
1767     }
1768
1769     cvReleaseObsInfo( &info ); 
1770     gray_img.Destroy();
1771
1772     if( !code ) return code;
1773
1774     for( i = 0; i < MIN(3,m_base.GetCount()) ; i++ )
1775     {
1776         float maxl = -FLT_MAX;
1777         int maxind = -1;
1778
1779         for( int j = 0; j < m_base.GetCount(); j++ )
1780         {
1781             if (like_array[j] > maxl) { maxl = like_array[j]; maxind = j; }
1782         }
1783         three_first[i] = maxind;
1784         like_array[maxind] = -FLT_MAX;
1785     }
1786
1787     return MIN(3,m_base.GetCount());
1788 }
1789
1790 CContEHMM& CPerson::GetHMM()
1791 {
1792     return m_hmm;
1793 }
1794
1795
1796 int CFaceBase::SetParams(   //sampling params
1797                          CvSize dctSize, 
1798                          CvSize obsSize, 
1799                          CvSize delta,
1800                          //HMM params
1801                          int* states, int mix,
1802                          //image scaling params
1803                          BOOL use_width, int width,
1804                          BOOL use_height, int height,
1805                          BOOL suppress_intens, BOOL leave_hmm_alive)
1806 {
1807     BOOL clearHMM = FALSE;
1808     
1809     //sampling params
1810     if ( (dctSize.height != m_dctSize.height) || (dctSize.width != m_dctSize.width) ||
1811          (obsSize.height != m_obsSize.height) || (obsSize.width != m_obsSize.width) ||
1812          (delta.height != m_delta.height) || (delta.width != m_delta.width) ||
1813          (m_suppress_intensity != suppress_intens ) )
1814     {
1815         clearHMM  = TRUE;
1816     }
1817     
1818     m_dctSize =  dctSize;
1819     m_obsSize =  obsSize;
1820     m_delta   =  delta;
1821     m_suppress_intensity = suppress_intens;
1822     
1823     //hmm params
1824     BOOL dochange = FALSE;
1825     
1826     for( int i = 0; i <= states[0]; i++ )
1827     {
1828         if ( m_stnum[i] != (states[i]) )
1829         { 
1830             dochange = TRUE; 
1831             break;
1832         }
1833     }
1834     if ( mix != m_mixnum[0] ) 
1835         dochange = TRUE;
1836     
1837     if ( dochange )
1838     {
1839         //change hmm params 
1840         int counter = 0;
1841         for( int i = 0; i <= states[0]; i++ )
1842         {
1843             m_stnum[i] = (states[i]);
1844             for( int j  = 0; j < states[i]; j++, counter++ )
1845             {
1846                 m_mixnum[counter]  = mix;
1847             }
1848         }
1849         clearHMM |= dochange;
1850     } 
1851     
1852     //image scaling params
1853     if ( (m_useWidth != use_width) ||
1854          (m_useHeight != use_height) )
1855     { 
1856         clearHMM = TRUE;
1857     }
1858     else if ( ( m_useWidth &&  (width != m_scaleWidth) ) || 
1859               ( m_useHeight && (height != m_scaleHeight) ) )
1860     {
1861         clearHMM = TRUE;
1862     }
1863     
1864     m_useWidth = use_width;
1865     m_useHeight = use_height;
1866     m_scaleWidth = width;
1867     m_scaleHeight = height;
1868     
1869     if( clearHMM && (!leave_hmm_alive) )
1870     {
1871         for ( int i = 0; i < m_base.GetCount(); i++ )
1872         {
1873             CPerson* person = GetPerson( i );
1874             person->ClearHMM();
1875             person->SetModified(true);
1876         }
1877     }
1878     return clearHMM;
1879 }                          
1880
1881 void CPerson::ClearHMM()
1882 {
1883    m_hmm.Release();
1884    m_trained = false;
1885 }
1886
1887 int CFaceBase::RecognizeOtherBase(CFaceBase* other)
1888 {   
1889     CWaitCursor wait;
1890    
1891     int total = 0;
1892     int right = 0;
1893     int wrong = 0;
1894     
1895     //iterate through all persons and all images
1896     for( int i = 0; i < other->GetPersonList().GetCount(); i++ )
1897     {
1898         CPerson* other_person = other->GetPerson( i );
1899         
1900         CPerson* this_person = FindPersonByName( other_person->GetName() );
1901
1902         //match person with original base
1903         if ( this_person )
1904         {
1905             other_person->LoadRest();
1906             //iterate images
1907             CPersonImgList& list = other_person->GetImgList();
1908
1909             POSITION pos = list.GetHeadPosition();
1910             while ( pos )
1911             {   
1912                 int indices[2048]; //2 kilomen
1913
1914                 CPersonImage* img = list.GetNext(pos);
1915                 RecognizePerson( img->GetImage(), CRect(0,0,0,0), indices );
1916
1917                 if ( GetPerson( indices[0] ) == this_person )
1918                 {
1919                     right++;
1920                 }
1921                 else
1922                 {
1923                     wrong++;
1924                 }
1925                 total++;
1926
1927                 //write number of already processed images to status bar
1928                 //CString RecogResult;
1929
1930                 char RecogResult[64];
1931
1932                         CMainFrame* frame = (CMainFrame*)AfxGetMainWnd();
1933                                 frame->GetStatusBar()->SetPaneText(0, "");
1934                                 //RecogResult.Format("Processed %d images", total );
1935                 sprintf( RecogResult, "Processed %d images", total );
1936                                 frame->GetStatusBar()->SetPaneText(0, RecogResult); 
1937                // frame->GetStatusBar()->RedrawWindow();
1938                 frame->RedrawWindow();
1939                 
1940                     }
1941
1942             other_person->UnloadRest();
1943         }
1944     }
1945     
1946     //message
1947     CString message;
1948     ASSERT( total == (right + wrong) );
1949     message.Format("Total images processed %d\nRight recognized %d\nReco rate is %.1f%% ",
1950                    total, right, 100*(float)right/(float)total );
1951     
1952
1953     MessageBox( 0, message, "Batch recognition results", MB_OK );
1954
1955
1956    return 1;
1957 }