1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
40 //M*/// FaceBase.cpp: implementation of the CFaceBase class.
42 //////////////////////////////////////////////////////////////////////
56 static char THIS_FILE[]=__FILE__;
61 static const char* base_signature = "FACE DATABASE\n";
62 static const char* person_signature = "PERSONAL INFO\n";
64 void ConvertNameToFolder( const char* name, char* folder )
67 int len = strlen(name);
69 for( i = 0; i < len; i++ )
73 if( j == 0 || folder[j-1] != '.' )
80 folder[j++] = name[i];
88 /***************************************************************************************\
89 Face data base structure:
113 ( names in <> brackets can be arbitrary ).
128 Main base index file contains name of the base followed by list of personal folders.
129 Format is the following:
132 --------------------------------
133 1 FACE DATABASE (signature)
134 2 base name/description
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.
144 --------------------------------
145 1 PERSONAL INFO (signature)
146 2 person name/description
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.
158 lines, started with #, are comments, and skipped when file is readed.
160 \***************************************************************************************/
162 static char* chomp( char* str )
164 int l = strlen( str );
165 if( l > 0 && str[l-1] == '\n' )
172 const int STR_BUF_SIZE = 1000;
174 /****************************************************************************************\
176 \****************************************************************************************/
179 CFaceBase::CFaceBase()
188 for( int i = 0; i < 128; i++ )
194 m_trained_index = -1;
196 SetImageSize( CSize(100,120) );
198 m_delta = cvSize(4,4);
199 m_obsSize = cvSize(3,3);
200 m_dctSize = cvSize(12,12);
206 m_suppress_intensity = FALSE;
210 CFaceBase::~CFaceBase()
216 void CFaceBase::SetFileName( const CString& filename )
218 m_filename = filename;
223 void CFaceBase::SetName( const CString& name )
230 void CFaceBase::GetRootFolder( char* root_folder, int* root_path_len )
232 char buffer[STR_BUF_SIZE];
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 );
241 bool CFaceBase::GetPersonFolder( const char* root_folder, int root_folder_len,
242 const char* person_folder, char* folder )
244 char buffer[STR_BUF_SIZE];
245 char drive[STR_BUF_SIZE];
248 strcpy( buffer, person_folder );
250 len = strlen( buffer );
251 if( len == 0 ) return false;
253 // add slash (if absent)
254 if( buffer[len-1] != '\\')
257 buffer[len+1] = '\0';
260 _splitpath( buffer, drive, 0, 0, 0 );
261 if( strlen( drive ) > 0 ) return false;
263 if( root_folder != folder )
265 strcpy( folder, root_folder );
268 strcpy( folder + root_folder_len, buffer );
273 void CFaceBase::GetPersonSubFolder( const char* folder, char* subfolder )
275 char buffer[STR_BUF_SIZE];
276 char name[STR_BUF_SIZE];
277 char ext[STR_BUF_SIZE];
279 strcpy( buffer, folder );
281 ASSERT( buffer[strlen(buffer)-1] == '\\' );
284 buffer[strlen(buffer)-1] = '\0';
286 _splitpath( buffer, 0, 0, name, ext );
288 strcpy( subfolder, name );
289 strcat( subfolder, ext );
293 bool CFaceBase::Load()
296 char buffer[STR_BUF_SIZE];
297 char root_folder[STR_BUF_SIZE];
301 if( m_filename.GetLength() == 0 ) return false;
303 f = fopen( m_filename, "rt" );
304 if( !f ) return false;
308 if( !fgets( buffer, STR_BUF_SIZE, f ) || strcmp( buffer, base_signature ))
312 if( !fgets( buffer, STR_BUF_SIZE, f )) return false;
314 m_basename = chomp( buffer );
316 // construct root folder path
317 GetRootFolder( root_folder, &root_path_len );
319 // skip one line after the base name
320 fgets( buffer, STR_BUF_SIZE, f );
322 // load all the people data
326 if( !fgets( buffer,STR_BUF_SIZE, f )) break;
328 if( strlen(buffer) == 0 || buffer[0] == '#' ) continue;
331 if( !GetPersonFolder( root_folder, root_path_len, buffer, root_folder ))
334 person = new CPerson( this );
336 person->SetFolder( root_folder );
337 if( !person->Load() )
343 m_base.AddTail( person );
347 SetModified( error );
352 void CFaceBase::Unload()
355 while( !m_base.IsEmpty() )
357 CPerson* person = m_base.RemoveHead();
362 bool CFaceBase::Save()
364 if( m_filename.GetLength() > 0 )
366 POSITION pos = m_base.GetHeadPosition();
369 CPerson* person = m_base.GetNext( pos );
375 FILE* f = fopen( m_filename, "wt" );
376 char subfolder[STR_BUF_SIZE];
377 if( !f ) return false;
379 fputs( base_signature, f );
380 fputs( m_basename, f );
383 pos = m_base.GetHeadPosition();
387 CPerson* person = m_base.GetNext( pos );
388 const CString& str = person->GetFolder();
389 GetPersonSubFolder( str, subfolder );
390 fprintf( f, "%s\n", subfolder );
398 cfg_name = GetFileName();
399 cfg_name.Replace( ".txt", "CFG.txt" );
401 //save parameters (HMM, Sampling etc.) for whole application
402 CHMMDemoApp* app = (CHMMDemoApp*)AfxGetApp();
404 //check if any trained person
405 BOOL save_config = TRUE;//FALSE;
406 /*for( int i = 0; i < m_base.GetPersonList().GetCount(); i++ )
408 CPerson* person = m_base.GetPerson(i);
409 if ( person->IsTrained() )
415 if ( save_config ) app->SaveConfig( cfg_name );
416 else remove( cfg_name );
424 CPerson* CFaceBase::AddPerson( const char* name, const char* folder, bool import_data )
426 char temp_folder[STR_BUF_SIZE];
427 char root_folder[STR_BUF_SIZE];
433 ASSERT( strlen( name ) > 0 );
436 ConvertNameToFolder( name, temp_folder );
437 folder = temp_folder;
442 ASSERT( strlen( folder ) > 0 && name == 0 );
445 GetRootFolder( root_folder, &len );
446 GetPersonFolder( root_folder, len, folder, root_folder );
448 person = new CPerson( this );
449 person->SetFolder( root_folder );
460 _mkdir( root_folder );
461 person->SetName( name );
462 person->SetModified();
467 m_base.AddTail( person );
474 void CFaceBase::RemovePerson( POSITION pos )
476 CPerson* person = m_base.GetAt( pos );
480 m_base.RemoveAt( pos );
487 void CFaceBase::SetImageSize( CSize size )
489 m_baseImgSize = size;
494 CPerson* CFaceBase::GetPerson( int index )
496 ASSERT( index >= 0 );
497 POSITION pos = m_base.FindIndex( index );
498 return pos ? m_base.GetAt( pos ) : 0;
502 CPerson* CFaceBase::FindPersonByName( const CString& name )
504 POSITION pos = m_base.GetHeadPosition();
508 CPerson* person = m_base.GetNext(pos);
509 if( person && name.CompareNoCase( person->GetName()) == 0 ) return person;
515 int CFaceBase::GetPersonIndex( CPerson* person )
517 POSITION pos = m_base.GetHeadPosition();
520 for( i = 0; pos != 0; i++ )
522 CPerson* p = m_base.GetNext(pos);
523 if( p == person ) return i;
530 void CFaceBase::Draw( int index, CImage& img, SIZE win_size, int y_pos,
531 SIZE base_size, SIZE delta )
533 ASSERT( delta.cx > base_size.cx && delta.cy > base_size.cy );
535 int nx = MAX((win_size.cx + delta.cx - base_size.cx)/delta.cx,1);
536 int row = y_pos/delta.cy;
540 CPersonImgList* list = 0;
545 CPerson* person = GetPerson( index );
546 if( !person ) return;
548 list = &person->GetImgList();
549 count = list->GetCount();
553 count = m_base.GetCount();
556 if( !img.GetImage() || idx0 >= count ) return;
560 pos = list->FindIndex( idx0 );
564 pos = m_base.FindIndex( idx0 );
567 for( y = row*delta.cy - y_pos + (delta.cy - base_size.cy)/2;
568 y < win_size.cy ; y += delta.cy )
570 for( x = (delta.cx - base_size.cx)/2; ; )
572 CPersonImage* src_img = 0;
575 src_img = list->GetNext( pos );
579 CPerson* person = m_base.GetNext( pos );
582 CPersonImgList& l = person->GetImgList();
585 src_img = l.GetHead();
592 src_img->Draw( img, win_size, CPoint( x, y ), base_size );
597 if( x + base_size.cx > win_size.cx ) break;
603 void CFaceBase::UpdateTrainedImage()
607 m_base_view->InvalidateRect(0);
608 m_base_view->UpdateWindow();
613 void CFaceBase::DeleteHMMInfo()
615 POSITION pos = m_base.GetHeadPosition();
619 CPerson* person = m_base.GetNext(pos);
622 person->DeleteHMMInfo();
628 /****************************************************************************************\
630 \****************************************************************************************/
632 CPerson::CPerson( CFaceBase* parent )
637 ASSERT( parent != 0 );
646 void CPerson::SetName( const CString& name )
653 void CPerson::SetFolder( const CString& folder )
660 bool CPerson::GetPersonFullImageName( const char* root, int root_len,
661 const char* image, char* full_image_name )
663 char buffer[STR_BUF_SIZE];
664 char drive[STR_BUF_SIZE];
667 strcpy( buffer, image );
669 len = strlen( buffer );
670 if( len == 0 ) return false;
672 _splitpath( buffer, drive, 0, 0, 0 );
673 if( strlen( drive ) > 0 ) return false;
675 if( root != full_image_name )
677 strcpy( full_image_name, root );
680 strcpy( full_image_name + root_len, buffer );
685 void CPerson::ExtractPersonImageName( const char* full_image_name, char* image )
687 char buffer[STR_BUF_SIZE];
688 char name[STR_BUF_SIZE];
689 char ext[STR_BUF_SIZE];
691 strcpy( buffer, full_image_name );
693 _splitpath( buffer, 0, 0, name, ext );
695 strcpy( image, name );
696 strcat( image, ext );
703 char buffer[STR_BUF_SIZE];
704 char root[STR_BUF_SIZE];
707 CPersonImage* image = 0;
709 bool already_read = false;
711 strcpy( root, m_folder );
712 root_len = m_folder.GetLength();
713 strcpy( root + root_len, "info.txt" );
715 f = fopen( root, "rt" );
716 if( !f ) return false;
721 if( !fgets( buffer, STR_BUF_SIZE, f ) || strcmp(buffer,person_signature))
724 if( !fgets( buffer, STR_BUF_SIZE, f ))
727 m_name = chomp( buffer );
729 // skip one line after the base name
730 fgets( buffer, STR_BUF_SIZE, f );
732 // create image list for the person and load the first image
735 if( !already_read && !fgets( buffer,STR_BUF_SIZE, f )) break;
737 already_read = false;
738 if( strlen(buffer) == 0 || buffer[0] == '#' ) continue;
741 if( !GetPersonFullImageName( root, root_len, buffer, root ))
744 image = new CPersonImage;
745 image->SetFileName( root );
747 /* read ROI coordinates */
748 while( fgets( buffer,STR_BUF_SIZE, f ))
750 if( strlen(buffer) > 0 && buffer[0] == '#' ) continue;
752 if( sscanf( buffer, "%u%u%u%u", &roi.left, &roi.top,
753 &roi.right, &roi.bottom ) == 4 )
755 roi.right += roi.left;
756 roi.bottom += roi.top;
757 image->SetRoiInFile( roi );
758 already_read = false;
763 if( m_imgs.IsEmpty() && !image->Load() )
769 m_imgs.AddTail( image );
774 //load hmm if present
775 strcpy( root + root_len, "hmm.txt" );
776 f = fopen(root,"rt");
777 if( !f ) m_trained = false;
781 SetModified( error );
782 m_trained = m_hmm.Load( root );
789 void CPerson::Unload()
792 while( !m_imgs.IsEmpty() )
794 CPersonImage* image = m_imgs.RemoveHead();
804 char buffer[STR_BUF_SIZE];
806 POSITION pos = m_imgs.GetHeadPosition();
809 CPersonImage* image = m_imgs.GetNext( pos );
813 strcpy( buffer, m_folder );
814 strcat( buffer, "info.txt" );
816 FILE* f = fopen( buffer, "wt" );
817 if( !f ) return false;
819 fputs( person_signature, f );
823 pos = m_imgs.GetHeadPosition();
825 // write image names and ROI coordinates
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() )
835 fprintf(f, "%5u%5u%5u%5u\n", r.left, r.top, r.Width(), r.Height() );
843 char buffer[STR_BUF_SIZE];
846 strcpy( buffer, m_folder );
847 strcat( buffer, "hmm.txt" );
849 m_hmm.Save( buffer );
853 char buffer[STR_BUF_SIZE];
854 strcpy( buffer, m_folder );
855 strcat( buffer, "hmm.txt" );
865 void CPerson::LoadRest()
867 // load all the face images starting from second (first is always loaded)
868 POSITION pos = m_imgs.FindIndex(1);
872 POSITION tmp_pos = pos;
873 CPersonImage* image = m_imgs.GetNext( pos );
876 m_imgs.RemoveAt(tmp_pos);
884 void CPerson::UnloadRest()
886 // load all the face images starting from second (first is always loaded)
887 POSITION pos = m_imgs.FindIndex(1);
891 CPersonImage* image = m_imgs.GetNext( pos );
897 void CPerson::GenerateFileName( const char* base, char* filename )
899 char path[STR_BUF_SIZE];
900 int base_len = base ? strlen(base) : 0;
905 strcpy( filename, base );
909 char ext[STR_BUF_SIZE];
910 strcpy( path, m_folder );
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 );
922 for( ; i < 10000; i++ )
924 GetPersonFullImageName( m_folder, m_folder.GetLength(), filename, path );
925 sprintf( path + strlen(path), "%04d.bmp", i );
926 f = fopen( path, "rb" );
936 // try to open for writing. If success, output name
937 f = fopen( path, "wb" );
942 strcpy( filename, path );
947 void NormalizeIntensity(IplImage* ipl_image, int level)
953 ASSERT( (level>0) && (level <=255) );
954 cvGetImageRawData(ipl_image, &img, &step, &roi);
956 int width = roi.width;
957 int height = roi.height;
959 int mean = (int)cvMean( ipl_image );
961 for( int i = 0; i < height; i++, img+=step )
963 for( int j = 0; j < width; j++ )
965 int newval = img[j] + level - mean;
966 newval = (newval < 0) ? 0 : newval;
967 newval = (newval > 255) ? 255 : newval;
973 void NormalizeImageForHMM( IplImage* ipl_scaled, IplImage* normalized_image )
975 //iplFixedFilter( ipl_scaled, normalized_image, IPL_SOBEL_3x3_H );
978 void ExtractDCT( float* src, float* dst, int num_vec, int dst_len )
983 for( int i = 0; i < num_vec; i++ )
985 memcpy( dst_, src_, dst_len * sizeof(float) );
992 void CPerson::AddImage( const char* filename, CImage* import_image, CRect rect )
994 char root[STR_BUF_SIZE];
998 strcpy( root, m_folder );
999 root_len = m_folder.GetLength();
1003 ASSERT( import_image != 0 );
1004 GenerateFileName( 0, root );
1008 GetPersonFullImageName( root, root_len, filename, root );
1011 image = new CPersonImage;
1012 image->SetFileName( root );
1016 CImage& dst_img = image->GetImage();
1017 IplImage* src_img = import_image->GetImage();
1020 ASSERT( src_img != 0 );
1022 temp_roi = src_img->roi;
1024 if( rect.IsRectEmpty() )
1030 src_img->roi = &roi;
1031 roi = RectToROI( rect );
1034 dst_img.CopyOf( *import_image, 0 );
1035 src_img->roi = temp_roi;
1036 image->SetRoiInFile( CRect(0,0,0,0));
1037 image->SetModified();
1039 // to reserve file name
1044 image->SetRoiInFile( rect );
1048 m_imgs.AddTail( image );
1053 void CPerson::RemoveImage( POSITION pos )
1055 CPersonImage* image = m_imgs.GetAt( pos );
1058 m_imgs.RemoveAt( pos );
1060 remove( image->GetFileName() );
1067 void CPerson::MoveToTop( POSITION pos )
1069 CPersonImage* image = m_imgs.GetAt( pos );
1072 m_imgs.RemoveAt( pos );
1073 CPersonImage* old_head = m_imgs.GetHead();
1074 if( old_head ) old_head->Unload();
1075 m_imgs.AddHead( image );
1077 SetModified( true );
1082 void CPerson::DeleteHMMInfo()
1085 CString str = GetFolder() + "hmm.txt";
1089 void LightingCorrection(IplImage* ipl_image)
1095 cvGetImageRawData(ipl_image, &img, &step, &roi);
1098 int width = roi.width;
1099 int height = roi.height;
1101 float x1, x2, y1, y2;
1102 int f[3] = {0, 0, 0};
1103 float a[3] = {0, 0, 0};
1110 float min = FLT_MAX;
1111 float max = -FLT_MAX;
1114 float* float_img = (float*)malloc( width * height * sizeof(float) );
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)
1122 // extract grayvalues
1123 for (i = 0; i < height; i++)
1125 for (j = 0; j < width; j++)
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];
1133 h1 = (float)f[0] * (float)x1 / (float)width;
1134 h2 = (float)f[0] * (float)y1 / (float)height;
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;
1141 for (i = 0; i < height; i++)
1143 for (j = 0; j < width; j++)
1146 correction = a[0] + a[1]*(float)i + a[2]*(float)j;
1148 float_img[i*width + j] = img[i*step + j] - correction;
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];
1155 //rescaling to the range 0:255
1160 c2 = 255.0f/(float)(max - min);
1162 c1 = (-(float)min)*c2;
1164 for (i = 0; i < height; i++)
1166 for (j = 0; j < width; j++)
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;
1179 void CPerson::TrainHMM()
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) };
1188 //training loop can be not converged
1189 const int max_iterations = 80;
1191 CFaceBase* parent = GetParentBase();
1192 //CImage& segmentation = parent->GetTrainedImage();
1193 //segmentation.Create( 320, 320, 24 );
1195 int vect_len = parent->m_obsSize.height*parent->m_obsSize.width;
1197 //suppress first DCT coefficient
1198 if( parent->m_suppress_intensity)
1203 CvEHMM* hmm = m_hmm.GetIppiEHMM();
1204 if (!hmm) m_hmm.CreateHMM( parent->m_stnum, parent->m_mixnum, vect_len );
1206 hmm = m_hmm.GetIppiEHMM();
1208 //Create observation info
1209 int num_img = m_imgs.GetCount();
1212 CArray< CvImgObsInfo* , CvImgObsInfo* > obs_info;
1213 obs_info.SetSize( num_img );
1215 CvImgObsInfo** obs_info_array = obs_info.GetData();
1217 for( int i = 0; i < num_img; i++ )
1219 POSITION pos = m_imgs.FindIndex(i);
1220 IplImage* ipl = m_imgs.GetAt(pos)->GetImage().GetImage();
1222 bool doRescale = false;
1227 if ( parent->m_useWidth )
1230 new_width = parent->m_scaleWidth;
1232 if ( parent->m_useHeight )
1235 new_height = parent->m_scaleHeight;
1237 //recompute width or height if any is absent
1238 IplImage* ipl_scaled;
1240 CvSize image_roi = cvSize( ipl->roi ? ipl->roi->width : ipl->width,
1241 ipl->roi ? ipl->roi->height : ipl->height );
1247 new_width = new_height * image_roi.width / image_roi.height;
1249 else if ( !new_height )
1251 new_height = new_width * image_roi.height / image_roi.width;
1255 ipl_scaled = cvCreateImage( cvSize(new_width, new_height), IPL_DEPTH_8U, 1 );
1257 cvResize(ipl, ipl_scaled, /*ipl_scaled->width, ipl->width,
1258 ipl_scaled->height, ipl->height,*/ CV_INTER_NN);
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);
1270 CV_COUNT_OBS( &roi, &(parent->m_dctSize), &(parent->m_delta), &num_obs );
1273 obs_info_array[i] = cvCreateObsInfo( num_obs, vect_len );
1275 CvImgObsInfo* info = obs_info_array[i];
1277 //IplImage* normalized_image = cvCreateImage( roi, IPL_DEPTH_8U, 1 );
1278 //NormalizeImageForHMM( ipl_scaled, normalized_image );
1280 if( parent->m_suppress_intensity )
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);
1289 cvImgToObs_DCT( /*normalized_image*/ipl_scaled, info->obs, parent->m_dctSize, parent->m_obsSize, parent->m_delta );
1294 cvReleaseImage( &ipl_scaled );
1297 //cvReleaseImage( &normalized_image );
1299 cvUniformImgSegm( info, hmm );
1303 cvInitMixSegm( obs_info_array, num_img, hmm );
1305 bool trained = false;
1306 float old_likelihood = 0;
1311 while( (!trained) && (counter < max_iterations) )
1319 for( j = 0; j < 1; j++ )
1321 IplImage* ipl_segm = segmentation.GetImage();
1322 CvImgObsInfo* obs = obs_info_array[j];
1325 for(int k = 0; k < obs->obs_y; k++ )
1327 for(int m = 0; m < obs->obs_x; m++,counter++ )
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 );
1337 parent->SetTrainedIndex(j);
1338 parent->UpdateTrainedImage();
1344 cvEstimateHMMStateParams( obs_info_array, num_img, hmm);
1346 cvEstimateTransProb( obs_info_array, num_img, hmm);
1348 float likelihood = 0;
1349 for( j = 0; j < num_img; j++ )
1351 cvEstimateObsProb( obs_info_array[j], hmm );
1352 likelihood += cvEViterbi( obs_info_array[j], hmm );
1354 likelihood /= num_img*obs_info_array[0]->obs_size;
1356 cvMixSegmL2( obs_info_array, num_img, hmm);
1358 trained = ( fabs(likelihood - old_likelihood) < 0.01 );
1359 old_likelihood = likelihood;
1362 for(i = 0; i < num_img; i++ )
1364 cvReleaseObsInfo( &(obs_info_array[i]) );
1367 obs_info.RemoveAll();
1368 // segmentation.Destroy();
1376 /****************************************************************************************\
1377 * CPersonImage class *
1378 \****************************************************************************************/
1380 CPersonImage::CPersonImage()
1383 m_roi_in_file = CRect(0,0,0,0);
1387 CPersonImage::~CPersonImage()
1393 bool CPersonImage::Load()
1395 bool res = m_img.LoadRect( m_filename, 0, m_roi_in_file ); // load as a grayscale image
1396 SetModified( false );
1401 void CPersonImage::Unload()
1408 bool CPersonImage::Save()
1413 res = m_img.Save( m_filename );
1414 SetModified( false );
1420 void CPersonImage::SetFileName( const CString& filename )
1422 m_filename = filename;
1423 SetModified( m_img.Width() != 0 );
1427 void CPersonImage::SetRoiInFile( CRect r )
1430 SetModified( m_img.Width() != 0 );
1434 void CPersonImage::CalcRect( SIZE win_size, POINT pos, SIZE base_size,
1435 CRect& src_rect, CRect& dst_rect )
1437 IplImage* src = m_img.GetImage();
1442 src_rect = dst_rect = CRect(0,0,0,0);
1447 sr.left = sr.top = 0;
1451 // calc scaling coefficients
1452 if( w*base_size.cy > h*base_size.cx )
1454 mul_k = base_size.cx;
1459 mul_k = base_size.cy;
1463 // calc resultant width & height
1464 dr.right = w * mul_k/div_k;
1465 dr.bottom = h * mul_k/div_k;
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;
1471 // calculate bottom-right coordinates
1472 dr.right += dr.left;
1473 dr.bottom += dr.top;
1476 if( !(dr.right < 0 || dr.bottom < 0 || dr.left > win_size.cx || dr.top > win_size.cy))
1481 sr.left = -dr.left * div_k/mul_k;
1487 sr.top = -dr.top * div_k/mul_k;
1491 if( dr.right > win_size.cx )
1493 sr.right -= (dr.right - win_size.cx) * div_k/mul_k;
1494 dr.right = win_size.cx;
1497 if( dr.bottom > win_size.cy )
1499 sr.bottom -= (dr.bottom - win_size.cy) * div_k/mul_k;
1500 dr.bottom = win_size.cy;
1503 if( !(sr.Width() <= 0 || sr.Height() <= 0 ||
1504 dr.Width() <= 0 || dr.Height() <= 0))
1513 void CPersonImage::Draw( CImage& img, SIZE win_size, POINT pos, SIZE base_size )
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;
1524 src_roi_tmp = src->roi;
1525 dst_roi_tmp = dst->roi;
1527 src->roi = &src_roi;
1528 dst->roi = &dst_roi;
1530 CalcRect( win_size, pos, base_size, sr, dr );
1532 if( !sr.IsRectEmpty() && !dr.IsRectEmpty())
1535 src_roi = RectToROI( sr );
1536 dst_roi = RectToROI( dr );
1538 cvResize( src, dst, CV_INTER_LINEAR );
1541 src->roi = src_roi_tmp;
1542 dst->roi = dst_roi_tmp;
1549 void CFaceBase::TrainPerson(int index, bool loaded)
1551 CPerson* person = GetPerson( index );
1554 if (!person) return;
1556 if (person->IsTrained() ) return;
1558 CPersonImgList& imgs = person->GetImgList();
1560 int num_img = imgs.GetCount();
1566 person->UnloadRest();
1572 void CFaceBase::TrainAll(int flag)
1575 for( POSITION pos = m_base.GetHeadPosition(); pos ; )
1577 CPerson* person = m_base.GetNext(pos);
1578 if ((flag == TRAIN_UNTRAINED) && person->IsTrained() ) continue;
1582 person->UnloadRest();
1587 int CFaceBase::RecognizeBatch(CStringList* image_list)
1589 int images_processed = 0;
1590 int right_recognized = 0;
1591 int wrong_recognized = 0;
1593 POSITION pos = image_list->GetHeadPosition();
1596 CString path = image_list->GetNext(pos);
1598 //check if person exists in base
1599 char drive[1024], dir[1024], fname[256], ext[32];
1600 _splitpath( path, drive, dir, fname, ext );
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;
1608 img.Load( path, 0 );
1612 int num = RecognizePerson( img, CRect(0,0,0,0), pers_ind );
1616 CPerson* person = GetPerson( pers_ind[0] );
1618 CString person_name = person->GetName();
1620 //compare recognized person name and input file name
1621 if( person_name == input_name )
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 );
1637 MessageBox( 0, message, "Batch recognition results", MB_OK );
1646 int CFaceBase::RecognizePerson(CImage& image, CRect rect, int* three_first)
1648 if ( rect == CRect( 0,0,0,0 ) )
1650 rect.bottom = image.Height();
1651 rect.right = image.Width();
1654 float like_array[1000]; ASSERT( m_base.GetCount() < 1000 );
1657 gray_img.CopyOf( image, 0 );
1659 IplImage* ipl = gray_img.GetImage();
1661 cvSetImageROI( ipl, RectToCvRect( rect ));
1664 bool doRescale = false;
1672 new_width = m_scaleWidth;
1677 new_height = m_scaleHeight;
1679 //recompute width or height if any is absent
1680 IplImage* ipl_scaled;
1685 new_width = new_height * ipl->roi->width / ipl->roi->height;
1687 else if ( !new_height )
1689 new_height = new_width * ipl->roi->height / ipl->roi->width;
1693 ipl_scaled = cvCreateImage( cvSize( new_width, new_height ), IPL_DEPTH_8U, 1 );
1695 cvResize(ipl, ipl_scaled, /*ipl_scaled->width, ipl->width,
1696 ipl_scaled->height, ipl->height,*/ CV_INTER_NN);
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);
1709 CV_COUNT_OBS( &cvroi, &m_dctSize, &m_delta, &num_obs );
1711 int vect_len = m_obsSize.height*m_obsSize.width;
1713 if( m_suppress_intensity )
1718 info = cvCreateObsInfo( num_obs, vect_len );
1721 if( m_suppress_intensity )
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);
1731 //IplImage* normalized_image = cvCreateImage( cvroi, IPL_DEPTH_8U, 1 );
1732 //NormalizeImageForHMM( ipl_scaled, normalized_image );
1734 cvImgToObs_DCT( /*normalized_image*/ipl_scaled, info->obs, m_dctSize, m_obsSize, m_delta );
1736 //cvReleaseImage(&normalized_image);
1741 cvReleaseImage( &ipl_scaled );
1744 float max_like = -100000000;
1745 //int recognized = -1;
1746 for( int i = 0 ; i < m_base.GetCount(); i++ )
1748 CPerson* person = m_base.GetAt( m_base.FindIndex(i) );
1751 if( !person->IsTrained() )
1757 hmm = person->GetHMM().GetIppiEHMM();
1759 if (!hmm) //person not trained
1765 cvEstimateObsProb( info, hmm );
1766 like_array[i] = cvEViterbi( info, hmm );
1769 cvReleaseObsInfo( &info );
1772 if( !code ) return code;
1774 for( i = 0; i < MIN(3,m_base.GetCount()) ; i++ )
1776 float maxl = -FLT_MAX;
1779 for( int j = 0; j < m_base.GetCount(); j++ )
1781 if (like_array[j] > maxl) { maxl = like_array[j]; maxind = j; }
1783 three_first[i] = maxind;
1784 like_array[maxind] = -FLT_MAX;
1787 return MIN(3,m_base.GetCount());
1790 CContEHMM& CPerson::GetHMM()
1796 int CFaceBase::SetParams( //sampling 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)
1807 BOOL clearHMM = FALSE;
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 ) )
1818 m_dctSize = dctSize;
1819 m_obsSize = obsSize;
1821 m_suppress_intensity = suppress_intens;
1824 BOOL dochange = FALSE;
1826 for( int i = 0; i <= states[0]; i++ )
1828 if ( m_stnum[i] != (states[i]) )
1834 if ( mix != m_mixnum[0] )
1841 for( int i = 0; i <= states[0]; i++ )
1843 m_stnum[i] = (states[i]);
1844 for( int j = 0; j < states[i]; j++, counter++ )
1846 m_mixnum[counter] = mix;
1849 clearHMM |= dochange;
1852 //image scaling params
1853 if ( (m_useWidth != use_width) ||
1854 (m_useHeight != use_height) )
1858 else if ( ( m_useWidth && (width != m_scaleWidth) ) ||
1859 ( m_useHeight && (height != m_scaleHeight) ) )
1864 m_useWidth = use_width;
1865 m_useHeight = use_height;
1866 m_scaleWidth = width;
1867 m_scaleHeight = height;
1869 if( clearHMM && (!leave_hmm_alive) )
1871 for ( int i = 0; i < m_base.GetCount(); i++ )
1873 CPerson* person = GetPerson( i );
1875 person->SetModified(true);
1881 void CPerson::ClearHMM()
1887 int CFaceBase::RecognizeOtherBase(CFaceBase* other)
1895 //iterate through all persons and all images
1896 for( int i = 0; i < other->GetPersonList().GetCount(); i++ )
1898 CPerson* other_person = other->GetPerson( i );
1900 CPerson* this_person = FindPersonByName( other_person->GetName() );
1902 //match person with original base
1905 other_person->LoadRest();
1907 CPersonImgList& list = other_person->GetImgList();
1909 POSITION pos = list.GetHeadPosition();
1912 int indices[2048]; //2 kilomen
1914 CPersonImage* img = list.GetNext(pos);
1915 RecognizePerson( img->GetImage(), CRect(0,0,0,0), indices );
1917 if ( GetPerson( indices[0] ) == this_person )
1927 //write number of already processed images to status bar
1928 //CString RecogResult;
1930 char RecogResult[64];
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();
1942 other_person->UnloadRest();
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 );
1953 MessageBox( 0, message, "Batch recognition results", MB_OK );