hmm.cpp 51.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

#define LN2PI 1.837877f
#define BIG_FLT 1.e+10f


#define _CV_ERGODIC 1
#define _CV_CAUSAL 2

#define _CV_LAST_STATE 1
52
#define _CV_BEST_STATE 2
53 54 55 56


//*F///////////////////////////////////////////////////////////////////////////////////////
//    Name: _cvCreateObsInfo
57
//    Purpose: The function allocates memory for CvImgObsInfo structure
58 59 60 61 62 63 64 65 66
//             and its inner stuff
//    Context:
//    Parameters: obs_info - addres of pointer to CvImgObsInfo structure
//                num_hor_obs - number of horizontal observation vectors
//                num_ver_obs - number of horizontal observation vectors
//                obs_size - length of observation vector
//
//    Returns: error status
//
67 68 69
//    Notes:
//F*/
static CvStatus CV_STDCALL icvCreateObsInfo(  CvImgObsInfo** obs_info,
70 71 72
                                           CvSize num_obs, int obs_size )
{
    int total = num_obs.height * num_obs.width;
73

74
    CvImgObsInfo* obs = (CvImgObsInfo*)cvAlloc( sizeof( CvImgObsInfo) );
75

76 77 78 79 80 81
    obs->obs_x = num_obs.width;
    obs->obs_y = num_obs.height;

    obs->obs = (float*)cvAlloc( total * obs_size * sizeof(float) );

    obs->state = (int*)cvAlloc( 2 * total * sizeof(int) );
82 83
    obs->mix = (int*)cvAlloc( total * sizeof(int) );

84 85 86
    obs->obs_size = obs_size;

    obs_info[0] = obs;
87

88 89 90 91 92 93 94 95 96
    return CV_NO_ERR;
}

static CvStatus CV_STDCALL icvReleaseObsInfo( CvImgObsInfo** p_obs_info )
{
    CvImgObsInfo* obs_info = p_obs_info[0];

    cvFree( &(obs_info->obs) );
    cvFree( &(obs_info->mix) );
97
    cvFree( &(obs_info->state) );
98 99 100 101 102
    cvFree( &(obs_info) );

    p_obs_info[0] = NULL;

    return CV_NO_ERR;
103 104
}

105 106 107

//*F///////////////////////////////////////////////////////////////////////////////////////
//    Name: icvCreate2DHMM
108
//    Purpose: The function allocates memory for 2-dimensional embedded HMM model
109 110 111 112
//             and its inner stuff
//    Context:
//    Parameters: hmm - addres of pointer to CvEHMM structure
//                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 115 116 117 118 119 120
//                          size of array is defined by previous array values
//                obs_size - length of observation vectors
//
//    Returns: error status
//
//    Notes: state_number[0] - number of states in external HMM.
//           state_number[i] - number of states in embedded HMM
121
//
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
//           example for face recognition: state_number = { 5 3 6 6 6 3 },
//                                         length of num_mix array = 3+6+6+6+3 = 24//
//
//F*/
static CvStatus CV_STDCALL icvCreate2DHMM( CvEHMM** this_hmm,
                                         int* state_number, int* num_mix, int obs_size )
{
    int i;
    int real_states = 0;

    CvEHMMState* all_states;
    CvEHMM* hmm;
    int total_mix = 0;
    float* pointers;

    //compute total number of states of all level in 2d EHMM
    for( i = 1; i <= state_number[0]; i++ )
    {
        real_states += state_number[i];
    }

    /* allocate memory for all hmms (from all levels) */
    hmm = (CvEHMM*)cvAlloc( (state_number[0] + 1) * sizeof(CvEHMM) );
145

146 147 148
    /* set number of superstates */
    hmm[0].num_states = state_number[0];
    hmm[0].level = 1;
149

150 151 152 153 154 155 156 157 158 159 160 161 162
    /* allocate memory for all states */
    all_states = (CvEHMMState *)cvAlloc( real_states * sizeof( CvEHMMState ) );

    /* assign number of mixtures */
    for( i = 0; i < real_states; i++ )
    {
        all_states[i].num_mix = num_mix[i];
    }

    /* compute size of inner of all real states */
    for( i = 0; i < real_states; i++ )
    {
        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 169 170
    /* organize memory */
    for( i = 0; i < real_states; i++ )
    {
171
        all_states[i].mu      = pointers; pointers += num_mix[i] * obs_size;
172 173 174 175
        all_states[i].inv_var = pointers; pointers += num_mix[i] * obs_size;

        all_states[i].log_var_val = pointers; pointers += num_mix[i];
        all_states[i].weight      = pointers; pointers += num_mix[i];
176 177
    }

178 179
    /* set pointer to embedded hmm array */
    hmm->u.ehmm = hmm + 1;
180

181 182 183 184 185
    for( i = 0; i < hmm[0].num_states; i++ )
    {
        hmm[i+1].u.state = all_states;
        all_states += state_number[i+1];
        hmm[i+1].num_states = state_number[i+1];
186 187
    }

188 189 190 191 192 193
    for( i = 0; i <= state_number[0]; i++ )
    {
        hmm[i].transP = icvCreateMatrix_32f( hmm[i].num_states, hmm[i].num_states );
        hmm[i].obsProb = NULL;
        hmm[i].level = i ? 0 : 1;
    }
194

195 196 197
    /* if all ok - return pointer */
    *this_hmm = hmm;
    return CV_NO_ERR;
198
}
199 200 201

static CvStatus CV_STDCALL icvRelease2DHMM( CvEHMM** phmm )
{
202
    CvEHMM* hmm = phmm[0];
203 204 205 206
    int i;
    for( i = 0; i < hmm[0].num_states + 1; i++ )
    {
        icvDeleteMatrix( hmm[i].transP );
207
    }
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224

    if (hmm->obsProb != NULL)
    {
        int* tmp = ((int*)(hmm->obsProb)) - 3;
        cvFree( &(tmp)  );
    }

    cvFree( &(hmm->u.ehmm->u.state->mu) );
    cvFree( &(hmm->u.ehmm->u.state) );


    /* free hmm structures */
    cvFree( phmm );

    phmm[0] = NULL;

    return CV_NO_ERR;
225
}
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253

/* distance between 2 vectors */
static float icvSquareDistance( CvVect32f v1, CvVect32f v2, int len )
{
    int i;
    double dist0 = 0;
    double dist1 = 0;

    for( i = 0; i <= len - 4; i += 4 )
    {
        double t0 = v1[i] - v2[i];
        double t1 = v1[i+1] - v2[i+1];
        dist0 += t0*t0;
        dist1 += t1*t1;

        t0 = v1[i+2] - v2[i+2];
        t1 = v1[i+3] - v2[i+3];
        dist0 += t0*t0;
        dist1 += t1*t1;
    }

    for( ; i < len; i++ )
    {
        double t0 = v1[i] - v2[i];
        dist0 += t0*t0;
    }

    return (float)(dist0 + dist1);
254
}
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

/*can be used in CHMM & DHMM */
static CvStatus CV_STDCALL
icvUniformImgSegm(  CvImgObsInfo* obs_info, CvEHMM* hmm )
{
#if 1
    /* implementation is very bad */
    int  i, j, counter = 0;
    CvEHMMState* first_state;
    float inv_x = 1.f/obs_info->obs_x;
    float inv_y = 1.f/obs_info->obs_y;

    /* check arguments */
    if ( !obs_info || !hmm ) return CV_NULLPTR_ERR;

    first_state = hmm->u.ehmm->u.state;
271

272 273 274 275
    for (i = 0; i < obs_info->obs_y; i++)
    {
        //bad line (division )
        int superstate = (int)((i * hmm->num_states)*inv_y);/* /obs_info->obs_y; */
276

277 278 279 280 281
        int index = (int)(hmm->u.ehmm[superstate].u.state - first_state);

        for (j = 0; j < obs_info->obs_x; j++, counter++)
        {
            int state = (int)((j * hmm->u.ehmm[superstate].num_states)* inv_x); /* / obs_info->obs_x; */
282

283 284 285
            obs_info->state[2 * counter] = superstate;
            obs_info->state[2 * counter + 1] = state + index;
        }
286
    }
287 288 289 290
#else
    //this is not ready yet

    int i,j,k,m;
291
    CvEHMMState* first_state = hmm->u.ehmm->u.state;
292 293 294 295 296 297 298

    /* check bad arguments */
    if ( hmm->num_states > obs_info->obs_y ) return CV_BADSIZE_ERR;

    //compute vertical subdivision
    float row_per_state = (float)obs_info->obs_y / hmm->num_states;
    float col_per_state[1024]; /* maximum 1024 superstates */
299

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
    //for every horizontal band compute subdivision
    for( i = 0; i < hmm->num_states; i++ )
    {
        CvEHMM* ehmm = &(hmm->u.ehmm[i]);
        col_per_state[i] = (float)obs_info->obs_x / ehmm->num_states;
    }

    //compute state bounds
    int ss_bound[1024];
    for( i = 0; i < hmm->num_states - 1; i++ )
    {
        ss_bound[i] = floor( row_per_state * ( i+1 ) );
    }
    ss_bound[hmm->num_states - 1] = obs_info->obs_y;

    //work inside every superstate

    int row = 0;

    for( i = 0; i < hmm->num_states; i++ )
    {
        CvEHMM* ehmm = &(hmm->u.ehmm[i]);
        int index = ehmm->u.state - first_state;

        //calc distribution in superstate
        int es_bound[1024];
        for( j = 0; j < ehmm->num_states - 1; j++ )
        {
            es_bound[j] = floor( col_per_state[i] * ( j+1 ) );
        }
        es_bound[ehmm->num_states - 1] = obs_info->obs_x;

        //assign states to first row of superstate
        int col = 0;
        for( j = 0; j < ehmm->num_states; j++ )
        {
            for( k = col; k < es_bound[j]; k++, col++ )
            {
                obs_info->state[row * obs_info->obs_x + 2 * k] = i;
                obs_info->state[row * obs_info->obs_x + 2 * k + 1] = j + index;
            }
341
            col = es_bound[j];
342 343 344 345 346
        }

        //copy the same to other rows of superstate
        for( m = row; m < ss_bound[i]; m++ )
        {
347
            memcpy( &(obs_info->state[m * obs_info->obs_x * 2]),
348 349 350
                    &(obs_info->state[row * obs_info->obs_x * 2]), obs_info->obs_x * 2 * sizeof(int) );
        }

351 352
        row = ss_bound[i];
    }
353 354 355 356 357

#endif

    return CV_NO_ERR;
}
358

359 360 361 362 363 364 365 366

/*F///////////////////////////////////////////////////////////////////////////////////////
//    Name: InitMixSegm
//    Purpose: The function implements the mixture segmentation of the states of the
//             embedded HMM
//    Context: used with the Viterbi training of the embedded HMM
//             Function uses K-Means algorithm for clustering
//
367
//    Parameters:  obs_info_array - array of pointers to image observations
368
//                 num_img - length of above array
369 370
//                 hmm - pointer to HMM structure
//
371 372
//    Returns: error status
//
373
//    Notes:
374 375 376
//F*/
static CvStatus CV_STDCALL
icvInitMixSegm( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
377 378
{
    int  k, i, j;
379 380
    int* num_samples; /* number of observations in every state */
    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 386
    int***  samples_mix;   /* for every state - array of pointers to vectors mixtures */

387 388 389
    CvTermCriteria criteria = cvTermCriteria( CV_TERMCRIT_EPS|CV_TERMCRIT_ITER,
                                              1000,    /* iter */
                                              0.01f ); /* eps  */
390

391
    int total = 0;
392 393 394

    CvEHMMState* first_state = hmm->u.ehmm->u.state;

395 396 397
    for( i = 0 ; i < hmm->num_states; i++ )
    {
        total += hmm->u.ehmm[i].num_states;
398 399
    }

400 401
    /* for every state integer is allocated - number of vectors in state */
    num_samples = (int*)cvAlloc( total * sizeof(int) );
402

403 404
    /* integer counter is allocated for every state */
    counter = (int*)cvAlloc( total * sizeof(int) );
405 406 407 408

    samples = (CvVect32f**)cvAlloc( total * sizeof(CvVect32f*) );
    samples_mix = (int***)cvAlloc( total * sizeof(int**) );

409 410 411
    /* clear */
    memset( num_samples, 0 , total*sizeof(int) );
    memset( counter, 0 , total*sizeof(int) );
412 413


414 415
    /* for every state the number of vectors which belong to it is computed (smth. like histogram) */
    for (k = 0; k < num_img; k++)
416
    {
417 418
        CvImgObsInfo* obs = obs_info_array[k];
        int count = 0;
419

420 421 422 423 424 425 426 427
        for (i = 0; i < obs->obs_y; i++)
        {
            for (j = 0; j < obs->obs_x; j++, count++)
            {
                int state = obs->state[ 2 * count + 1];
                num_samples[state] += 1;
            }
        }
428 429
    }

430 431
    /* for every state int* is allocated */
    a_class = (int**)cvAlloc( total*sizeof(int*) );
432

433 434 435 436 437 438
    for (i = 0; i < total; i++)
    {
        a_class[i] = (int*)cvAlloc( num_samples[i] * sizeof(int) );
        samples[i] = (CvVect32f*)cvAlloc( num_samples[i] * sizeof(CvVect32f) );
        samples_mix[i] = (int**)cvAlloc( num_samples[i] * sizeof(int*) );
    }
439

440 441
    /* for every state vectors which belong to state are gathered */
    for (k = 0; k < num_img; k++)
442
    {
443 444 445 446 447 448 449
        CvImgObsInfo* obs = obs_info_array[k];
        int num_obs = ( obs->obs_x ) * ( obs->obs_y );
        float* vector = obs->obs;

        for (i = 0; i < num_obs; i++, vector+=obs->obs_size )
        {
            int state = obs->state[2*i+1];
450

451 452
            samples[state][counter[state]] = vector;
            samples_mix[state][counter[state]] = &(obs->mix[i]);
453
            counter[state]++;
454
        }
455 456
    }

457 458
    /* clear counters */
    memset( counter, 0, total*sizeof(int) );
459

460 461 462 463
    /* do the actual clustering using the K Means algorithm */
    for (i = 0; i < total; i++)
    {
        if ( first_state[i].num_mix == 1)
464
        {
465
            for (k = 0; k < num_samples[i]; k++)
466
            {
467 468 469
                /* all vectors belong to one mixture */
                a_class[i][k] = 0;
            }
470
        }
471 472 473
        else if( num_samples[i] )
        {
            /* 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 480 481 482 483 484 485 486
    /* for every vector number of mixture is assigned */
    for( i = 0; i < total; i++ )
    {
        for (j = 0; j < num_samples[i]; j++)
        {
            samples_mix[i][j][0] = a_class[i][j];
        }
    }
487

488 489 490 491 492 493 494 495 496 497 498
    for (i = 0; i < total; i++)
    {
        cvFree( &(a_class[i]) );
        cvFree( &(samples[i]) );
        cvFree( &(samples_mix[i]) );
    }

    cvFree( &a_class );
    cvFree( &samples );
    cvFree( &samples_mix );
    cvFree( &counter );
499 500
    cvFree( &num_samples );

501 502 503 504 505
    return CV_NO_ERR;
}

/*F///////////////////////////////////////////////////////////////////////////////////////
//    Name: ComputeUniModeGauss
506
//    Purpose: The function computes the Gaussian pdf for a sample vector
507 508 509 510 511 512
//    Context:
//    Parameters:  obsVeq - pointer to the sample vector
//                 mu - pointer to the mean vector of the Gaussian pdf
//                 var - pointer to the variance vector of the Gaussian pdf
//                 VecSize - the size of sample vector
//
513 514 515
//    Returns: the pdf of the sample vector given the specified Gaussian
//
//    Notes:
516
//F*/
517 518
/*static float icvComputeUniModeGauss(CvVect32f vect, CvVect32f mu,
                              CvVect32f inv_var, float log_var_val, int vect_size)
519
{
520
    int n;
521 522 523 524 525 526 527 528 529 530 531
    double tmp;
    double prob;

    prob = -log_var_val;

    for (n = 0; n < vect_size; n++)
    {
        tmp = (vect[n] - mu[n]) * inv_var[n];
        prob = prob - tmp * tmp;
   }
   //prob *= 0.5f;
532

533
   return (float)prob;
534
}*/
535 536 537

/*F///////////////////////////////////////////////////////////////////////////////////////
//    Name: ComputeGaussMixture
538
//    Purpose: The function computes the mixture Gaussian pdf of a sample vector.
539 540 541
//    Context:
//    Parameters:  obsVeq - pointer to the sample vector
//                 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 544
//                       the second dimension is indexed along the size of the mean vector
//                 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 547 548 549 550
//                       the second dimension is indexed along the size of the variance vector
//                 VecSize - the size of sample vector
//                 weight - pointer to the wights of the Gaussian mixture
//                 NumMix - the number of Gaussian mixtures
//
551 552 553
//    Returns: the pdf of the sample vector given the specified Gaussian mixture.
//
//    Notes:
554 555 556
//F*/
/* Calculate probability of observation at state in logarithmic scale*/
/*static float
557 558
icvComputeGaussMixture( CvVect32f vect, float* mu,
                        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 566

    if (num_mix == 1)
    {
567
        return icvComputeUniModeGauss( vect, mu, inv_var, log_var_val[0], vect_size);
568 569 570 571 572 573 574
    }
    else
    {
        int m;
        for (m = 0; m < num_mix; m++)
        {
            if ( weight[m] > 0.0)
575 576
            {
                l_prob = icvComputeUniModeGauss(vect, mu + m*vect_size,
577
                                                        inv_var + m * vect_size,
578 579
                                                        log_var_val[m],
                                                        vect_size);
580 581 582

                prob = prob + weight[m]*exp((double)l_prob);
            }
583 584 585 586 587
        }
        prob = log(prob);
    }
    return (float)prob;
}*/
588 589 590 591


/*F///////////////////////////////////////////////////////////////////////////////////////
//    Name: EstimateObsProb
592
//    Purpose: The function computes the probability of every observation in every state
593 594 595
//    Context:
//    Parameters:  obs_info - observations
//                 hmm      - hmm
596
//    Returns: error status
597
//
598
//    Notes:
599 600 601 602 603 604 605 606
//F*/
static CvStatus CV_STDCALL icvEstimateObsProb( CvImgObsInfo* obs_info, CvEHMM* hmm )
{
    int i, j;
    int total_states = 0;

    /* check if matrix exist and check current size
       if not sufficient - realloc */
607
    int status = 0; /* 1 - not allocated, 2 - allocated but small size,
608 609 610 611 612 613 614
                       3 - size is enough, but distribution is bad, 0 - all ok */

    for( j = 0; j < hmm->num_states; j++ )
    {
       total_states += hmm->u.ehmm[j].num_states;
    }

615
    if ( hmm->obsProb == NULL )
616 617 618 619 620 621 622 623 624 625 626
    {
        /* allocare memory */
        int need_size = ( obs_info->obs_x * obs_info->obs_y * total_states * sizeof(float) +
                          obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f) );

        int* buffer = (int*)cvAlloc( need_size + 3 * sizeof(int) );
        buffer[0] = need_size;
        buffer[1] = obs_info->obs_y;
        buffer[2] = obs_info->obs_x;
        hmm->obsProb = (float**) (buffer + 3);
        status = 3;
627

628 629
    }
    else
630
    {
631 632 633 634 635 636 637
        /* check current size */
        int* total= (int*)(((int*)(hmm->obsProb)) - 3);
        int need_size = ( obs_info->obs_x * obs_info->obs_y * total_states * sizeof(float) +
                          obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f/*(float*)*/ ) );

        assert( sizeof(float*) == sizeof(int) );

638
        if ( need_size > (*total) )
639 640 641 642 643 644 645 646 647
        {
            int* buffer = ((int*)(hmm->obsProb)) - 3;
            cvFree( &buffer);
            buffer = (int*)cvAlloc( need_size + 3 * sizeof(int));
            buffer[0] = need_size;
            buffer[1] = obs_info->obs_y;
            buffer[2] = obs_info->obs_x;

            hmm->obsProb = (float**)(buffer + 3);
648

649
            status = 3;
650
        }
651 652 653 654 655
    }
    if (!status)
    {
        int* obsx = ((int*)(hmm->obsProb)) - 1;
        int* obsy = ((int*)(hmm->obsProb)) - 2;
656

657 658 659
        assert( (*obsx > 0) && (*obsy > 0) );

        /* is good distribution? */
660 661
        if ( (obs_info->obs_x > (*obsx) ) || (obs_info->obs_y > (*obsy) ) )
            status = 3;
662
    }
663

664 665 666 667 668 669 670 671 672 673 674
    /* if bad status - do reallocation actions */
    assert( (status == 0) || (status == 3) );

    if ( status )
    {
        float** tmp = hmm->obsProb;
        float*  tmpf;

        /* distribute pointers of ehmm->obsProb */
        for( i = 0; i < hmm->num_states; i++ )
        {
675
            hmm->u.ehmm[i].obsProb = tmp;
676 677 678 679 680 681 682 683 684
            tmp += obs_info->obs_y;
        }

        tmpf = (float*)tmp;

        /* distribute pointers of ehmm->obsProb[j] */
        for( i = 0; i < hmm->num_states; i++ )
        {
            CvEHMM* ehmm = &( hmm->u.ehmm[i] );
685

686 687 688 689
            for( j = 0; j < obs_info->obs_y; j++ )
            {
                ehmm->obsProb[j] = tmpf;
                tmpf += ehmm->num_states * obs_info->obs_x;
690
            }
691
        }
692
    }/* end of pointer distribution */
693

694
#if 1
695 696 697 698 699 700 701 702 703
    {
#define MAX_BUF_SIZE  1200
        float  local_log_mix_prob[MAX_BUF_SIZE];
        double local_mix_prob[MAX_BUF_SIZE];
        int    vect_size = obs_info->obs_size;
        CvStatus res = CV_NO_ERR;

        float*  log_mix_prob = local_log_mix_prob;
        double* mix_prob = local_mix_prob;
704

705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
        int  max_size = 0;
        int  obs_x = obs_info->obs_x;

        /* calculate temporary buffer size */
        for( i = 0; i < hmm->num_states; i++ )
        {
            CvEHMM* ehmm = &(hmm->u.ehmm[i]);
            CvEHMMState* state = ehmm->u.state;

            int max_mix = 0;
            for( j = 0; j < ehmm->num_states; j++ )
            {
                int t = state[j].num_mix;
                if( max_mix < t ) max_mix = t;
            }
            max_mix *= ehmm->num_states;
            if( max_size < max_mix ) max_size = max_mix;
        }

        max_size *= obs_x * vect_size;
725

726 727 728 729 730 731 732 733 734 735 736
        /* allocate buffer */
        if( max_size > MAX_BUF_SIZE )
        {
            log_mix_prob = (float*)cvAlloc( max_size*(sizeof(float) + sizeof(double)));
            if( !log_mix_prob ) return CV_OUTOFMEM_ERR;
            mix_prob = (double*)(log_mix_prob + max_size);
        }

        memset( log_mix_prob, 0, max_size*sizeof(float));

        /*****************computing probabilities***********************/
737

738 739 740 741 742
        /* loop through external states */
        for( i = 0; i < hmm->num_states; i++ )
        {
            CvEHMM* ehmm = &(hmm->u.ehmm[i]);
            CvEHMMState* state = ehmm->u.state;
743

744 745 746 747 748 749 750 751 752 753 754 755 756 757
            int max_mix = 0;
            int n_states = ehmm->num_states;

            /* determine maximal number of mixtures (again) */
            for( j = 0; j < ehmm->num_states; j++ )
            {
                int t = state[j].num_mix;
                if( max_mix < t ) max_mix = t;
            }

            /* loop through rows of the observation matrix */
            for( j = 0; j < obs_info->obs_y; j++ )
            {
                int  m, n;
758

759 760 761
                float* obs = obs_info->obs + j * obs_x * vect_size;
                float* log_mp = max_mix > 1 ? log_mix_prob : ehmm->obsProb[j];
                double* mp = mix_prob;
762

763
                /* several passes are done below */
764

765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
                /* 1. calculate logarithms of probabilities for each mixture */

                /* loop through mixtures */
                for( m = 0; m < max_mix; m++ )
                {
                    /* set pointer to first observation in the line */
                    float* vect = obs;

                    /* cycles through obseravtions in the line */
                    for( n = 0; n < obs_x; n++, vect += vect_size, log_mp += n_states )
                    {
                        int k, l;
                        for( l = 0; l < n_states; l++ )
                        {
                            if( state[l].num_mix > m )
                            {
                                float* mu = state[l].mu + m*vect_size;
                                float* inv_var = state[l].inv_var + m*vect_size;
                                double prob = -state[l].log_var_val[m];
                                for( k = 0; k < vect_size; k++ )
                                {
                                    double t = (vect[k] - mu[k])*inv_var[k];
                                    prob -= t*t;
                                }
                                log_mp[l] = MAX( (float)prob, -500 );
                            }
                        }
                    }
                }

                /* skip the rest if there is a single mixture */
                if( max_mix == 1 ) continue;

                /* 2. calculate exponent of log_mix_prob
                      (i.e. probability for each mixture) */
                cvbFastExp( log_mix_prob, mix_prob, max_mix * obs_x * n_states );

                /* 3. sum all mixtures with weights */
                /* 3a. first mixture - simply scale by weight */
                for( n = 0; n < obs_x; n++, mp += n_states )
                {
                    int l;
                    for( l = 0; l < n_states; l++ )
                    {
                        mp[l] *= state[l].weight[0];
                    }
                }

                /* 3b. add other mixtures */
                for( m = 1; m < max_mix; m++ )
                {
                    int ofs = -m*obs_x*n_states;
                    for( n = 0; n < obs_x; n++, mp += n_states )
                    {
                        int l;
                        for( l = 0; l < n_states; l++ )
                        {
                            if( m < state[l].num_mix )
                            {
                                mp[l + ofs] += mp[l] * state[l].weight[m];
                            }
                        }
                    }
                }

                /* 4. Put logarithms of summary probabilities to the destination matrix */
                cvbFastLog( mix_prob, ehmm->obsProb[j], obs_x * n_states );
            }
        }

        if( log_mix_prob != local_log_mix_prob ) cvFree( &log_mix_prob );
        return res;
#undef MAX_BUF_SIZE
    }
#else
    for( i = 0; i < hmm->num_states; i++ )
    {
        CvEHMM* ehmm = &(hmm->u.ehmm[i]);
        CvEHMMState* state = ehmm->u.state;

        for( j = 0; j < obs_info->obs_y; j++ )
        {
            int k,m;
848

849 850 851
            int obs_index = j * obs_info->obs_x;

            float* B = ehmm->obsProb[j];
852

853 854 855 856
            /* cycles through obs and states */
            for( k = 0; k < obs_info->obs_x; k++ )
            {
                CvVect32f vect = (obs_info->obs) + (obs_index + k) * vect_size;
857

858 859 860 861
                float* matr_line = B + k * ehmm->num_states;

                for( m = 0; m < ehmm->num_states; m++ )
                {
862
                    matr_line[m] = icvComputeGaussMixture( vect, state[m].mu, state[m].inv_var,
863 864 865 866 867 868 869 870 871 872 873 874
                                                             state[m].log_var_val, vect_size, state[m].weight,
                                                             state[m].num_mix );
                }
            }
        }
    }
#endif
}


/*F///////////////////////////////////////////////////////////////////////////////////////
//    Name: EstimateTransProb
875 876
//    Purpose: The function calculates the state and super state transition probabilities
//             of the model given the images,
877 878
//             the state segmentation and the input parameters
//    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 883
//    Returns: void
//
884
//    Notes:
885 886 887 888 889 890 891 892
//F*/
static CvStatus CV_STDCALL
icvEstimateTransProb( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
{
    int  i, j, k;

    CvEHMMState* first_state = hmm->u.ehmm->u.state;
    /* as a counter we will use transP matrix */
893

894
    /* initialization */
895

896 897 898 899 900 901
    /* clear transP */
    icvSetZero_32f( hmm->transP, hmm->num_states, hmm->num_states );
    for (i = 0; i < hmm->num_states; i++ )
    {
        icvSetZero_32f( hmm->u.ehmm[i].transP , hmm->u.ehmm[i].num_states, hmm->u.ehmm[i].num_states );
    }
902

903 904 905 906 907
    /* compute the counters */
    for (i = 0; i < num_img; i++)
    {
        int counter = 0;
        CvImgObsInfo* info = obs_info_array[i];
908

909 910 911 912 913
        for (j = 0; j < info->obs_y; j++)
        {
            for (k = 0; k < info->obs_x; k++, counter++)
            {
                /* compute how many transitions from state to state
914
                   occured both in horizontal and vertical direction */
915 916 917 918 919 920
                int superstate, state;
                int nextsuperstate, nextstate;
                int begin_ind;

                superstate = info->state[2 * counter];
                begin_ind = (int)(hmm->u.ehmm[superstate].u.state - first_state);
921 922
                state = info->state[ 2 * counter + 1] - begin_ind;

923 924 925
                if (j < info->obs_y - 1)
                {
                    int transP_size = hmm->num_states;
926

927 928 929 930
                    nextsuperstate = info->state[ 2*(counter + info->obs_x) ];

                    hmm->transP[superstate * transP_size + nextsuperstate] += 1;
                }
931

932
                if (k < info->obs_x - 1)
933
                {
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
                    int transP_size = hmm->u.ehmm[superstate].num_states;

                    nextstate = info->state[2*(counter+1) + 1] - begin_ind;
                    hmm->u.ehmm[superstate].transP[ state * transP_size + nextstate] += 1;
                }
            }
        }
    }
    /* estimate superstate matrix */
    for( i = 0; i < hmm->num_states; i++)
    {
        float total = 0;
        float inv_total;
        for( j = 0; j < hmm->num_states; j++)
        {
            total += hmm->transP[i * hmm->num_states + j];
        }
        //assert( total );

        inv_total = total ? 1.f/total : 0;
954

955
        for( j = 0; j < hmm->num_states; j++)
956 957 958
        {
            hmm->transP[i * hmm->num_states + j] =
                hmm->transP[i * hmm->num_states + j] ?
959 960 961
                (float)log( hmm->transP[i * hmm->num_states + j] * inv_total ) : -BIG_FLT;
        }
    }
962

963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
    /* estimate other matrices */
    for( k = 0; k < hmm->num_states; k++ )
    {
        CvEHMM* ehmm = &(hmm->u.ehmm[k]);

        for( i = 0; i < ehmm->num_states; i++)
        {
            float total = 0;
            float inv_total;
            for( j = 0; j < ehmm->num_states; j++)
            {
                total += ehmm->transP[i*ehmm->num_states + j];
            }
            //assert( total );
            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 983 984 985 986 987
                    (ehmm->transP[i * ehmm->num_states + j]) ?
                    (float)log( ehmm->transP[i * ehmm->num_states + j] * inv_total) : -BIG_FLT ;
            }
        }
    }
    return CV_NO_ERR;
988 989
}

990 991 992 993 994 995 996

/*F///////////////////////////////////////////////////////////////////////////////////////
//    Name: MixSegmL2
//    Purpose: The function implements the mixture segmentation of the states of the
//             embedded HMM
//    Context: used with the Viterbi training of the embedded HMM
//
997
//    Parameters:
998 999 1000 1001 1002
//             obs_info_array
//             num_img
//             hmm
//    Returns: void
//
1003
//    Notes:
1004 1005 1006 1007 1008
//F*/
static CvStatus CV_STDCALL
icvMixSegmL2( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
{
    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 1016 1017 1018 1019 1020 1021 1022 1023
        int counter = 0;
        CvImgObsInfo* info = obs_info_array[k];

        for (i = 0; i < info->obs_y; i++)
        {
            for (j = 0; j < info->obs_x; j++, counter++)
            {
                int e_state = info->state[2 * counter + 1];
                float min_dist;
1024 1025

                min_dist = icvSquareDistance((info->obs) + (counter * info->obs_size),
1026
                                               state[e_state].mu, info->obs_size);
1027 1028
                info->mix[counter] = 0;

1029 1030 1031 1032 1033 1034 1035 1036
                for (m = 1; m < state[e_state].num_mix; m++)
                {
                    float dist=icvSquareDistance( (info->obs) + (counter * info->obs_size),
                                                    state[e_state].mu + m * info->obs_size,
                                                    info->obs_size);
                    if (dist < min_dist)
                    {
                        min_dist = dist;
1037
                        /* assign mixture with smallest distance */
1038 1039 1040 1041 1042 1043 1044
                        info->mix[counter] = m;
                    }
                }
            }
        }
    }
    return CV_NO_ERR;
1045
}
1046 1047 1048 1049 1050

/*
CvStatus icvMixSegmProb(CvImgObsInfo* obs_info, int num_img, CvEHMM* hmm )
{
    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 1058 1059 1060 1061 1062 1063 1064 1065
        int counter = 0;
        CvImgObsInfo* info = obs_info + k;

        for (i = 0; i < info->obs_y; i++)
        {
            for (j = 0; j < info->obs_x; j++, counter++)
            {
                int e_state = info->in_state[counter];
                float max_prob;
1066 1067 1068

                max_prob = icvComputeUniModeGauss( info->obs[counter], state[e_state].mu[0],
                                                    state[e_state].inv_var[0],
1069 1070
                                                    state[e_state].log_var[0],
                                                    info->obs_size );
1071 1072
                info->mix[counter] = 0;

1073 1074 1075
                for (m = 1; m < state[e_state].num_mix; m++)
                {
                    float prob=icvComputeUniModeGauss(info->obs[counter], state[e_state].mu[m],
1076
                                                       state[e_state].inv_var[m],
1077 1078 1079 1080 1081
                                                       state[e_state].log_var[m],
                                                       info->obs_size);
                    if (prob > max_prob)
                    {
                        max_prob = prob;
1082
                        // assign mixture with greatest probability.
1083 1084 1085 1086 1087
                        info->mix[counter] = m;
                    }
                }
            }
        }
1088
    }
1089 1090

    return CV_NO_ERR;
1091
}
1092 1093 1094 1095 1096 1097 1098
*/
static CvStatus CV_STDCALL
icvViterbiSegmentation( int num_states, int /*num_obs*/, CvMatr32f transP,
                        CvMatr32f B, int start_obs, int prob_type,
                        int** q, int min_num_obs, int max_num_obs,
                        float* prob )
{
1099
    // memory allocation
1100 1101
    int i, j, last_obs;
    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 1106
    int m_minNumObs  = min_num_obs; /*??*/
    int m_maxNumObs  = max_num_obs; /*??*/
1107

1108
    int m_numStates  = num_states;
1109

1110 1111 1112
    float* m_pi = (float*)cvAlloc( num_states* sizeof(float) );
    CvMatr32f m_a = transP;

1113
    // offset brobability matrix to starting observation
1114 1115 1116
    CvMatr32f m_b = B + start_obs * num_states;
    //so m_xl will not be used more

1117
    //m_xl = start_obs;
1118

1119
    /*     if (muDur != NULL){
1120 1121 1122
    m_d = new int[m_numStates];
    m_l = new double[m_numStates];
    for (i = 0; i < m_numStates; i++){
1123 1124
    m_l[i] = muDur[i];
    }
1125 1126 1127 1128 1129 1130
    }
    else{
    m_d = NULL;
    m_l = NULL;
    }
    */
1131

1132 1133
    CvMatr32f m_Gamma = icvCreateMatrix_32f( num_states, m_maxNumObs );
    int* m_csi = (int*)cvAlloc( num_states * m_maxNumObs * sizeof(int) );
1134

1135 1136
    //stores maximal result for every ending observation */
    CvVect32f   m_MaxGamma = prob;
1137

1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153

//    assert( m_xl + max_num_obs <= num_obs );

    /*??m_q          = new int*[m_maxNumObs - m_minNumObs];
      ??for (i = 0; i < m_maxNumObs - m_minNumObs; i++)
      ??     m_q[i] = new int[m_minNumObs + i + 1];
    */

    /******************************************************************/
    /*    Viterbi initialization                                      */
    /* set initial state probabilities, in logarithmic scale */
    for (i = 0; i < m_numStates; i++)
    {
        m_pi[i] = -BIG_FLT;
    }
    m_pi[0] = 0.0f;
1154

1155 1156 1157
    for  (i = 0; i < num_states; i++)
    {
        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 1165
    if ( m_HMMType == _CV_CAUSAL ) //causal model
    {
1166 1167
        int t;

1168 1169 1170 1171 1172
        for (t = 1 ; t < m_maxNumObs; t++)
        {
            // evaluate self-to-self transition for state 0
            m_Gamma[t * num_states + 0] = m_Gamma[(t-1) * num_states + 0] + m_a[0];
            m_csi[t * num_states + 0] = 0;
1173

1174
            for (j = 1; j < num_states; j++)
1175
            {
1176 1177
                float self = m_Gamma[ (t-1) * num_states + j] + m_a[ j * num_states + j];
                float prev = m_Gamma[ (t-1) * num_states +(j-1)] + m_a[ (j-1) * num_states + j];
1178

1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
                if ( prev > self )
                {
                    m_csi[t * num_states + j] = j-1;
                    m_Gamma[t * num_states + j] = prev;
                }
                else
                {
                    m_csi[t * num_states + j] = j;
                    m_Gamma[t * num_states + j] = self;
                }
1189 1190 1191

                m_Gamma[t * num_states + j] = m_Gamma[t * num_states + j] + m_b[t * num_states + j];
            }
1192 1193
        }
    }
1194 1195
    else if ( m_HMMType == _CV_ERGODIC ) //ergodic model
    {
1196 1197
        int t;
        for (t = 1 ; t < m_maxNumObs; t++)
1198
        {
1199
            for (j = 0; j < num_states; j++)
1200
            {
1201 1202
                m_Gamma[ t*num_states + j] = m_Gamma[(t-1) * num_states + 0] + m_a[0*num_states+j];
                m_csi[t *num_states + j] = 0;
1203

1204 1205
                for (i = 1; i < num_states; i++)
                {
1206
                    float currGamma = m_Gamma[(t-1) *num_states + i] + m_a[i *num_states + j];
1207
                    if (currGamma > m_Gamma[t *num_states + j])
1208
                    {
1209 1210 1211
                        m_Gamma[t * num_states + j] = currGamma;
                        m_csi[t * num_states + j] = i;
                    }
1212
                }
1213
                m_Gamma[t *num_states + j] = m_Gamma[t *num_states + j] + m_b[t * num_states + j];
1214 1215
            }
        }
1216 1217 1218 1219 1220 1221 1222 1223
    }

    for( last_obs = m_minNumObs-1, i = 0; last_obs < m_maxNumObs; last_obs++, i++ )
    {
        int t;

        /******************************************************************/
        /*    Viterbi termination                                         */
1224

1225 1226 1227 1228 1229 1230 1231 1232
        if ( m_ProbType == _CV_LAST_STATE )
        {
            m_MaxGamma[i] = m_Gamma[last_obs * num_states + num_states - 1];
            q[i][last_obs] = num_states - 1;
        }
        else if( m_ProbType == _CV_BEST_STATE )
        {
            int k;
1233 1234 1235
            q[i][last_obs] = 0;
            m_MaxGamma[i] = m_Gamma[last_obs * num_states + 0];

1236
            for(k = 1; k < num_states; k++)
1237
            {
1238 1239 1240 1241
                if ( m_Gamma[last_obs * num_states + k] > m_MaxGamma[i] )
                {
                    m_MaxGamma[i] = m_Gamma[last_obs * num_states + k];
                    q[i][last_obs] = k;
1242
                }
1243
            }
1244 1245
        }

1246 1247 1248 1249
        /******************************************************************/
        /*    Viterbi backtracking                                        */
        for  (t = last_obs-1; t >= 0; t--)
        {
1250 1251 1252 1253
            q[i][t] = m_csi[(t+1) * num_states + q[i][t+1] ];
        }
    }

1254 1255 1256
    /* memory free */
    cvFree( &m_pi );
    cvFree( &m_csi );
1257 1258
    icvDeleteMatrix( m_Gamma );

1259
    return CV_NO_ERR;
1260
}
1261 1262 1263 1264

/*F///////////////////////////////////////////////////////////////////////////////////////
//    Name: icvEViterbi
//    Purpose: The function calculates the embedded Viterbi algorithm
1265
//             for 1 image
1266
//    Context:
1267
//    Parameters:
1268 1269
//             obs_info - observations
//             hmm      - HMM
1270 1271
//
//    Returns: the Embedded Viterbi probability (float)
1272 1273
//             and do state segmentation of observations
//
1274
//    Notes:
1275 1276 1277 1278 1279 1280 1281 1282 1283
//F*/
static float CV_STDCALL icvEViterbi( CvImgObsInfo* obs_info, CvEHMM* hmm )
{
    int    i, j, counter;
    float  log_likelihood;

    float inv_obs_x = 1.f / obs_info->obs_x;

    CvEHMMState* first_state = hmm->u.ehmm->u.state;
1284

1285 1286
    /* memory allocation for superB */
    CvMatr32f superB = icvCreateMatrix_32f(hmm->num_states, obs_info->obs_y );
1287

1288 1289 1290
    /* memory allocation for q */
    int*** q = (int***)cvAlloc( hmm->num_states * sizeof(int**) );
    int* super_q = (int*)cvAlloc( obs_info->obs_y * sizeof(int) );
1291

1292 1293 1294
    for (i = 0; i < hmm->num_states; i++)
    {
        q[i] = (int**)cvAlloc( obs_info->obs_y * sizeof(int*) );
1295

1296 1297 1298 1299
        for (j = 0; j < obs_info->obs_y ; j++)
        {
            q[i][j] = (int*)cvAlloc( obs_info->obs_x * sizeof(int) );
        }
1300 1301
    }

1302 1303 1304 1305
    /* start Viterbi segmentation */
    for (i = 0; i < hmm->num_states; i++)
    {
        CvEHMM* ehmm = &(hmm->u.ehmm[i]);
1306

1307 1308 1309
        for (j = 0; j < obs_info->obs_y; j++)
        {
            float max_gamma;
1310

1311
            /* 1D HMM Viterbi segmentation */
1312 1313
            icvViterbiSegmentation( ehmm->num_states, obs_info->obs_x,
                ehmm->transP, ehmm->obsProb[j], 0,
1314 1315
                _CV_LAST_STATE, &q[i][j], obs_info->obs_x,
                obs_info->obs_x, &max_gamma);
1316

1317 1318 1319
            superB[j * hmm->num_states + i] = max_gamma * inv_obs_x;
        }
    }
1320

1321
    /* perform global Viterbi segmentation (i.e. process higher-level HMM) */
1322 1323 1324

    icvViterbiSegmentation( hmm->num_states, obs_info->obs_y,
                             hmm->transP, superB, 0,
1325 1326
                             _CV_LAST_STATE, &super_q, obs_info->obs_y,
                             obs_info->obs_y, &log_likelihood );
1327 1328 1329 1330

    log_likelihood /= obs_info->obs_y ;


1331 1332 1333
    counter = 0;
    /* assign new state to observation vectors */
    for (i = 0; i < obs_info->obs_y; i++)
1334
    {
1335 1336 1337 1338
        for (j = 0; j < obs_info->obs_x; j++, counter++)
        {
            int superstate = super_q[i];
            int state = (int)(hmm->u.ehmm[superstate].u.state - first_state);
1339

1340 1341 1342 1343
            obs_info->state[2 * counter] = superstate;
            obs_info->state[2 * counter + 1] = state + q[superstate][i][j];
        }
    }
1344

1345 1346
    /* memory deallocation for superB */
    icvDeleteMatrix( superB );
1347

1348 1349 1350 1351 1352 1353 1354 1355 1356
    /*memory deallocation for q */
    for (i = 0; i < hmm->num_states; i++)
    {
        for (j = 0; j < obs_info->obs_y ; j++)
        {
            cvFree( &q[i][j] );
        }
        cvFree( &q[i] );
    }
1357

1358 1359
    cvFree( &q );
    cvFree( &super_q );
1360

1361
    return log_likelihood;
1362
}
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374

static CvStatus CV_STDCALL
icvEstimateHMMStateParams( CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm )
{
    /* compute gamma, weights, means, vars */
    int k, i, j, m;
    int total = 0;
    int vect_len = obs_info_array[0]->obs_size;

    float start_log_var_val = LN2PI * vect_len;

    CvVect32f tmp_vect = icvCreateVector_32f( vect_len );
1375

1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
    CvEHMMState* first_state = hmm->u.ehmm[0].u.state;

    assert( sizeof(float) == sizeof(int) );

    for(i = 0; i < hmm->num_states; i++ )
    {
        total+= hmm->u.ehmm[i].num_states;
    }

    /***************Gamma***********************/
    /* initialize gamma */
    for( i = 0; i < total; i++ )
    {
        for (m = 0; m < first_state[i].num_mix; m++)
        {
            ((int*)(first_state[i].weight))[m] = 0;
1392
        }
1393
    }
1394

1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
    /* maybe gamma must be computed in mixsegm process ?? */

    /* compute gamma */
    for (k = 0; k < num_img; k++)
    {
        CvImgObsInfo* info = obs_info_array[k];
        int num_obs = info->obs_y * info->obs_x;

        for (i = 0; i < num_obs; i++)
        {
            int state, mixture;
            state = info->state[2*i + 1];
            mixture = info->mix[i];
1408 1409 1410
            /* computes gamma - number of observations corresponding
               to every mixture of every state */
            ((int*)(first_state[state].weight))[mixture] += 1;
1411
        }
1412
    }
1413 1414 1415 1416 1417 1418
    /***************Mean and Var***********************/
    /* compute means and variances of every item */
    /* initially variance placed to inv_var */
    /* zero mean and variance */
    for (i = 0; i < total; i++)
    {
1419
        memset( (void*)first_state[i].mu, 0, first_state[i].num_mix * vect_len *
1420
                                                                         sizeof(float) );
1421
        memset( (void*)first_state[i].inv_var, 0, first_state[i].num_mix * vect_len *
1422 1423
                                                                         sizeof(float) );
    }
1424

1425 1426 1427 1428 1429 1430 1431 1432 1433
    /* compute sums */
    for (i = 0; i < num_img; i++)
    {
        CvImgObsInfo* info = obs_info_array[i];
        int total_obs = info->obs_x * info->obs_y;

        float* vector = info->obs;

        for (j = 0; j < total_obs; j++, vector+=vect_len )
1434
        {
1435
            int state = info->state[2 * j + 1];
1436 1437
            int mixture = info->mix[j];

1438 1439
            CvVect32f mean  = first_state[state].mu + mixture * vect_len;
            CvVect32f mean2 = first_state[state].inv_var + mixture * vect_len;
1440

1441 1442 1443
            icvAddVector_32f( mean, vector, mean, vect_len );
            for( k = 0; k < vect_len; k++ )
                mean2[k] += vector[k]*vector[k];
1444
        }
1445
    }
1446

1447 1448 1449
    /*compute the means and variances */
    /* assume gamma already computed */
    for (i = 0; i < total; i++)
1450
    {
1451 1452 1453 1454 1455
        CvEHMMState* state = &(first_state[i]);

        for (m = 0; m < state->num_mix; m++)
        {
            CvVect32f mu  = state->mu + m * vect_len;
1456 1457
            CvVect32f invar = state->inv_var + m * vect_len;

1458 1459 1460
            if ( ((int*)state->weight)[m] > 1)
            {
                float inv_gamma = 1.f/((int*)(state->weight))[m];
1461

1462 1463 1464 1465 1466
                icvScaleVector_32f( mu, mu, vect_len, inv_gamma);
                icvScaleVector_32f( invar, invar, vect_len, inv_gamma);
            }

            icvMulVectors_32f(mu, mu, tmp_vect, vect_len);
1467 1468
            icvSubVector_32f( invar, tmp_vect, invar, vect_len);

1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479
            /* low bound of variance - 100 (Ara's experimental result) */
            for( k = 0; k < vect_len; k++ )
            {
                invar[k] = (invar[k] > 100.f) ? invar[k] : 100.f;
            }

            /* compute log_var */
            state->log_var_val[m] = start_log_var_val;
            for( k = 0; k < vect_len; k++ )
            {
                state->log_var_val[m] += (float)log( invar[k] );
1480
            }
1481 1482 1483 1484 1485 1486 1487 1488 1489 1490

            /* SMOLI 27.10.2000 */
            state->log_var_val[m] *= 0.5;


            /* compute inv_var = 1/sqrt(2*variance) */
            icvScaleVector_32f(invar, invar, vect_len, 2.f );
            cvbInvSqrt( invar, invar, vect_len );
        }
    }
1491

1492 1493
    /***************Weights***********************/
    /* normilize gammas - i.e. compute mixture weights */
1494

1495 1496
    //compute weights
    for (i = 0; i < total; i++)
1497
    {
1498 1499 1500 1501 1502
        int gamma_total = 0;
        float norm;

        for (m = 0; m < first_state[i].num_mix; m++)
        {
1503
            gamma_total += ((int*)(first_state[i].weight))[m];
1504 1505 1506
        }

        norm = gamma_total ? (1.f/(float)gamma_total) : 0.f;
1507

1508 1509 1510
        for (m = 0; m < first_state[i].num_mix; m++)
        {
            first_state[i].weight[m] = ((int*)(first_state[i].weight))[m] * norm;
1511 1512
        }
    }
1513 1514

    icvDeleteVector( tmp_vect);
1515 1516
    return CV_NO_ERR;
}
1517 1518 1519 1520 1521 1522 1523

/*
CvStatus icvLightingCorrection8uC1R( uchar* img, CvSize roi, int src_step )
{
    int i, j;
    int width = roi.width;
    int height = roi.height;
1524

1525 1526 1527
    float x1, x2, y1, y2;
    int f[3] = {0, 0, 0};
    float a[3] = {0, 0, 0};
1528

1529 1530
    float h1;
    float h2;
1531

1532
    float c1,c2;
1533

1534 1535 1536
    float min = FLT_MAX;
    float max = -FLT_MAX;
    float correction;
1537

1538
    float* float_img = icvAlloc( width * height * sizeof(float) );
1539

1540 1541 1542 1543
    x1 = width * (width + 1) / 2.0f; // Sum (1, ... , width)
    x2 = width * (width + 1 ) * (2 * width + 1) / 6.0f; // Sum (1^2, ... , width^2)
    y1 = height * (height + 1)/2.0f; // Sum (1, ... , width)
    y2 = height * (height + 1 ) * (2 * height + 1) / 6.0f; // Sum (1^2, ... , width^2)
1544 1545


1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
    // extract grayvalues
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            f[2] = f[2] + j * img[i*src_step + j];
            f[1] = f[1] + i * img[i*src_step + j];
            f[0] = f[0] +     img[i*src_step + j];
        }
    }
1556

1557 1558
    h1 = (float)f[0] * (float)x1 / (float)width;
    h2 = (float)f[0] * (float)y1 / (float)height;
1559

1560 1561
    a[2] = ((float)f[2] - h1) / (float)(x2*height - x1*x1*height/(float)width);
    a[1] = ((float)f[1] - h2) / (float)(y2*width - y1*y1*width/(float)height);
1562
    a[0] = (float)f[0]/(float)(width*height) - (float)y1*a[1]/(float)height -
1563
        (float)x1*a[2]/(float)width;
1564 1565 1566

    for (i = 0; i < height; i++)
    {
1567 1568
        for (j = 0; j < width; j++)
        {
1569

1570
            correction = a[0] + a[1]*(float)i + a[2]*(float)j;
1571

1572
            float_img[i*width + j] = img[i*src_step + j] - correction;
1573

1574 1575 1576 1577
            if (float_img[i*width + j] < min) min = float_img[i*width+j];
            if (float_img[i*width + j] > max) max = float_img[i*width+j];
        }
    }
1578

1579 1580 1581 1582 1583 1584
    //rescaling to the range 0:255
    c2 = 0;
    if (max == min)
        c2 = 255.0f;
    else
        c2 = 255.0f/(float)(max - min);
1585

1586
    c1 = (-(float)min)*c2;
1587

1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            int value = (int)floor(c2*float_img[i*width + j] + c1);
            if (value < 0) value = 0;
            if (value > 255) value = 255;
            img[i*src_step + j] = (uchar)value;
        }
    }

    cvFree( &float_img );
    return CV_NO_ERR;
}

1603 1604

CvStatus icvLightingCorrection( icvImage* img )
1605 1606 1607 1608 1609 1610
{
    CvSize roi;
    if ( img->type != IPL_DEPTH_8U || img->channels != 1 )
    return CV_BADFACTOR_ERR;

    roi = _cvSize( img->roi.width, img->roi.height );
1611 1612

    return _cvLightingCorrection8uC1R( img->data + img->roi.y * img->step + img->roi.x,
1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697
                                        roi, img->step );

}

*/

CV_IMPL CvEHMM*
cvCreate2DHMM( int *state_number, int *num_mix, int obs_size )
{
    CvEHMM* hmm = 0;

    IPPI_CALL( icvCreate2DHMM( &hmm, state_number, num_mix, obs_size ));

    return hmm;
}

CV_IMPL void
cvRelease2DHMM( CvEHMM ** hmm )
{
    IPPI_CALL( icvRelease2DHMM( hmm ));
}

CV_IMPL CvImgObsInfo*
cvCreateObsInfo( CvSize num_obs, int obs_size )
{
    CvImgObsInfo *obs_info = 0;

    IPPI_CALL( icvCreateObsInfo( &obs_info, num_obs, obs_size ));

    return obs_info;
}

CV_IMPL void
cvReleaseObsInfo( CvImgObsInfo ** obs_info )
{
    IPPI_CALL( icvReleaseObsInfo( obs_info ));
}


CV_IMPL void
cvUniformImgSegm( CvImgObsInfo * obs_info, CvEHMM * hmm )
{
    IPPI_CALL( icvUniformImgSegm( obs_info, hmm ));
}

CV_IMPL void
cvInitMixSegm( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
{
    IPPI_CALL( icvInitMixSegm( obs_info_array, num_img, hmm ));
}

CV_IMPL void
cvEstimateHMMStateParams( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
{
    IPPI_CALL( icvEstimateHMMStateParams( obs_info_array, num_img, hmm ));
}

CV_IMPL void
cvEstimateTransProb( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
{
    IPPI_CALL( icvEstimateTransProb( obs_info_array, num_img, hmm ));
}

CV_IMPL void
cvEstimateObsProb( CvImgObsInfo * obs_info, CvEHMM * hmm )
{
    IPPI_CALL( icvEstimateObsProb( obs_info, hmm ));
}

CV_IMPL float
cvEViterbi( CvImgObsInfo * obs_info, CvEHMM * hmm )
{
    if( (obs_info == NULL) || (hmm == NULL) )
        CV_Error( CV_BadDataPtr, "Null pointer." );

    return icvEViterbi( obs_info, hmm );
}

CV_IMPL void
cvMixSegmL2( CvImgObsInfo ** obs_info_array, int num_img, CvEHMM * hmm )
{
    IPPI_CALL( icvMixSegmL2( obs_info_array, num_img, hmm ));
}

/* End of file */