Home | History | Annotate | Download | only in src
      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 
   1771