Update the changelog
[opencv] / apps / HMMDemo / Threads.cpp
1 #include "stdafx.h"
2 #include "Threads.h"
3 #include "facebase.h"
4 #include <afxtempl.h>
5 #include <float.h>
6
7 #include "image.h"
8
9 //#include "cv.h"
10
11 //#include "HMMDemo.h"
12 //#include "FaceBase.h"
13 //#include "direct.h"
14
15 #include "multiprocdiv.h"
16
17 #define NONE_FINISH_WORK -1
18 #define BRAKE_WORK -2
19
20 //#define PRIOR //
21 #define PRIOR
22
23 #define CHECK_TRAIN_FOR_BREAK(mac_thrArr,mac_thrParams,mac_numProc) \
24     if( thrFinishWork == BRAKE_WORK ) { \
25         int mac_i; \
26         POSITION pos; \
27         for( mac_i = 0; mac_i < mac_numProc; mac_i ++ ) { \
28             if( mac_thrParams[mac_i].working == true ) { \
29                 mac_thrParams[mac_i].doNext = false; \
30                 ResumeThread( mac_thrArr[mac_i] ); \
31                 Sleep(50); \
32             } \
33         } \
34         for( pos = base.GetPersonList().GetHeadPosition(); pos;  ) \
35         { \
36             CPerson* person = base.GetPersonList().GetNext( pos ); \
37             person->SetTrainFlag( false ); \
38         } \
39         Sleep( 5000 ); \
40         for( mac_i = 0; mac_i < mac_numProc; mac_i ++ ) { \
41             if( mac_thrParams[mac_i].working == true ) { \
42                 char buf[256]; \
43                 _RPT1( _CRT_WARN, "Terminating thread #%d\n", mac_i ); \
44                 if( !TerminateThread( mac_thrArr[mac_i], 1 ) ) { \
45                     FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, buf, 256, 0 ); \
46                     _RPT1( _CRT_WARN, "TerminateThread returned: %s\n", buf ); \
47                 } \
48                 else { \
49                     FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, buf, 256, 0 ); \
50                     _RPT1( _CRT_WARN, "TerminateThread returned: %s\n", buf ); \
51                 } \
52                 WaitForSingleObject( mac_thrArr[mac_i], 3000 ); \
53             } \
54         } \
55         base.DeleteHMMInfo(); \
56         CloseHandle( g_hevtWakeUpControlThread ); \
57         DeleteCriticalSection( &g_critSect ); \
58         hCtrlTrainThread = 0; \
59         trainParam.frame->EnableItemsAfterTrain(); \
60         ExitThread(0); \
61     }
62
63 #define CHECK_TRAIN_FOR_BREAK1(mac_thrArr,mac_thrParams,mac_numProc) \
64     if( thrFinishWork == BRAKE_WORK ) { \
65         int mac_i; \
66         for( mac_i = 0; mac_i < mac_numProc; mac_i ++ ) { \
67             if( mac_thrParams[mac_i].working == true ) { \
68                 mac_thrParams[mac_i].doNext = false; \
69                 ResumeThread( mac_thrArr[mac_i] ); \
70             } \
71         } \
72         Sleep( 5000 ); \
73         for( mac_i = 0; mac_i < mac_numProc; mac_i ++ ) { \
74             if( mac_thrParams[mac_i].working == true ) { \
75                 char buf[256]; \
76                 _RPT1( _CRT_WARN, "Terminating thread #%d\n", mac_i ); \
77                 if( !TerminateThread( mac_thrArr[mac_i], 1 ) ) { \
78                     FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, buf, 256, 0 ); \
79                     _RPT1( _CRT_WARN, "TerminateThread returned: %s\n", buf ); \
80                 } \
81                 else { \
82                     FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, buf, 256, 0 ); \
83                     _RPT1( _CRT_WARN, "TerminateThread returned: %s\n", buf ); \
84                 } \
85                 WaitForSingleObject( mac_thrArr[mac_i], 30 ); \
86             } \
87         } \
88         CloseHandle( g_hevtWakeUpControlThread ); \
89         DeleteCriticalSection( &g_critSect ); \
90         hCtrlTrainThread = 0; \
91         ExitThread(0); \
92     }
93
94 struct TrainThreadParams {
95     int threadNum;
96     CPerson* person;
97     int doNext;
98     HANDLE hThread;
99     bool working;
100 };
101
102 HANDLE g_hevtWakeUpControlThread;
103 CRITICAL_SECTION g_critSect;
104
105 DWORD dwCtrlTrainThread;
106 HANDLE hCtrlTrainThread;
107
108 volatile int thrFinishWork;
109
110 StartTrainParams trainParam;
111
112 //DWORD WINAPI ThreadProc(
113 //  LPVOID lpParameter   // thread data
114 //);
115  
116 DWORD trainFunc( LPVOID param )
117 {
118     TrainThreadParams* thrParams = (TrainThreadParams*)param;
119     int threadNum = thrParams->threadNum;
120     HANDLE hThread = thrParams->hThread;
121     CPerson* person;
122     int anotherThrBlocksVar;
123
124     InterlockedExchange( (long*)&(thrParams->working), (int)true );
125
126     while( thrParams->doNext )
127     {
128         person = thrParams->person;
129
130         _RPT1( _CRT_WARN, "Thread #%d begins\n", threadNum );
131
132         EnterCriticalSection( &g_critSect );
133             person->LoadRest();
134         LeaveCriticalSection( &g_critSect );
135
136         person->TrainHMM();
137         person->UnloadRest();
138
139         if( !thrParams->doNext ) {
140             break;
141         }
142
143
144         _RPT1( _CRT_WARN, "Thread #%d ends\n", threadNum );
145
146         EnterCriticalSection( &g_critSect );
147             thrParams->doNext = false;
148             anotherThrBlocksVar = true;
149             while( anotherThrBlocksVar )
150             {
151                 if( thrFinishWork == NONE_FINISH_WORK ) {
152                     thrFinishWork = threadNum;
153                     anotherThrBlocksVar = false;
154                 }
155                 else {
156                     LeaveCriticalSection( &g_critSect );
157                         Sleep(0);
158                     EnterCriticalSection( &g_critSect );
159                 }
160             }
161
162             _RPT1( _CRT_WARN, "Thread #%d sets event\n", threadNum );
163
164             SetEvent( g_hevtWakeUpControlThread );
165         LeaveCriticalSection( &g_critSect );
166
167         _RPT1( _CRT_WARN, "Thread #%d suspends\n", threadNum );
168
169         SuspendThread( hThread );
170
171         Sleep(0);
172
173         _RPT1( _CRT_WARN, "Thread #%d resumes\n", threadNum );
174     } // while( thrParams->doNext )
175
176     _RPT1( _CRT_WARN, "Thread #%d finishes\n", threadNum );
177
178     InterlockedExchange( (long*)&(thrParams->working), (int)false );
179     return 0;
180 } // trainFunc
181
182 DWORD ctrlTrainThreadFunc( LPVOID param )
183 {
184     SYSTEM_INFO sysInfo;
185     int numProc;
186     int i;
187     DWORD dwTrainThread[32];
188     HANDLE hTrainThread[32];
189     TrainThreadParams thrParams[32];
190     DWORD affMask = 0;
191     POSITION pos;
192     CPerson* person;
193     
194     InitializeCriticalSection( &g_critSect );
195     g_hevtWakeUpControlThread = CreateEvent( 0, true, false, "WakeUpCtrlTrainThread" );
196
197     GetSystemInfo( &sysInfo );
198     numProc = sysInfo.dwNumberOfProcessors;
199
200     numProc = 32;
201
202     if( numProc > 32 ) {
203         CloseHandle( g_hevtWakeUpControlThread );
204         DeleteCriticalSection( &g_critSect );
205         hCtrlTrainThread = 0;
206         return 0;
207     }
208
209     trainParam.frame->DisableItemsForTrain();
210
211
212     if( numProc == 1 )
213     {
214         // Single processor code
215         CHMMDemoDoc* doc = ( (StartTrainParams*)param )->doc;
216         if( !doc )
217             return 0;
218         CFaceBase& base = doc->GetFaceBase();
219         base.TrainAll( ( (StartTrainParams*)param )->flag );
220     }
221     else {
222         // Multiple processor code
223         CHMMDemoDoc* doc = ( (StartTrainParams*)param )->doc;
224         if( !doc )
225             ExitThread(0);
226         CFaceBase& base = doc->GetFaceBase();
227
228         affMask = 0;
229         for( i = 0; i < numProc; i ++ )
230         {
231             affMask |= ( 1 << i );
232         }
233         for( i = 0; i < numProc; i ++ )
234         {
235             thrParams[i].threadNum = i;
236             thrParams[i].working = true;
237             hTrainThread[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)trainFunc, &(thrParams[i]), CREATE_SUSPENDED, &(dwTrainThread[i]) );
238             thrParams[i].hThread = hTrainThread[i];
239             thrParams[i].doNext = false;
240             PRIOR SetThreadPriority( hTrainThread[i], THREAD_PRIORITY_BELOW_NORMAL );
241             //SetThreadAffinityMask( hTrainThread[i], affMask );
242             //SetThreadIdealProcessor( hTrainThread[i], (DWORD)i );
243         }
244
245         thrFinishWork = NONE_FINISH_WORK;
246         ResetEvent( g_hevtWakeUpControlThread );
247         for( i = 0, pos = base.GetPersonList().GetHeadPosition(); pos; )
248         {
249             person = base.GetPersonList().GetNext(pos);
250
251             _RPT2( _CRT_WARN, "%s %d\n", "pos = ", (int)pos );
252
253             if( (( (StartTrainParams*)param )->flag == TRAIN_UNTRAINED) && person->IsTrained() ) continue;
254         
255             EnterCriticalSection( &g_critSect );
256
257                 _RPT1( _CRT_WARN, "Giving execute to thread #%d\n", i );
258
259                 thrParams[i].person = person;
260                 thrParams[i].doNext = true;
261             LeaveCriticalSection( &g_critSect );
262
263             _RPT1( _CRT_WARN, "Resuming thread #%d\n", i );
264
265             ResumeThread( hTrainThread[i] );
266             i ++;
267             if( i == numProc ) {
268                 break;
269             }
270         }
271         if( i != numProc ) {
272             while( i > 0 ) {
273                 WaitForSingleObject( g_hevtWakeUpControlThread, INFINITE );
274                 CHECK_TRAIN_FOR_BREAK( hTrainThread, thrParams, numProc );
275
276                 _RPT1( _CRT_WARN, "Main thread gets last event from thread #%d\n", thrFinishWork );
277
278                 EnterCriticalSection( &g_critSect );
279                     ResetEvent( g_hevtWakeUpControlThread );
280                     thrParams[ thrFinishWork ].doNext = false;
281
282                     _RPT1( _CRT_WARN, "Resuming thread #%d\n", thrFinishWork );
283
284                     ResumeThread( hTrainThread[ thrFinishWork ] );
285                     thrFinishWork = NONE_FINISH_WORK;
286                     i --;
287                 LeaveCriticalSection( &g_critSect );
288             }
289         } // if( i == numProc )
290         else {
291             i = base.GetPersonList().GetCount() - numProc;
292             while( i > 0 ) {
293                 WaitForSingleObject( g_hevtWakeUpControlThread, INFINITE );
294                 CHECK_TRAIN_FOR_BREAK( hTrainThread, thrParams, numProc );
295
296                 _RPT0( _CRT_WARN, "Main thread gets event\n" );
297
298                 EnterCriticalSection( &g_critSect );
299                     ResetEvent( g_hevtWakeUpControlThread );
300                     person = base.GetPersonList().GetNext(pos);
301
302                     _RPT1( _CRT_WARN, "pos = %d\n", (int)pos );
303
304                     while( pos && person->IsTrained() ) {
305                         if( (( (StartTrainParams*)param )->flag != TRAIN_UNTRAINED) ) {
306                             person = base.GetPersonList().GetNext(pos);
307                             i --;
308                         }
309                     }
310         
311                     if( person ) {
312
313                         _RPT1( _CRT_WARN, "Giving execute to thread #%d\n", thrFinishWork );
314
315                         thrParams[ thrFinishWork ].person = person;
316                         thrParams[ thrFinishWork ].doNext = true;
317
318                         _RPT1( _CRT_WARN, "Resuming thread #%d\n", thrFinishWork );
319
320                         ResumeThread( hTrainThread[ thrFinishWork ] );
321                         thrFinishWork = NONE_FINISH_WORK;
322                         i --;
323                     }
324                 LeaveCriticalSection( &g_critSect );
325
326                 _RPT1( _CRT_WARN, "i = %d\n", i );
327
328                 //WaitForSingleObject( g_hevtWakeUpControlThread, INFINITE );
329             } // while( i > 0 )
330
331             for( i = 0; i < numProc; i ++ ) {
332
333                 int thrNum;
334                 DWORD resumeRes;
335
336                 WaitForSingleObject( g_hevtWakeUpControlThread, INFINITE );
337                 CHECK_TRAIN_FOR_BREAK( hTrainThread, thrParams, numProc );
338
339                 _RPT1( _CRT_WARN, "Main thread gets last event from thread #%d\n", thrFinishWork );
340             
341                 EnterCriticalSection( &g_critSect );
342                     ResetEvent( g_hevtWakeUpControlThread );
343                     thrNum = thrFinishWork;
344                     thrParams[thrNum].doNext = false;
345
346                     _RPT1( _CRT_WARN, "Resuming thread #%d\n", thrFinishWork );
347
348                     resumeRes = ResumeThread( hTrainThread[thrNum] );
349                     thrFinishWork = NONE_FINISH_WORK;
350                 LeaveCriticalSection( &g_critSect );
351
352                 _RPT1( _CRT_WARN, "Waiting for finishing thread #%d\n", thrNum );
353
354                 while( !resumeRes ) {
355                     resumeRes = ResumeThread( hTrainThread[thrNum] );
356                 }
357                 WaitForSingleObject( hTrainThread[thrNum], INFINITE );
358             }
359
360         } // if( i == numProc ) else
361         for( i = 0; i < numProc; i ++ )
362         {
363             thrParams[i].doNext = false;
364             if( thrParams[i].working == true ) {
365
366                 _RPT1( _CRT_WARN, "Resuming thread #%d\n", i );
367
368                 while( !ResumeThread( hTrainThread[i] ) && thrParams[i].working == true ) {
369                     Sleep(0);
370                 }
371
372                 _RPT1( _CRT_WARN, "Waiting for finishing thread #%d\n", i );
373
374                 WaitForSingleObject( hTrainThread[i], INFINITE );
375             }
376         }
377         base.Save();
378     } // if( numProc == 1 )
379
380
381     _RPT0( _CRT_WARN, "Main thread: All is Ok!\n" );
382
383     CloseHandle( g_hevtWakeUpControlThread );
384     DeleteCriticalSection( &g_critSect );
385     hCtrlTrainThread = 0;
386     trainParam.frame->EnableItemsAfterTrain();
387     return 0;
388 } // ctrlTrainThreadFunc
389
390 bool startTrain( CHMMDemoDoc* doc, CMainFrame* frame, int flag )
391 {
392     static bool trainingStartsFirstTime = true;
393     bool anotherThrBlocksVar;
394
395     if( trainingStartsFirstTime ) {
396         trainingStartsFirstTime = false;
397         hCtrlTrainThread = 0;
398     }
399
400     if( hCtrlTrainThread ) {
401         EnterCriticalSection( &g_critSect );
402             anotherThrBlocksVar = true;
403             while( anotherThrBlocksVar )
404             {
405                 if( thrFinishWork == NONE_FINISH_WORK ) {
406                     thrFinishWork = BRAKE_WORK;
407                     anotherThrBlocksVar = false;
408                 }
409                 else {
410                     LeaveCriticalSection( &g_critSect );
411                         Sleep(0);
412                     EnterCriticalSection( &g_critSect );
413                 }
414             }
415
416             _RPT0( _CRT_WARN, "Main thread sets break event\n" );
417
418             SetEvent( g_hevtWakeUpControlThread );
419         LeaveCriticalSection( &g_critSect );
420     }
421     else {
422         trainParam.doc = doc;
423         trainParam.frame = frame;
424         trainParam.flag = flag;
425
426         hCtrlTrainThread = CreateThread( NULL, 0,
427             (LPTHREAD_START_ROUTINE)ctrlTrainThreadFunc, &trainParam, 0, &dwCtrlTrainThread );
428         PRIOR SetThreadPriority( hCtrlTrainThread, THREAD_PRIORITY_BELOW_NORMAL );
429     }
430
431     return true;
432 }
433
434
435
436
437
438 struct InputRecogChildThread {
439     INPUT_STRUCT_COMMON_PARAMS();
440     CvEHMM* hmm;
441     CvImgObsInfo* info;
442     float* like_array;
443 };
444
445 struct InputCtrlChildThread {
446     CFaceBase* faceBase;
447     CImage* image;
448     CRect rect;
449     //HWND hwnd;
450     CFaceBase* base;
451     CImageBaseView* baseview;
452 };
453
454 COMMON_GLOBAL_VARS(recognizeThread,InputCtrlChildThread);
455
456
457 /*struct InputRecogChildThread {
458     int threadNum; bool doNext; HANDLE hThread; bool working;
459     CvEHMM* hmm;
460     CvImgObsInfo* info;
461     float* like_array;
462 };
463
464 struct InputCtrlChildThread {
465     CFaceBase* faceBase;
466     CImage* image;
467     CRect rect;
468     //HWND hwnd;
469     CFaceBase* base;
470     CImageBaseView* baseview;
471 };
472
473 CRITICAL_SECTION recognizeThreadCritSect; HANDLE recognizeThreadEvent; volatile int recognizeThreadMessage; HANDLE recognizeThreadThreadHandle; InputCtrlChildThread recognizeThreadInputStruct;
474 */
475
476 // recognize child thread function
477 BEGIN_CHILD_THREAD_FUNCTION(recognizeThread,InputRecogChildThread);
478     BEGIN_CHILD_THREAD_CORE();
479         cvEstimateObsProb( params->info, params->hmm );
480         *(params->like_array) = cvEViterbi( params->info, params->hmm );
481     END_CHILD_THREAD_CORE();
482 END_CHILD_THREAD_FUNCTION();
483
484
485 // recognize control thread function
486 BEGIN_CTRL_THREAD_FUNCTION(recognizeThread,InputCtrlChildThread,InputRecogChildThread,0,0,0);
487     int ranged[3];
488
489     if ( params->rect == CRect( 0,0,0,0 ) )
490     {
491         params->rect.bottom = params->image->Height();
492         params->rect.right = params->image->Width();
493     }
494
495     float like_array[1000]; ASSERT( params->faceBase->GetPersonList().GetCount() < 1000 );
496     
497     CImage gray_img;
498     gray_img.CopyOf( *(params->image), 0 );
499              
500     IplImage* ipl = gray_img.GetImage();
501     IplROI ipl_roi;
502     ipl_roi.coi = 0;
503     ipl_roi.xOffset = params->rect.left;
504     ipl_roi.yOffset = params->rect.top;
505     ipl_roi.height = params->rect.Height();
506     ipl_roi.width = params->rect.Width();
507     ipl->roi = &ipl_roi;
508            
509     int code = 1;
510
511       bool doRescale = false;
512         
513         int new_height = 0;
514         int new_width = 0; 
515  
516         if ( params->faceBase->m_useWidth )
517         {
518             doRescale = true;
519             new_width = params->faceBase->m_scaleWidth;
520         }
521         if ( params->faceBase->m_useHeight )
522         {
523             doRescale = true;
524             new_height = params->faceBase->m_scaleHeight;
525         }
526         //recompute width or height if any is absent
527         IplImage* ipl_scaled;
528         if ( doRescale )
529         {
530             if ( !new_width )
531             {
532                 new_width  = new_height * ipl->roi->width / ipl->roi->height;
533             }
534             else if ( !new_height ) 
535             {
536                 new_height  = new_width * ipl->roi->height / ipl->roi->width;
537             }
538
539             //rescale
540             ipl_scaled = cvCreateImage( cvSize( new_width, new_height ), IPL_DEPTH_8U, 1 );
541                 
542             iplResizeFit(ipl, ipl_scaled, /*ipl_scaled->width, ipl->width, 
543                       ipl_scaled->height, ipl->height,*/ IPL_INTER_NN);
544                 
545         }
546         else
547             ipl_scaled = ipl;
548
549     
550         CvSize cvroi = cvSize( ipl_scaled->roi ? ipl_scaled->roi->width : ipl_scaled->width,
551                                ipl_scaled->roi ? ipl_scaled->roi->height : ipl_scaled->height);
552     
553     CvSize num_obs;
554     CvImgObsInfo* info;
555     
556     CV_COUNT_OBS( &cvroi, &(params->faceBase->m_dctSize), &(params->faceBase->m_delta), &num_obs ); 
557
558     int vect_len = (params->faceBase->m_obsSize.height)*(params->faceBase->m_obsSize.width);
559
560     if( params->faceBase->m_suppress_intensity )
561     {
562         vect_len--;
563     }
564
565     info = cvCreateObsInfo( num_obs, vect_len );
566
567     
568     if( params->faceBase->m_suppress_intensity )
569     {
570         float* observations = (float*)malloc( num_obs.height * num_obs.width * (vect_len+1) * sizeof(float) );
571         cvImgToObs_DCT( /*normalized_image*/ipl_scaled, observations, params->faceBase->m_dctSize, params->faceBase->m_obsSize, params->faceBase->m_delta );
572         ExtractDCT( observations, info->obs, num_obs.height * num_obs.width, vect_len );
573         free( observations);
574     }
575     else
576     {
577     
578         //IplImage* normalized_image = cvCreateImage( cvroi, IPL_DEPTH_8U, 1 );
579         //NormalizeImageForHMM( ipl_scaled, normalized_image );
580     
581         cvImgToObs_DCT( /*normalized_image*/ipl_scaled, info->obs, params->faceBase->m_dctSize, params->faceBase->m_obsSize, params->faceBase->m_delta );
582
583         //cvReleaseImage(&normalized_image);
584     }
585
586     if ( doRescale )
587     {
588         cvReleaseImage( &ipl_scaled );
589     }
590     
591     float max_like = -100000000; 
592     //int recognized = -1;
593
594     BEGIN_CTRL_THREAD_CORE(params->faceBase->GetPersonList().GetCount());
595
596         CPerson* person = params->faceBase->GetPersonList().GetAt( params->faceBase->GetPersonList().FindIndex(i) );
597         //CvEHMM* hmm = 0;
598         childParams.hmm = 0;
599
600         if( !person->IsTrained() )
601         {
602             code = 0;
603             break;
604         }
605
606         childParams.hmm = person->GetHMM().GetIppiEHMM();
607
608         if (!childParams.hmm) //person not trained
609         {
610             code = 0;
611             break;
612         }
613
614         //cvEstimateObsProb( info, hmm );
615         //like_array[i] = cvEViterbi( info, hmm );
616         childParams.like_array = &(like_array[i]);
617         childParams.info = info;
618
619     END_CTRL_THREAD_CORE();
620
621     for( i = 0; i < MIN(3,params->faceBase->GetPersonList().GetCount()); i ++ )
622     {
623         float maxl = -FLT_MAX;
624         int maxind = -1;
625
626         for( int j = 0; j < params->faceBase->GetPersonList().GetCount(); j++ )
627         {
628             if (like_array[j] > maxl) { maxl = like_array[j]; maxind = j; }
629         }
630         //params->three_first[i] = maxind;
631         ranged[i] = maxind;
632         like_array[maxind] = -FLT_MAX;
633     }
634     cvReleaseObsInfo( &info ); 
635     gray_img.Destroy();
636
637     int result;
638     if( !code ) return result = code;
639
640     //return MIN(3,params->faceBase->GetPersonList().GetCount());
641
642     //int ranged[3];
643     //int result = base.RecognizePerson( camera.GetFrame(), view->GetSelection(), 
644     //                                   ranged );
645     result = MIN(3,params->faceBase->GetPersonList().GetCount());
646
647     if( result == 0 ) 
648     {
649          //MessageBox( params->hwnd, "Not all persons are trained", NULL, MB_ICONERROR );
650          MessageBox( 0, "Not all persons are trained", NULL, MB_ICONERROR );
651     }
652     else
653     {   
654         CString message = "";
655         for( int i = 0 ; i < result; i++ )
656         {
657             CPerson* person = params->base->GetPerson( ranged[i]);
658             message += person->GetName() + "\n";
659         }
660
661         params->baseview->SwitchMode(ranged[0], false);
662         //MessageBox( params->hwnd, (LPCTSTR)message, NULL, MB_ICONEXCLAMATION  );
663         MessageBox( 0, (LPCTSTR)message, "Result of recognition", MB_ICONEXCLAMATION  );
664     }
665
666 END_CTRL_THREAD_FUNCTION();
667
668 BEGIN_START_THREAD_FUNCTION(recognizeThread,
669                             (CImage& image, CRect rect, /*HWND hwnd,*/
670                             CFaceBase& base, CImageBaseView* baseview),InputCtrlChildThread);
671     params->image = &image;
672     params->rect = rect;
673     params->base = &base;
674     params->faceBase = &base;
675     params->baseview = baseview;
676 END_START_THREAD_FUNCTION();
677
678