Update the changelog
[opencv] / cvaux / src / cvhmm.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*/
41
42 #include "_cvaux.h"
43
44 #define LN2PI 1.837877f
45 #define BIG_FLT 1.e+10f
46
47
48 #define _CV_ERGODIC 1
49 #define _CV_CAUSAL 2
50
51 #define _CV_LAST_STATE 1
52 #define _CV_BEST_STATE 2  
53
54
55 //*F///////////////////////////////////////////////////////////////////////////////////////
56 //    Name: _cvCreateObsInfo
57 //    Purpose: The function allocates memory for CvImgObsInfo structure 
58 //             and its inner stuff
59 //    Context:
60 //    Parameters: obs_info - addres of pointer to CvImgObsInfo structure
61 //                num_hor_obs - number of horizontal observation vectors
62 //                num_ver_obs - number of horizontal observation vectors
63 //                obs_size - length of observation vector
64 //
65 //    Returns: error status
66 //
67 //    Notes:   
68 //F*/      
69 static CvStatus CV_STDCALL icvCreateObsInfo(  CvImgObsInfo** obs_info, 
70                                            CvSize num_obs, int obs_size )
71 {
72     int total = num_obs.height * num_obs.width;
73  
74     CvImgObsInfo* obs = (CvImgObsInfo*)cvAlloc( sizeof( CvImgObsInfo) );
75     
76     obs->obs_x = num_obs.width;
77     obs->obs_y = num_obs.height;
78
79     obs->obs = (float*)cvAlloc( total * obs_size * sizeof(float) );
80
81     obs->state = (int*)cvAlloc( 2 * total * sizeof(int) );
82     obs->mix = (int*)cvAlloc( total * sizeof(int) );  
83         
84     obs->obs_size = obs_size;
85
86     obs_info[0] = obs;
87  
88     return CV_NO_ERR;
89 }
90
91 static CvStatus CV_STDCALL icvReleaseObsInfo( CvImgObsInfo** p_obs_info )
92 {
93     CvImgObsInfo* obs_info = p_obs_info[0];
94
95     cvFree( &(obs_info->obs) );
96     cvFree( &(obs_info->mix) );
97     cvFree( &(obs_info->state) ); 
98     cvFree( &(obs_info) );
99
100     p_obs_info[0] = NULL;
101
102     return CV_NO_ERR;
103
104
105     
106 //*F///////////////////////////////////////////////////////////////////////////////////////
107 //    Name: icvCreate2DHMM
108 //    Purpose: The function allocates memory for 2-dimensional embedded HMM model 
109 //             and its inner stuff
110 //    Context:
111 //    Parameters: hmm - addres of pointer to CvEHMM structure
112 //                state_number - array of hmm sizes (size of array == state_number[0]+1 )
113 //                num_mix - number of gaussian mixtures in low-level HMM states 
114 //                          size of array is defined by previous array values
115 //                obs_size - length of observation vectors
116 //
117 //    Returns: error status
118 //
119 //    Notes: state_number[0] - number of states in external HMM.
120 //           state_number[i] - number of states in embedded HMM
121 //           
122 //           example for face recognition: state_number = { 5 3 6 6 6 3 },
123 //                                         length of num_mix array = 3+6+6+6+3 = 24//
124 //
125 //F*/
126 static CvStatus CV_STDCALL icvCreate2DHMM( CvEHMM** this_hmm,
127                                          int* state_number, int* num_mix, int obs_size )
128 {
129     int i;
130     int real_states = 0;
131
132     CvEHMMState* all_states;
133     CvEHMM* hmm;
134     int total_mix = 0;
135     float* pointers;
136
137     //compute total number of states of all level in 2d EHMM
138     for( i = 1; i <= state_number[0]; i++ )
139     {
140         real_states += state_number[i];
141     }
142
143     /* allocate memory for all hmms (from all levels) */
144     hmm = (CvEHMM*)cvAlloc( (state_number[0] + 1) * sizeof(CvEHMM) );
145     
146     /* set number of superstates */
147     hmm[0].num_states = state_number[0];
148     hmm[0].level = 1;
149         
150     /* allocate memory for all states */
151     all_states = (CvEHMMState *)cvAlloc( real_states * sizeof( CvEHMMState ) );
152
153     /* assign number of mixtures */
154     for( i = 0; i < real_states; i++ )
155     {
156         all_states[i].num_mix = num_mix[i];
157     }
158
159     /* compute size of inner of all real states */
160     for( i = 0; i < real_states; i++ )
161     {
162         total_mix += num_mix[i];
163     } 
164     /* allocate memory for states stuff */
165     pointers = (float*)cvAlloc( total_mix * (2/*for mu invvar */ * obs_size + 
166                                  2/*for weight and log_var_val*/ ) * sizeof( float) );
167     
168     /* organize memory */
169     for( i = 0; i < real_states; i++ )
170     {
171         all_states[i].mu      = pointers; pointers += num_mix[i] * obs_size;  
172         all_states[i].inv_var = pointers; pointers += num_mix[i] * obs_size;
173
174         all_states[i].log_var_val = pointers; pointers += num_mix[i];
175         all_states[i].weight      = pointers; pointers += num_mix[i];
176     }          
177     
178     /* set pointer to embedded hmm array */
179     hmm->u.ehmm = hmm + 1;
180     
181     for( i = 0; i < hmm[0].num_states; i++ )
182     {
183         hmm[i+1].u.state = all_states;
184         all_states += state_number[i+1];
185         hmm[i+1].num_states = state_number[i+1];
186     }                              
187     
188     for( i = 0; i <= state_number[0]; i++ )
189     {
190         hmm[i].transP = icvCreateMatrix_32f( hmm[i].num_states, hmm[i].num_states );
191         hmm[i].obsProb = NULL;
192         hmm[i].level = i ? 0 : 1;
193     }
194     
195     /* if all ok - return pointer */
196     *this_hmm = hmm;
197     return CV_NO_ERR;
198
199
200 static CvStatus CV_STDCALL icvRelease2DHMM( CvEHMM** phmm )
201 {
202     CvEHMM* hmm = phmm[0]; 
203     int i;
204     for( i = 0; i < hmm[0].num_states + 1; i++ )
205     {
206         icvDeleteMatrix( hmm[i].transP );
207     } 
208
209     if (hmm->obsProb != NULL)
210     {
211         int* tmp = ((int*)(hmm->obsProb)) - 3;
212         cvFree( &(tmp)  );
213     }
214
215     cvFree( &(hmm->u.ehmm->u.state->mu) );
216     cvFree( &(hmm->u.ehmm->u.state) );
217
218
219     /* free hmm structures */
220     cvFree( phmm );
221
222     phmm[0] = NULL;
223
224     return CV_NO_ERR;
225 }     
226
227 /* distance between 2 vectors */
228 static float icvSquareDistance( CvVect32f v1, CvVect32f v2, int len )
229 {
230     int i;
231     double dist0 = 0;
232     double dist1 = 0;
233
234     for( i = 0; i <= len - 4; i += 4 )
235     {
236         double t0 = v1[i] - v2[i];
237         double t1 = v1[i+1] - v2[i+1];
238         dist0 += t0*t0;
239         dist1 += t1*t1;
240
241         t0 = v1[i+2] - v2[i+2];
242         t1 = v1[i+3] - v2[i+3];
243         dist0 += t0*t0;
244         dist1 += t1*t1;
245     }
246
247     for( ; i < len; i++ )
248     {
249         double t0 = v1[i] - v2[i];
250         dist0 += t0*t0;
251     }
252
253     return (float)(dist0 + dist1);
254
255
256 /*can be used in CHMM & DHMM */
257 static CvStatus CV_STDCALL
258 icvUniformImgSegm(  CvImgObsInfo* obs_info, CvEHMM* hmm )
259 {
260 #if 1
261     /* implementation is very bad */
262     int  i, j, counter = 0;
263     CvEHMMState* first_state;
264     float inv_x = 1.f/obs_info->obs_x;
265     float inv_y = 1.f/obs_info->obs_y;
266
267     /* check arguments */
268     if ( !obs_info || !hmm ) return CV_NULLPTR_ERR;
269
270     first_state = hmm->u.ehmm->u.state;
271             
272     for (i = 0; i < obs_info->obs_y; i++)
273     {
274         //bad line (division )
275         int superstate = (int)((i * hmm->num_states)*inv_y);/* /obs_info->obs_y; */
276         
277         int index = (int)(hmm->u.ehmm[superstate].u.state - first_state);
278
279         for (j = 0; j < obs_info->obs_x; j++, counter++)
280         {
281             int state = (int)((j * hmm->u.ehmm[superstate].num_states)* inv_x); /* / obs_info->obs_x; */
282             
283             obs_info->state[2 * counter] = superstate;
284             obs_info->state[2 * counter + 1] = state + index;
285         }
286     } 
287 #else
288     //this is not ready yet
289
290     int i,j,k,m;
291     CvEHMMState* first_state = hmm->u.ehmm->u.state; 
292
293     /* check bad arguments */
294     if ( hmm->num_states > obs_info->obs_y ) return CV_BADSIZE_ERR;
295
296     //compute vertical subdivision
297     float row_per_state = (float)obs_info->obs_y / hmm->num_states;
298     float col_per_state[1024]; /* maximum 1024 superstates */
299     
300     //for every horizontal band compute subdivision
301     for( i = 0; i < hmm->num_states; i++ )
302     {
303         CvEHMM* ehmm = &(hmm->u.ehmm[i]);
304         col_per_state[i] = (float)obs_info->obs_x / ehmm->num_states;
305     }
306
307     //compute state bounds
308     int ss_bound[1024];
309     for( i = 0; i < hmm->num_states - 1; i++ )
310     {
311         ss_bound[i] = floor( row_per_state * ( i+1 ) );
312     }
313     ss_bound[hmm->num_states - 1] = obs_info->obs_y;
314
315     //work inside every superstate
316
317     int row = 0;
318
319     for( i = 0; i < hmm->num_states; i++ )
320     {
321         CvEHMM* ehmm = &(hmm->u.ehmm[i]);
322         int index = ehmm->u.state - first_state;
323
324         //calc distribution in superstate
325         int es_bound[1024];
326         for( j = 0; j < ehmm->num_states - 1; j++ )
327         {
328             es_bound[j] = floor( col_per_state[i] * ( j+1 ) );
329         }
330         es_bound[ehmm->num_states - 1] = obs_info->obs_x;
331
332         //assign states to first row of superstate
333         int col = 0;
334         for( j = 0; j < ehmm->num_states; j++ )
335         {
336             for( k = col; k < es_bound[j]; k++, col++ )
337             {
338                 obs_info->state[row * obs_info->obs_x + 2 * k] = i;
339                 obs_info->state[row * obs_info->obs_x + 2 * k + 1] = j + index;
340             }
341             col = es_bound[j]; 
342         }
343
344         //copy the same to other rows of superstate
345         for( m = row; m < ss_bound[i]; m++ )
346         {
347             memcpy( &(obs_info->state[m * obs_info->obs_x * 2]), 
348                     &(obs_info->state[row * obs_info->obs_x * 2]), obs_info->obs_x * 2 * sizeof(int) );
349         }
350
351         row = ss_bound[i];    
352     }   
353
354 #endif
355
356     return CV_NO_ERR;
357 }
358            
359
360 /*F///////////////////////////////////////////////////////////////////////////////////////
361 //    Name: InitMixSegm
362 //    Purpose: The function implements the mixture segmentation of the states of the
363 //             embedded HMM
364 //    Context: used with the Viterbi training of the embedded HMM
365 //             Function uses K-Means algorithm for clustering
366 //
367 //    Parameters:  obs_info_array - array of pointers to image observations 
368 //                 num_img - length of above array
369 //                 hmm - pointer to HMM structure   
370 //     
371 //    Returns: error status
372 //
373 //    Notes: 
374 //F*/
375 static CvStatus CV_STDCALL
376 icvInitMixSegm( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
377 {                                      
378     int  k, i, j; 
379     int* num_samples; /* number of observations in every state */
380     int* counter;     /* array of counters for every state */
381     
382     int**  a_class;   /* for every state - characteristic array */
383     
384     CvVect32f** samples; /* for every state - pointer to observation vectors */
385     int***  samples_mix;   /* for every state - array of pointers to vectors mixtures */   
386     
387     CvTermCriteria criteria = cvTermCriteria( CV_TERMCRIT_EPS|CV_TERMCRIT_ITER,
388                                               1000,    /* iter */
389                                               0.01f ); /* eps  */
390     
391     int total = 0;
392     
393     CvEHMMState* first_state = hmm->u.ehmm->u.state; 
394     
395     for( i = 0 ; i < hmm->num_states; i++ )
396     {
397         total += hmm->u.ehmm[i].num_states;
398     }                                  
399     
400     /* for every state integer is allocated - number of vectors in state */
401     num_samples = (int*)cvAlloc( total * sizeof(int) );
402     
403     /* integer counter is allocated for every state */
404     counter = (int*)cvAlloc( total * sizeof(int) );
405     
406     samples = (CvVect32f**)cvAlloc( total * sizeof(CvVect32f*) ); 
407     samples_mix = (int***)cvAlloc( total * sizeof(int**) ); 
408     
409     /* clear */
410     memset( num_samples, 0 , total*sizeof(int) );
411     memset( counter, 0 , total*sizeof(int) );
412     
413     
414     /* for every state the number of vectors which belong to it is computed (smth. like histogram) */
415     for (k = 0; k < num_img; k++)
416     {  
417         CvImgObsInfo* obs = obs_info_array[k];
418         int count = 0;
419         
420         for (i = 0; i < obs->obs_y; i++)
421         {
422             for (j = 0; j < obs->obs_x; j++, count++)
423             {
424                 int state = obs->state[ 2 * count + 1];
425                 num_samples[state] += 1;
426             }
427         }
428     } 
429     
430     /* for every state int* is allocated */
431     a_class = (int**)cvAlloc( total*sizeof(int*) );
432     
433     for (i = 0; i < total; i++)
434     {
435         a_class[i] = (int*)cvAlloc( num_samples[i] * sizeof(int) );
436         samples[i] = (CvVect32f*)cvAlloc( num_samples[i] * sizeof(CvVect32f) );
437         samples_mix[i] = (int**)cvAlloc( num_samples[i] * sizeof(int*) );
438     }
439     
440     /* for every state vectors which belong to state are gathered */
441     for (k = 0; k < num_img; k++)
442     {  
443         CvImgObsInfo* obs = obs_info_array[k];
444         int num_obs = ( obs->obs_x ) * ( obs->obs_y );
445         float* vector = obs->obs;
446
447         for (i = 0; i < num_obs; i++, vector+=obs->obs_size )
448         {
449             int state = obs->state[2*i+1];
450             
451             samples[state][counter[state]] = vector;
452             samples_mix[state][counter[state]] = &(obs->mix[i]);
453             counter[state]++;            
454         }
455     } 
456     
457     /* clear counters */
458     memset( counter, 0, total*sizeof(int) );
459     
460     /* do the actual clustering using the K Means algorithm */
461     for (i = 0; i < total; i++)
462     {
463         if ( first_state[i].num_mix == 1)
464         {   
465             for (k = 0; k < num_samples[i]; k++)
466             {  
467                 /* all vectors belong to one mixture */
468                 a_class[i][k] = 0;
469             }
470         }      
471         else if( num_samples[i] )
472         {
473             /* clusterize vectors  */
474             cvKMeans( first_state[i].num_mix, samples[i], num_samples[i], 
475                       obs_info_array[0]->obs_size, criteria, a_class[i] );
476         } 
477     }
478     
479     /* for every vector number of mixture is assigned */
480     for( i = 0; i < total; i++ )
481     {
482         for (j = 0; j < num_samples[i]; j++)
483         {
484             samples_mix[i][j][0] = a_class[i][j];
485         }
486     }
487     
488     for (i = 0; i < total; i++)
489     {
490         cvFree( &(a_class[i]) );
491         cvFree( &(samples[i]) );
492         cvFree( &(samples_mix[i]) );
493     }
494
495     cvFree( &a_class );
496     cvFree( &samples );
497     cvFree( &samples_mix );
498     cvFree( &counter );
499     cvFree( &num_samples );  
500     
501     return CV_NO_ERR;
502 }
503
504 /*F///////////////////////////////////////////////////////////////////////////////////////
505 //    Name: ComputeUniModeGauss
506 //    Purpose: The function computes the Gaussian pdf for a sample vector 
507 //    Context:
508 //    Parameters:  obsVeq - pointer to the sample vector
509 //                 mu - pointer to the mean vector of the Gaussian pdf
510 //                 var - pointer to the variance vector of the Gaussian pdf
511 //                 VecSize - the size of sample vector
512 //                 
513 //    Returns: the pdf of the sample vector given the specified Gaussian 
514 //
515 //    Notes: 
516 //F*/
517 /*static float icvComputeUniModeGauss(CvVect32f vect, CvVect32f mu, 
518                               CvVect32f inv_var, float log_var_val, int vect_size)           
519 {
520     int n; 
521     double tmp;
522     double prob;
523
524     prob = -log_var_val;
525
526     for (n = 0; n < vect_size; n++)
527     {
528         tmp = (vect[n] - mu[n]) * inv_var[n];
529         prob = prob - tmp * tmp;
530    }
531    //prob *= 0.5f;
532   
533    return (float)prob;
534 }*/                        
535
536 /*F///////////////////////////////////////////////////////////////////////////////////////
537 //    Name: ComputeGaussMixture
538 //    Purpose: The function computes the mixture Gaussian pdf of a sample vector. 
539 //    Context:
540 //    Parameters:  obsVeq - pointer to the sample vector
541 //                 mu  - two-dimensional pointer to the mean vector of the Gaussian pdf;
542 //                       the first dimension is indexed over the number of mixtures and 
543 //                       the second dimension is indexed along the size of the mean vector
544 //                 var - two-dimensional pointer to the variance vector of the Gaussian pdf;
545 //                       the first dimension is indexed over the number of mixtures and 
546 //                       the second dimension is indexed along the size of the variance vector
547 //                 VecSize - the size of sample vector
548 //                 weight - pointer to the wights of the Gaussian mixture
549 //                 NumMix - the number of Gaussian mixtures
550 //                 
551 //    Returns: the pdf of the sample vector given the specified Gaussian mixture.  
552 //
553 //    Notes: 
554 //F*/
555 /* Calculate probability of observation at state in logarithmic scale*/
556 /*static float
557 icvComputeGaussMixture( CvVect32f vect, float* mu, 
558                         float* inv_var, float* log_var_val, 
559                         int vect_size, float* weight, int num_mix )
560 {       
561     double prob, l_prob;
562     
563     prob = 0.0f; 
564
565     if (num_mix == 1)
566     {
567         return icvComputeUniModeGauss( vect, mu, inv_var, log_var_val[0], vect_size);    
568     }
569     else
570     {
571         int m;
572         for (m = 0; m < num_mix; m++)
573         {
574             if ( weight[m] > 0.0)
575             { 
576                 l_prob = icvComputeUniModeGauss(vect, mu + m*vect_size, 
577                                                         inv_var + m * vect_size,
578                                                         log_var_val[m], 
579                                                         vect_size); 
580
581                 prob = prob + weight[m]*exp((double)l_prob);
582             }
583         } 
584         prob = log(prob);    
585     }                        
586     return (float)prob;   
587 }*/                            
588
589
590 /*F///////////////////////////////////////////////////////////////////////////////////////
591 //    Name: EstimateObsProb
592 //    Purpose: The function computes the probability of every observation in every state 
593 //    Context:
594 //    Parameters:  obs_info - observations
595 //                 hmm      - hmm
596 //    Returns: error status  
597 //
598 //    Notes: 
599 //F*/
600 static CvStatus CV_STDCALL icvEstimateObsProb( CvImgObsInfo* obs_info, CvEHMM* hmm )
601 {
602     int i, j;
603     int total_states = 0;
604
605     /* check if matrix exist and check current size
606        if not sufficient - realloc */
607     int status = 0; /* 1 - not allocated, 2 - allocated but small size, 
608                        3 - size is enough, but distribution is bad, 0 - all ok */
609
610     for( j = 0; j < hmm->num_states; j++ )
611     {
612        total_states += hmm->u.ehmm[j].num_states;
613     }
614
615     if ( hmm->obsProb == NULL ) 
616     {
617         /* allocare memory */
618         int need_size = ( obs_info->obs_x * obs_info->obs_y * total_states * sizeof(float) +
619                           obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f) );
620
621         int* buffer = (int*)cvAlloc( need_size + 3 * sizeof(int) );
622         buffer[0] = need_size;
623         buffer[1] = obs_info->obs_y;
624         buffer[2] = obs_info->obs_x;
625         hmm->obsProb = (float**) (buffer + 3);
626         status = 3;
627         
628     }
629     else
630     {   
631         /* check current size */
632         int* total= (int*)(((int*)(hmm->obsProb)) - 3);
633         int need_size = ( obs_info->obs_x * obs_info->obs_y * total_states * sizeof(float) +
634                           obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f/*(float*)*/ ) );
635
636         assert( sizeof(float*) == sizeof(int) );
637
638         if ( need_size > (*total) ) 
639         {
640             int* buffer = ((int*)(hmm->obsProb)) - 3;
641             cvFree( &buffer);
642             buffer = (int*)cvAlloc( need_size + 3 * sizeof(int));
643             buffer[0] = need_size;
644             buffer[1] = obs_info->obs_y;
645             buffer[2] = obs_info->obs_x;
646
647             hmm->obsProb = (float**)(buffer + 3);
648             
649             status = 3;
650         }          
651     }
652     if (!status)
653     {
654         int* obsx = ((int*)(hmm->obsProb)) - 1;
655         int* obsy = ((int*)(hmm->obsProb)) - 2;
656                 
657         assert( (*obsx > 0) && (*obsy > 0) );
658
659         /* is good distribution? */
660         if ( (obs_info->obs_x > (*obsx) ) || (obs_info->obs_y > (*obsy) ) ) 
661             status = 3;        
662     }
663     
664     /* if bad status - do reallocation actions */
665     assert( (status == 0) || (status == 3) );
666
667     if ( status )
668     {
669         float** tmp = hmm->obsProb;
670         float*  tmpf;
671
672         /* distribute pointers of ehmm->obsProb */
673         for( i = 0; i < hmm->num_states; i++ )
674         {
675             hmm->u.ehmm[i].obsProb = tmp; 
676             tmp += obs_info->obs_y;
677         }
678
679         tmpf = (float*)tmp;
680
681         /* distribute pointers of ehmm->obsProb[j] */
682         for( i = 0; i < hmm->num_states; i++ )
683         {
684             CvEHMM* ehmm = &( hmm->u.ehmm[i] );
685             
686             for( j = 0; j < obs_info->obs_y; j++ )
687             {
688                 ehmm->obsProb[j] = tmpf;
689                 tmpf += ehmm->num_states * obs_info->obs_x;
690             }           
691         }
692     }/* end of pointer distribution */ 
693
694 #if 1    
695     {
696 #define MAX_BUF_SIZE  1200
697         float  local_log_mix_prob[MAX_BUF_SIZE];
698         double local_mix_prob[MAX_BUF_SIZE];
699         int    vect_size = obs_info->obs_size;
700         CvStatus res = CV_NO_ERR;
701
702         float*  log_mix_prob = local_log_mix_prob;
703         double* mix_prob = local_mix_prob;
704         
705         int  max_size = 0;
706         int  obs_x = obs_info->obs_x;
707
708         /* calculate temporary buffer size */
709         for( i = 0; i < hmm->num_states; i++ )
710         {
711             CvEHMM* ehmm = &(hmm->u.ehmm[i]);
712             CvEHMMState* state = ehmm->u.state;
713
714             int max_mix = 0;
715             for( j = 0; j < ehmm->num_states; j++ )
716             {
717                 int t = state[j].num_mix;
718                 if( max_mix < t ) max_mix = t;
719             }
720             max_mix *= ehmm->num_states;
721             if( max_size < max_mix ) max_size = max_mix;
722         }
723
724         max_size *= obs_x * vect_size;
725         
726         /* allocate buffer */
727         if( max_size > MAX_BUF_SIZE )
728         {
729             log_mix_prob = (float*)cvAlloc( max_size*(sizeof(float) + sizeof(double)));
730             if( !log_mix_prob ) return CV_OUTOFMEM_ERR;
731             mix_prob = (double*)(log_mix_prob + max_size);
732         }
733
734         memset( log_mix_prob, 0, max_size*sizeof(float));
735
736         /*****************computing probabilities***********************/
737         
738         /* loop through external states */
739         for( i = 0; i < hmm->num_states; i++ )
740         {
741             CvEHMM* ehmm = &(hmm->u.ehmm[i]);
742             CvEHMMState* state = ehmm->u.state;
743             
744             int max_mix = 0;
745             int n_states = ehmm->num_states;
746
747             /* determine maximal number of mixtures (again) */
748             for( j = 0; j < ehmm->num_states; j++ )
749             {
750                 int t = state[j].num_mix;
751                 if( max_mix < t ) max_mix = t;
752             }
753
754             /* loop through rows of the observation matrix */
755             for( j = 0; j < obs_info->obs_y; j++ )
756             {
757                 int  m, n;
758                        
759                 float* obs = obs_info->obs + j * obs_x * vect_size;
760                 float* log_mp = max_mix > 1 ? log_mix_prob : ehmm->obsProb[j];
761                 double* mp = mix_prob;
762             
763                 /* several passes are done below */
764                 
765                 /* 1. calculate logarithms of probabilities for each mixture */
766
767                 /* loop through mixtures */
768                 for( m = 0; m < max_mix; m++ )
769                 {
770                     /* set pointer to first observation in the line */
771                     float* vect = obs;
772
773                     /* cycles through obseravtions in the line */
774                     for( n = 0; n < obs_x; n++, vect += vect_size, log_mp += n_states )
775                     {
776                         int k, l;
777                         for( l = 0; l < n_states; l++ )
778                         {
779                             if( state[l].num_mix > m )
780                             {
781                                 float* mu = state[l].mu + m*vect_size;
782                                 float* inv_var = state[l].inv_var + m*vect_size;
783                                 double prob = -state[l].log_var_val[m];
784                                 for( k = 0; k < vect_size; k++ )
785                                 {
786                                     double t = (vect[k] - mu[k])*inv_var[k];
787                                     prob -= t*t;
788                                 }
789                                 log_mp[l] = MAX( (float)prob, -500 );
790                             }
791                         }
792                     }
793                 }
794
795                 /* skip the rest if there is a single mixture */
796                 if( max_mix == 1 ) continue;
797
798                 /* 2. calculate exponent of log_mix_prob
799                       (i.e. probability for each mixture) */
800                 cvbFastExp( log_mix_prob, mix_prob, max_mix * obs_x * n_states );
801
802                 /* 3. sum all mixtures with weights */
803                 /* 3a. first mixture - simply scale by weight */
804                 for( n = 0; n < obs_x; n++, mp += n_states )
805                 {
806                     int l;
807                     for( l = 0; l < n_states; l++ )
808                     {
809                         mp[l] *= state[l].weight[0];
810                     }
811                 }
812
813                 /* 3b. add other mixtures */
814                 for( m = 1; m < max_mix; m++ )
815                 {
816                     int ofs = -m*obs_x*n_states;
817                     for( n = 0; n < obs_x; n++, mp += n_states )
818                     {
819                         int l;
820                         for( l = 0; l < n_states; l++ )
821                         {
822                             if( m < state[l].num_mix )
823                             {
824                                 mp[l + ofs] += mp[l] * state[l].weight[m];
825                             }
826                         }
827                     }
828                 }
829
830                 /* 4. Put logarithms of summary probabilities to the destination matrix */
831                 cvbFastLog( mix_prob, ehmm->obsProb[j], obs_x * n_states );
832             }
833         }
834
835         if( log_mix_prob != local_log_mix_prob ) cvFree( &log_mix_prob );
836         return res;
837 #undef MAX_BUF_SIZE
838     }
839 #else
840     for( i = 0; i < hmm->num_states; i++ )
841     {
842         CvEHMM* ehmm = &(hmm->u.ehmm[i]);
843         CvEHMMState* state = ehmm->u.state;
844
845         for( j = 0; j < obs_info->obs_y; j++ )
846         {
847             int k,m;
848                        
849             int obs_index = j * obs_info->obs_x;
850
851             float* B = ehmm->obsProb[j];
852             
853             /* cycles through obs and states */
854             for( k = 0; k < obs_info->obs_x; k++ )
855             {
856                 CvVect32f vect = (obs_info->obs) + (obs_index + k) * vect_size;
857                 
858                 float* matr_line = B + k * ehmm->num_states;
859
860                 for( m = 0; m < ehmm->num_states; m++ )
861                 {
862                     matr_line[m] = icvComputeGaussMixture( vect, state[m].mu, state[m].inv_var, 
863                                                              state[m].log_var_val, vect_size, state[m].weight,
864                                                              state[m].num_mix );
865                 }
866             }
867         }
868     }
869 #endif
870 }
871
872
873 /*F///////////////////////////////////////////////////////////////////////////////////////
874 //    Name: EstimateTransProb
875 //    Purpose: The function calculates the state and super state transition probabilities 
876 //             of the model given the images, 
877 //             the state segmentation and the input parameters
878 //    Context:
879 //    Parameters: obs_info_array - array of pointers to image observations 
880 //                num_img - length of above array
881 //                hmm - pointer to HMM structure                 
882 //    Returns: void
883 //
884 //    Notes:   
885 //F*/
886 static CvStatus CV_STDCALL
887 icvEstimateTransProb( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
888 {
889     int  i, j, k;
890
891     CvEHMMState* first_state = hmm->u.ehmm->u.state;
892     /* as a counter we will use transP matrix */
893     
894     /* initialization */
895     
896     /* clear transP */
897     icvSetZero_32f( hmm->transP, hmm->num_states, hmm->num_states );
898     for (i = 0; i < hmm->num_states; i++ )
899     {
900         icvSetZero_32f( hmm->u.ehmm[i].transP , hmm->u.ehmm[i].num_states, hmm->u.ehmm[i].num_states );
901     }
902         
903     /* compute the counters */
904     for (i = 0; i < num_img; i++)
905     {
906         int counter = 0;
907         CvImgObsInfo* info = obs_info_array[i];
908         
909         for (j = 0; j < info->obs_y; j++)
910         {
911             for (k = 0; k < info->obs_x; k++, counter++)
912             {
913                 /* compute how many transitions from state to state
914                    occured both in horizontal and vertical direction */ 
915                 int superstate, state;
916                 int nextsuperstate, nextstate;
917                 int begin_ind;
918
919                 superstate = info->state[2 * counter];
920                 begin_ind = (int)(hmm->u.ehmm[superstate].u.state - first_state);
921                 state = info->state[ 2 * counter + 1] - begin_ind; 
922                 
923                 if (j < info->obs_y - 1)
924                 {
925                     int transP_size = hmm->num_states;
926                     
927                     nextsuperstate = info->state[ 2*(counter + info->obs_x) ];
928
929                     hmm->transP[superstate * transP_size + nextsuperstate] += 1;
930                 }
931                 
932                 if (k < info->obs_x - 1)
933                 {   
934                     int transP_size = hmm->u.ehmm[superstate].num_states;
935
936                     nextstate = info->state[2*(counter+1) + 1] - begin_ind;
937                     hmm->u.ehmm[superstate].transP[ state * transP_size + nextstate] += 1;
938                 }
939             }
940         }
941     }
942     /* estimate superstate matrix */
943     for( i = 0; i < hmm->num_states; i++)
944     {
945         float total = 0;
946         float inv_total;
947         for( j = 0; j < hmm->num_states; j++)
948         {
949             total += hmm->transP[i * hmm->num_states + j];
950         }
951         //assert( total );
952
953         inv_total = total ? 1.f/total : 0;
954         
955         for( j = 0; j < hmm->num_states; j++)
956         {                   
957             hmm->transP[i * hmm->num_states + j] = 
958                 hmm->transP[i * hmm->num_states + j] ? 
959                 (float)log( hmm->transP[i * hmm->num_states + j] * inv_total ) : -BIG_FLT;
960         }
961     }
962     
963     /* estimate other matrices */
964     for( k = 0; k < hmm->num_states; k++ )
965     {
966         CvEHMM* ehmm = &(hmm->u.ehmm[k]);
967
968         for( i = 0; i < ehmm->num_states; i++)
969         {
970             float total = 0;
971             float inv_total;
972             for( j = 0; j < ehmm->num_states; j++)
973             {
974                 total += ehmm->transP[i*ehmm->num_states + j];
975             }
976             //assert( total );
977             inv_total = total ? 1.f/total :  0;
978             
979             for( j = 0; j < ehmm->num_states; j++)
980             {                   
981                 ehmm->transP[i * ehmm->num_states + j] = 
982                     (ehmm->transP[i * ehmm->num_states + j]) ?
983                     (float)log( ehmm->transP[i * ehmm->num_states + j] * inv_total) : -BIG_FLT ;
984             }
985         }
986     }
987     return CV_NO_ERR;
988
989                       
990
991 /*F///////////////////////////////////////////////////////////////////////////////////////
992 //    Name: MixSegmL2
993 //    Purpose: The function implements the mixture segmentation of the states of the
994 //             embedded HMM
995 //    Context: used with the Viterbi training of the embedded HMM
996 //
997 //    Parameters:  
998 //             obs_info_array
999 //             num_img
1000 //             hmm
1001 //    Returns: void
1002 //
1003 //    Notes: 
1004 //F*/
1005 static CvStatus CV_STDCALL
1006 icvMixSegmL2( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
1007 {
1008     int     k, i, j, m;
1009        
1010     CvEHMMState* state = hmm->u.ehmm[0].u.state;
1011     
1012     
1013     for (k = 0; k < num_img; k++)
1014     {   
1015         int counter = 0;
1016         CvImgObsInfo* info = obs_info_array[k];
1017
1018         for (i = 0; i < info->obs_y; i++)
1019         {
1020             for (j = 0; j < info->obs_x; j++, counter++)
1021             {
1022                 int e_state = info->state[2 * counter + 1];
1023                 float min_dist;
1024                                                 
1025                 min_dist = icvSquareDistance((info->obs) + (counter * info->obs_size), 
1026                                                state[e_state].mu, info->obs_size);
1027                 info->mix[counter] = 0;  
1028                 
1029                 for (m = 1; m < state[e_state].num_mix; m++)
1030                 {
1031                     float dist=icvSquareDistance( (info->obs) + (counter * info->obs_size),
1032                                                     state[e_state].mu + m * info->obs_size,
1033                                                     info->obs_size);
1034                     if (dist < min_dist)
1035                     {
1036                         min_dist = dist;
1037                         /* assign mixture with smallest distance */ 
1038                         info->mix[counter] = m;
1039                     }
1040                 }
1041             }
1042         }
1043     }
1044     return CV_NO_ERR;
1045
1046
1047 /*
1048 CvStatus icvMixSegmProb(CvImgObsInfo* obs_info, int num_img, CvEHMM* hmm )
1049 {
1050     int     k, i, j, m;
1051        
1052     CvEHMMState* state = hmm->ehmm[0].state_info;
1053     
1054     
1055     for (k = 0; k < num_img; k++)
1056     {   
1057         int counter = 0;
1058         CvImgObsInfo* info = obs_info + k;
1059
1060         for (i = 0; i < info->obs_y; i++)
1061         {
1062             for (j = 0; j < info->obs_x; j++, counter++)
1063             {
1064                 int e_state = info->in_state[counter];
1065                 float max_prob;
1066                                                 
1067                 max_prob = icvComputeUniModeGauss( info->obs[counter], state[e_state].mu[0], 
1068                                                     state[e_state].inv_var[0], 
1069                                                     state[e_state].log_var[0],
1070                                                     info->obs_size );
1071                 info->mix[counter] = 0;  
1072                 
1073                 for (m = 1; m < state[e_state].num_mix; m++)
1074                 {
1075                     float prob=icvComputeUniModeGauss(info->obs[counter], state[e_state].mu[m],
1076                                                        state[e_state].inv_var[m], 
1077                                                        state[e_state].log_var[m],
1078                                                        info->obs_size);
1079                     if (prob > max_prob)
1080                     {
1081                         max_prob = prob;
1082                         // assign mixture with greatest probability. 
1083                         info->mix[counter] = m;
1084                     }
1085                 }
1086             }
1087         }
1088     } 
1089
1090     return CV_NO_ERR;
1091
1092 */
1093 static CvStatus CV_STDCALL
1094 icvViterbiSegmentation( int num_states, int /*num_obs*/, CvMatr32f transP,
1095                         CvMatr32f B, int start_obs, int prob_type,
1096                         int** q, int min_num_obs, int max_num_obs,
1097                         float* prob )
1098 {
1099     // memory allocation 
1100     int i, j, last_obs;
1101     int m_HMMType = _CV_ERGODIC; /* _CV_CAUSAL or _CV_ERGODIC */
1102     
1103     int m_ProbType   = prob_type; /* _CV_LAST_STATE or _CV_BEST_STATE */
1104     
1105     int m_minNumObs  = min_num_obs; /*??*/
1106     int m_maxNumObs  = max_num_obs; /*??*/
1107     
1108     int m_numStates  = num_states;
1109     
1110     float* m_pi = (float*)cvAlloc( num_states* sizeof(float) );
1111     CvMatr32f m_a = transP;
1112
1113     // offset brobability matrix to starting observation 
1114     CvMatr32f m_b = B + start_obs * num_states;
1115     //so m_xl will not be used more
1116
1117     //m_xl = start_obs; 
1118
1119     /*     if (muDur != NULL){ 
1120     m_d = new int[m_numStates];
1121     m_l = new double[m_numStates];
1122     for (i = 0; i < m_numStates; i++){
1123     m_l[i] = muDur[i]; 
1124     }
1125     } 
1126     else{
1127     m_d = NULL;
1128     m_l = NULL;
1129     }
1130     */
1131     
1132     CvMatr32f m_Gamma = icvCreateMatrix_32f( num_states, m_maxNumObs );
1133     int* m_csi = (int*)cvAlloc( num_states * m_maxNumObs * sizeof(int) );
1134     
1135     //stores maximal result for every ending observation */
1136     CvVect32f   m_MaxGamma = prob;
1137     
1138
1139 //    assert( m_xl + max_num_obs <= num_obs );
1140
1141     /*??m_q          = new int*[m_maxNumObs - m_minNumObs];
1142       ??for (i = 0; i < m_maxNumObs - m_minNumObs; i++)
1143       ??     m_q[i] = new int[m_minNumObs + i + 1];
1144     */
1145
1146     /******************************************************************/
1147     /*    Viterbi initialization                                      */
1148     /* set initial state probabilities, in logarithmic scale */
1149     for (i = 0; i < m_numStates; i++)
1150     {
1151         m_pi[i] = -BIG_FLT;
1152     }
1153     m_pi[0] = 0.0f;
1154     
1155     for  (i = 0; i < num_states; i++)
1156     {
1157         m_Gamma[0 * num_states + i] = m_pi[i] + m_b[0 * num_states + i];
1158         m_csi[0 * num_states + i] = 0;   
1159     }
1160     
1161     /******************************************************************/
1162     /*    Viterbi recursion                                           */
1163     
1164     if ( m_HMMType == _CV_CAUSAL ) //causal model
1165     {
1166         int t,j;
1167         
1168         for (t = 1 ; t < m_maxNumObs; t++)
1169         {
1170             // evaluate self-to-self transition for state 0
1171             m_Gamma[t * num_states + 0] = m_Gamma[(t-1) * num_states + 0] + m_a[0];
1172             m_csi[t * num_states + 0] = 0;
1173             
1174             for (j = 1; j < num_states; j++)
1175             {  
1176                 float self = m_Gamma[ (t-1) * num_states + j] + m_a[ j * num_states + j];
1177                 float prev = m_Gamma[ (t-1) * num_states +(j-1)] + m_a[ (j-1) * num_states + j];
1178                 
1179                 if ( prev > self )
1180                 {
1181                     m_csi[t * num_states + j] = j-1;
1182                     m_Gamma[t * num_states + j] = prev;
1183                 }
1184                 else
1185                 {
1186                     m_csi[t * num_states + j] = j;
1187                     m_Gamma[t * num_states + j] = self;
1188                 }
1189                 
1190                 m_Gamma[t * num_states + j] = m_Gamma[t * num_states + j] + m_b[t * num_states + j];   
1191             }                                                                    
1192         }
1193     }
1194     else if ( m_HMMType == _CV_ERGODIC ) //ergodic model 
1195     { 
1196         int t;
1197         for (t = 1 ; t < m_maxNumObs; t++)
1198         {     
1199             for (j = 0; j < num_states; j++)
1200             {   
1201                 int i;
1202                 m_Gamma[ t*num_states + j] = m_Gamma[(t-1) * num_states + 0] + m_a[0*num_states+j];
1203                 m_csi[t *num_states + j] = 0;
1204                 
1205                 for (i = 1; i < num_states; i++)
1206                 {
1207                     float currGamma = m_Gamma[(t-1) *num_states + i] + m_a[i *num_states + j];       
1208                     if (currGamma > m_Gamma[t *num_states + j])
1209                     { 
1210                         m_Gamma[t * num_states + j] = currGamma;
1211                         m_csi[t * num_states + j] = i;
1212                     }
1213                 } 
1214                 m_Gamma[t *num_states + j] = m_Gamma[t *num_states + j] + m_b[t * num_states + j];
1215             }             
1216         }                  
1217     }
1218
1219     for( last_obs = m_minNumObs-1, i = 0; last_obs < m_maxNumObs; last_obs++, i++ )
1220     {
1221         int t;
1222
1223         /******************************************************************/
1224         /*    Viterbi termination                                         */
1225     
1226         if ( m_ProbType == _CV_LAST_STATE )
1227         {
1228             m_MaxGamma[i] = m_Gamma[last_obs * num_states + num_states - 1];
1229             q[i][last_obs] = num_states - 1;
1230         }
1231         else if( m_ProbType == _CV_BEST_STATE )
1232         {
1233             int k;
1234             q[i][last_obs] = 0;  
1235             m_MaxGamma[i] = m_Gamma[last_obs * num_states + 0]; 
1236         
1237             for(k = 1; k < num_states; k++)
1238             { 
1239                 if ( m_Gamma[last_obs * num_states + k] > m_MaxGamma[i] )
1240                 {
1241                     m_MaxGamma[i] = m_Gamma[last_obs * num_states + k];
1242                     q[i][last_obs] = k;
1243                 }    
1244             }
1245         } 
1246     
1247         /******************************************************************/
1248         /*    Viterbi backtracking                                        */
1249         for  (t = last_obs-1; t >= 0; t--)
1250         {
1251             q[i][t] = m_csi[(t+1) * num_states + q[i][t+1] ];   
1252         } 
1253     }            
1254     
1255     /* memory free */
1256     cvFree( &m_pi );
1257     cvFree( &m_csi );
1258     icvDeleteMatrix( m_Gamma );   
1259        
1260     return CV_NO_ERR;
1261
1262
1263 /*F///////////////////////////////////////////////////////////////////////////////////////
1264 //    Name: icvEViterbi
1265 //    Purpose: The function calculates the embedded Viterbi algorithm
1266 //             for 1 image 
1267 //    Context:
1268 //    Parameters:  
1269 //             obs_info - observations
1270 //             hmm      - HMM
1271 //                
1272 //    Returns: the Embedded Viterbi probability (float) 
1273 //             and do state segmentation of observations
1274 //
1275 //    Notes: 
1276 //F*/
1277 static float CV_STDCALL icvEViterbi( CvImgObsInfo* obs_info, CvEHMM* hmm )
1278 {
1279     int    i, j, counter;
1280     float  log_likelihood;
1281
1282     float inv_obs_x = 1.f / obs_info->obs_x;
1283
1284     CvEHMMState* first_state = hmm->u.ehmm->u.state;
1285     
1286     /* memory allocation for superB */
1287     CvMatr32f superB = icvCreateMatrix_32f(hmm->num_states, obs_info->obs_y );
1288     
1289     /* memory allocation for q */
1290     int*** q = (int***)cvAlloc( hmm->num_states * sizeof(int**) );
1291     int* super_q = (int*)cvAlloc( obs_info->obs_y * sizeof(int) );
1292     
1293     for (i = 0; i < hmm->num_states; i++)
1294     {
1295         q[i] = (int**)cvAlloc( obs_info->obs_y * sizeof(int*) );
1296         
1297         for (j = 0; j < obs_info->obs_y ; j++)
1298         {
1299             q[i][j] = (int*)cvAlloc( obs_info->obs_x * sizeof(int) );
1300         }
1301     }             
1302     
1303     /* start Viterbi segmentation */
1304     for (i = 0; i < hmm->num_states; i++)
1305     {
1306         CvEHMM* ehmm = &(hmm->u.ehmm[i]);
1307         
1308         for (j = 0; j < obs_info->obs_y; j++)
1309         {
1310             float max_gamma;
1311             
1312             /* 1D HMM Viterbi segmentation */
1313             icvViterbiSegmentation( ehmm->num_states, obs_info->obs_x, 
1314                 ehmm->transP, ehmm->obsProb[j], 0, 
1315                 _CV_LAST_STATE, &q[i][j], obs_info->obs_x,
1316                 obs_info->obs_x, &max_gamma);
1317             
1318             superB[j * hmm->num_states + i] = max_gamma * inv_obs_x;
1319         }
1320     }
1321     
1322     /* perform global Viterbi segmentation (i.e. process higher-level HMM) */
1323     
1324     icvViterbiSegmentation( hmm->num_states, obs_info->obs_y, 
1325                              hmm->transP, superB, 0, 
1326                              _CV_LAST_STATE, &super_q, obs_info->obs_y,
1327                              obs_info->obs_y, &log_likelihood );
1328     
1329     log_likelihood /= obs_info->obs_y ;   
1330     
1331     
1332     counter = 0;
1333     /* assign new state to observation vectors */
1334     for (i = 0; i < obs_info->obs_y; i++)
1335     {   
1336         for (j = 0; j < obs_info->obs_x; j++, counter++)
1337         {
1338             int superstate = super_q[i];
1339             int state = (int)(hmm->u.ehmm[superstate].u.state - first_state);
1340             
1341             obs_info->state[2 * counter] = superstate;
1342             obs_info->state[2 * counter + 1] = state + q[superstate][i][j];
1343         }
1344     }
1345     
1346     /* memory deallocation for superB */
1347     icvDeleteMatrix( superB );
1348     
1349     /*memory deallocation for q */
1350     for (i = 0; i < hmm->num_states; i++)
1351     {
1352         for (j = 0; j < obs_info->obs_y ; j++)
1353         {
1354             cvFree( &q[i][j] );
1355         }
1356         cvFree( &q[i] );
1357     }
1358     
1359     cvFree( &q );
1360     cvFree( &super_q );
1361     
1362     return log_likelihood;
1363 }  
1364
1365 static CvStatus CV_STDCALL
1366 icvEstimateHMMStateParams( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
1367 {
1368     /* compute gamma, weights, means, vars */
1369     int k, i, j, m;
1370     int total = 0;
1371     int vect_len = obs_info_array[0]->obs_size;
1372
1373     float start_log_var_val = LN2PI * vect_len;
1374
1375     CvVect32f tmp_vect = icvCreateVector_32f( vect_len );
1376     
1377     CvEHMMState* first_state = hmm->u.ehmm[0].u.state;
1378
1379     assert( sizeof(float) == sizeof(int) );
1380
1381     for(i = 0; i < hmm->num_states; i++ )
1382     {
1383         total+= hmm->u.ehmm[i].num_states;
1384     }
1385
1386     /***************Gamma***********************/
1387     /* initialize gamma */
1388     for( i = 0; i < total; i++ )
1389     {
1390         for (m = 0; m < first_state[i].num_mix; m++)
1391         {
1392             ((int*)(first_state[i].weight))[m] = 0;
1393         }     
1394     }
1395     
1396     /* maybe gamma must be computed in mixsegm process ?? */
1397
1398     /* compute gamma */
1399     for (k = 0; k < num_img; k++)
1400     {
1401         CvImgObsInfo* info = obs_info_array[k];
1402         int num_obs = info->obs_y * info->obs_x;
1403
1404         for (i = 0; i < num_obs; i++)
1405         {
1406             int state, mixture;
1407             state = info->state[2*i + 1];
1408             mixture = info->mix[i];
1409             /* computes gamma - number of observations corresponding 
1410                to every mixture of every state */ 
1411             ((int*)(first_state[state].weight))[mixture] += 1;              
1412         }
1413     }     
1414     /***************Mean and Var***********************/
1415     /* compute means and variances of every item */
1416     /* initially variance placed to inv_var */
1417     /* zero mean and variance */
1418     for (i = 0; i < total; i++)
1419     {
1420         memset( (void*)first_state[i].mu, 0, first_state[i].num_mix * vect_len * 
1421                                                                          sizeof(float) );
1422         memset( (void*)first_state[i].inv_var, 0, first_state[i].num_mix * vect_len * 
1423                                                                          sizeof(float) );
1424     }
1425     
1426     /* compute sums */
1427     for (i = 0; i < num_img; i++)
1428     {
1429         CvImgObsInfo* info = obs_info_array[i];
1430         int total_obs = info->obs_x * info->obs_y;
1431
1432         float* vector = info->obs;
1433
1434         for (j = 0; j < total_obs; j++, vector+=vect_len )
1435         {   
1436             int state = info->state[2 * j + 1];
1437             int mixture = info->mix[j]; 
1438             
1439             CvVect32f mean  = first_state[state].mu + mixture * vect_len;
1440             CvVect32f mean2 = first_state[state].inv_var + mixture * vect_len;
1441             
1442             icvAddVector_32f( mean, vector, mean, vect_len );
1443             for( k = 0; k < vect_len; k++ )
1444                 mean2[k] += vector[k]*vector[k];
1445         }   
1446     }
1447     
1448     /*compute the means and variances */
1449     /* assume gamma already computed */
1450     for (i = 0; i < total; i++)
1451     {           
1452         CvEHMMState* state = &(first_state[i]);
1453
1454         for (m = 0; m < state->num_mix; m++)
1455         {
1456             int k;
1457             CvVect32f mu  = state->mu + m * vect_len;
1458             CvVect32f invar = state->inv_var + m * vect_len;             
1459             
1460             if ( ((int*)state->weight)[m] > 1)
1461             {
1462                 float inv_gamma = 1.f/((int*)(state->weight))[m];
1463             
1464                 icvScaleVector_32f( mu, mu, vect_len, inv_gamma);
1465                 icvScaleVector_32f( invar, invar, vect_len, inv_gamma);
1466             }
1467
1468             icvMulVectors_32f(mu, mu, tmp_vect, vect_len);
1469             icvSubVector_32f( invar, tmp_vect, invar, vect_len);     
1470             
1471             /* low bound of variance - 100 (Ara's experimental result) */
1472             for( k = 0; k < vect_len; k++ )
1473             {
1474                 invar[k] = (invar[k] > 100.f) ? invar[k] : 100.f;
1475             }
1476
1477             /* compute log_var */
1478             state->log_var_val[m] = start_log_var_val;
1479             for( k = 0; k < vect_len; k++ )
1480             {
1481                 state->log_var_val[m] += (float)log( invar[k] );
1482             }           
1483
1484             /* SMOLI 27.10.2000 */
1485             state->log_var_val[m] *= 0.5;
1486
1487
1488             /* compute inv_var = 1/sqrt(2*variance) */
1489             icvScaleVector_32f(invar, invar, vect_len, 2.f );
1490             cvbInvSqrt( invar, invar, vect_len );
1491         }
1492     }
1493   
1494     /***************Weights***********************/
1495     /* normilize gammas - i.e. compute mixture weights */
1496     
1497     //compute weights
1498     for (i = 0; i < total; i++)
1499     {           
1500         int gamma_total = 0;
1501         float norm;
1502
1503         for (m = 0; m < first_state[i].num_mix; m++)
1504         {
1505             gamma_total += ((int*)(first_state[i].weight))[m];  
1506         }
1507
1508         norm = gamma_total ? (1.f/(float)gamma_total) : 0.f;
1509             
1510         for (m = 0; m < first_state[i].num_mix; m++)
1511         {
1512             first_state[i].weight[m] = ((int*)(first_state[i].weight))[m] * norm;
1513         } 
1514     }                                               
1515
1516     icvDeleteVector( tmp_vect);
1517     return CV_NO_ERR; 
1518 }   
1519
1520 /*
1521 CvStatus icvLightingCorrection8uC1R( uchar* img, CvSize roi, int src_step )
1522 {
1523     int i, j;
1524     int width = roi.width;
1525     int height = roi.height;
1526     
1527     float x1, x2, y1, y2;
1528     int f[3] = {0, 0, 0};
1529     float a[3] = {0, 0, 0};
1530     
1531     float h1;
1532     float h2;
1533     
1534     float c1,c2;
1535     
1536     float min = FLT_MAX;
1537     float max = -FLT_MAX;
1538     float correction;
1539     
1540     float* float_img = icvAlloc( width * height * sizeof(float) );
1541     
1542     x1 = width * (width + 1) / 2.0f; // Sum (1, ... , width)
1543     x2 = width * (width + 1 ) * (2 * width + 1) / 6.0f; // Sum (1^2, ... , width^2)
1544     y1 = height * (height + 1)/2.0f; // Sum (1, ... , width)
1545     y2 = height * (height + 1 ) * (2 * height + 1) / 6.0f; // Sum (1^2, ... , width^2)
1546     
1547     
1548     // extract grayvalues
1549     for (i = 0; i < height; i++)
1550     {
1551         for (j = 0; j < width; j++)
1552         {
1553             f[2] = f[2] + j * img[i*src_step + j];
1554             f[1] = f[1] + i * img[i*src_step + j];
1555             f[0] = f[0] +     img[i*src_step + j];
1556         }
1557     }
1558     
1559     h1 = (float)f[0] * (float)x1 / (float)width;
1560     h2 = (float)f[0] * (float)y1 / (float)height;
1561     
1562     a[2] = ((float)f[2] - h1) / (float)(x2*height - x1*x1*height/(float)width);
1563     a[1] = ((float)f[1] - h2) / (float)(y2*width - y1*y1*width/(float)height);
1564     a[0] = (float)f[0]/(float)(width*height) - (float)y1*a[1]/(float)height - 
1565         (float)x1*a[2]/(float)width;
1566     
1567     for (i = 0; i < height; i++) 
1568     {    
1569         for (j = 0; j < width; j++)
1570         {
1571             
1572             correction = a[0] + a[1]*(float)i + a[2]*(float)j;
1573             
1574             float_img[i*width + j] = img[i*src_step + j] - correction;
1575             
1576             if (float_img[i*width + j] < min) min = float_img[i*width+j];
1577             if (float_img[i*width + j] > max) max = float_img[i*width+j];
1578         }
1579     }
1580     
1581     //rescaling to the range 0:255
1582     c2 = 0;
1583     if (max == min)
1584         c2 = 255.0f;
1585     else
1586         c2 = 255.0f/(float)(max - min);
1587     
1588     c1 = (-(float)min)*c2;
1589     
1590     for (i = 0; i < height; i++)
1591     {
1592         for (j = 0; j < width; j++)
1593         {
1594             int value = (int)floor(c2*float_img[i*width + j] + c1);
1595             if (value < 0) value = 0;
1596             if (value > 255) value = 255;
1597             img[i*src_step + j] = (uchar)value;
1598         }
1599     }
1600
1601     cvFree( &float_img );
1602     return CV_NO_ERR;
1603 }
1604                               
1605
1606 CvStatus icvLightingCorrection( icvImage* img ) 
1607 {
1608     CvSize roi;
1609     if ( img->type != IPL_DEPTH_8U || img->channels != 1 )
1610     return CV_BADFACTOR_ERR;
1611
1612     roi = _cvSize( img->roi.width, img->roi.height );
1613     
1614     return _cvLightingCorrection8uC1R( img->data + img->roi.y * img->step + img->roi.x, 
1615                                         roi, img->step );
1616
1617 }
1618
1619 */
1620
1621 CV_IMPL CvEHMM*
1622 cvCreate2DHMM( int *state_number, int *num_mix, int obs_size )
1623 {
1624     CvEHMM* hmm = 0;
1625
1626     CV_FUNCNAME( "cvCreate2DHMM" );
1627
1628     __BEGIN__;
1629
1630     IPPI_CALL( icvCreate2DHMM( &hmm, state_number, num_mix, obs_size ));
1631
1632     __END__;
1633
1634     return hmm;
1635 }
1636
1637 CV_IMPL void
1638 cvRelease2DHMM( CvEHMM ** hmm )
1639 {
1640     CV_FUNCNAME( "cvRelease2DHMM" );
1641
1642     __BEGIN__;
1643
1644     IPPI_CALL( icvRelease2DHMM( hmm ));
1645     __END__;
1646 }
1647
1648 CV_IMPL CvImgObsInfo*
1649 cvCreateObsInfo( CvSize num_obs, int obs_size )
1650 {
1651     CvImgObsInfo *obs_info = 0;
1652     
1653     CV_FUNCNAME( "cvCreateObsInfo" );
1654
1655     __BEGIN__;
1656
1657     IPPI_CALL( icvCreateObsInfo( &obs_info, num_obs, obs_size ));
1658
1659     __END__;
1660
1661     return obs_info;
1662 }
1663
1664 CV_IMPL void
1665 cvReleaseObsInfo( CvImgObsInfo ** obs_info )
1666 {
1667     CV_FUNCNAME( "cvReleaseObsInfo" );
1668
1669     __BEGIN__;
1670
1671     IPPI_CALL( icvReleaseObsInfo( obs_info ));
1672
1673     __END__;
1674 }
1675
1676
1677 CV_IMPL void
1678 cvUniformImgSegm( CvImgObsInfo * obs_info, CvEHMM * hmm )
1679 {
1680     CV_FUNCNAME( "cvUniformImgSegm" );
1681
1682     __BEGIN__;
1683
1684     IPPI_CALL( icvUniformImgSegm( obs_info, hmm ));
1685     __CLEANUP__;
1686     __END__;
1687 }
1688
1689 CV_IMPL void
1690 cvInitMixSegm( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
1691 {
1692     CV_FUNCNAME( "cvInitMixSegm" );
1693
1694     __BEGIN__;
1695
1696     IPPI_CALL( icvInitMixSegm( obs_info_array, num_img, hmm ));
1697
1698     __END__;
1699 }
1700
1701 CV_IMPL void
1702 cvEstimateHMMStateParams( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
1703 {
1704     CV_FUNCNAME( "cvEstimateHMMStateParams" );
1705
1706     __BEGIN__;
1707
1708     IPPI_CALL( icvEstimateHMMStateParams( obs_info_array, num_img, hmm ));
1709
1710     __END__;
1711 }
1712
1713 CV_IMPL void
1714 cvEstimateTransProb( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
1715 {
1716     CV_FUNCNAME( "cvEstimateTransProb" );
1717
1718     __BEGIN__;
1719
1720     IPPI_CALL( icvEstimateTransProb( obs_info_array, num_img, hmm ));
1721
1722     __END__;
1723
1724 }
1725
1726 CV_IMPL void
1727 cvEstimateObsProb( CvImgObsInfo * obs_info, CvEHMM * hmm )
1728 {
1729     CV_FUNCNAME( "cvEstimateObsProb" );
1730
1731     __BEGIN__;
1732
1733     IPPI_CALL( icvEstimateObsProb( obs_info, hmm ));
1734
1735     __END__;
1736 }
1737
1738 CV_IMPL float
1739 cvEViterbi( CvImgObsInfo * obs_info, CvEHMM * hmm )
1740 {
1741     float result = FLT_MAX;
1742
1743     CV_FUNCNAME( "cvEViterbi" );
1744
1745     __BEGIN__;
1746
1747     if( (obs_info == NULL) || (hmm == NULL) )
1748         CV_ERROR( CV_BadDataPtr, "Null pointer." );
1749
1750     result = icvEViterbi( obs_info, hmm );
1751     
1752     __END__;
1753     
1754     return result;
1755 }
1756
1757 CV_IMPL void
1758 cvMixSegmL2( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
1759 {
1760     CV_FUNCNAME( "cvMixSegmL2" );
1761
1762     __BEGIN__;
1763
1764     IPPI_CALL( icvMixSegmL2( obs_info_array, num_img, hmm ));
1765
1766     __END__;
1767 }
1768
1769 /* End of file */
1770