cvhmm1d.cpp revision 6acb9a7ea3d7564944e12cbc73a857b88c1301ee
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 43#include "_cvaux.h" 44 45#if 0 46 47#define LN2PI 1.837877f 48#define BIG_FLT 1.e+10f 49 50 51#define _CV_ERGODIC 1 52#define _CV_CAUSAL 2 53 54#define _CV_LAST_STATE 1 55#define _CV_BEST_STATE 2 56 57//*F/////////////////////////////////////////////////////////////////////////////////////// 58// Name: icvForward1DHMM 59// Purpose: The function performs baum-welsh algorithm 60// Context: 61// Parameters: obs_info - addres of pointer to CvImgObsInfo structure 62// num_hor_obs - number of horizontal observation vectors 63// num_ver_obs - number of horizontal observation vectors 64// obs_size - length of observation vector 65// 66// Returns: error status 67// 68// Notes: 69//F*/ 70#if 0 71CvStatus icvForward1DHMM( int num_states, int num_obs, CvMatr64d A, 72 CvMatr64d B, 73 double* scales) 74{ 75 // assume that observation and transition 76 // probabilities already computed 77 int m_HMMType = _CV_CAUSAL; 78 double* m_pi = icvAlloc( num_states* sizeof( double) ); 79 80 /* alpha is matrix 81 rows throuhg states 82 columns through time 83 */ 84 double* alpha = icvAlloc( num_states*num_obs * sizeof( double ) ); 85 86 /* All calculations will be in non-logarithmic domain */ 87 88 /* Initialization */ 89 /* set initial state probabilities */ 90 m_pi[0] = 1; 91 for (i = 1; i < num_states; i++) 92 { 93 m_pi[i] = 0.0; 94 } 95 96 for (i = 0; i < num_states; i++) 97 { 98 alpha[i] = m_pi[i] * m_b[ i]; 99 } 100 101 /******************************************************************/ 102 /* Induction */ 103 104 if ( m_HMMType == _CV_ERGODIC ) 105 { 106 int t; 107 for (t = 1 ; t < num_obs; t++) 108 { 109 for (j = 0; j < num_states; j++) 110 { 111 double sum = 0.0; 112 int i; 113 114 for (i = 0; i < num_states; i++) 115 { 116 sum += alpha[(t - 1) * num_states + i] * A[i * num_states + j]; 117 } 118 119 alpha[(t - 1) * num_states + j] = sum * B[t * num_states + j]; 120 121 /* add computed alpha to scale factor */ 122 sum_alpha += alpha[(t - 1) * num_states + j]; 123 } 124 125 double scale = 1/sum_alpha; 126 127 /* scale alpha */ 128 for (j = 0; j < num_states; j++) 129 { 130 alpha[(t - 1) * num_states + j] *= scale; 131 } 132 133 scales[t] = scale; 134 135 } 136 } 137 138#endif 139 140 141 142//*F/////////////////////////////////////////////////////////////////////////////////////// 143// Name: icvCreateObsInfo 144// Purpose: The function allocates memory for CvImgObsInfo structure 145// and its inner stuff 146// Context: 147// Parameters: obs_info - addres of pointer to CvImgObsInfo structure 148// num_hor_obs - number of horizontal observation vectors 149// num_ver_obs - number of horizontal observation vectors 150// obs_size - length of observation vector 151// 152// Returns: error status 153// 154// Notes: 155//F*/ 156/*CvStatus icvCreateObsInfo( CvImgObsInfo** obs_info, 157 CvSize num_obs, int obs_size ) 158{ 159 int total = num_obs.height * num_obs.width; 160 161 CvImgObsInfo* obs = (CvImgObsInfo*)icvAlloc( sizeof( CvImgObsInfo) ); 162 163 obs->obs_x = num_obs.width; 164 obs->obs_y = num_obs.height; 165 166 obs->obs = (float*)icvAlloc( total * obs_size * sizeof(float) ); 167 168 obs->state = (int*)icvAlloc( 2 * total * sizeof(int) ); 169 obs->mix = (int*)icvAlloc( total * sizeof(int) ); 170 171 obs->obs_size = obs_size; 172 173 obs_info[0] = obs; 174 175 return CV_NO_ERR; 176}*/ 177 178/*CvStatus icvReleaseObsInfo( CvImgObsInfo** p_obs_info ) 179{ 180 CvImgObsInfo* obs_info = p_obs_info[0]; 181 182 icvFree( &(obs_info->obs) ); 183 icvFree( &(obs_info->mix) ); 184 icvFree( &(obs_info->state) ); 185 icvFree( &(obs_info) ); 186 187 p_obs_info[0] = NULL; 188 189 return CV_NO_ERR; 190} */ 191 192 193//*F/////////////////////////////////////////////////////////////////////////////////////// 194// Name: icvCreate1DHMM 195// Purpose: The function allocates memory for 1-dimensional HMM 196// and its inner stuff 197// Context: 198// Parameters: hmm - addres of pointer to CvEHMM structure 199// state_number - number of states in HMM 200// num_mix - number of gaussian mixtures in HMM states 201// size of array is defined by previous parameter 202// obs_size - length of observation vectors 203// 204// Returns: error status 205// Notes: 206//F*/ 207CvStatus icvCreate1DHMM( CvEHMM** this_hmm, 208 int state_number, int* num_mix, int obs_size ) 209{ 210 int i; 211 int real_states = state_number; 212 213 CvEHMMState* all_states; 214 CvEHMM* hmm; 215 int total_mix = 0; 216 float* pointers; 217 218 /* allocate memory for hmm */ 219 hmm = (CvEHMM*)icvAlloc( sizeof(CvEHMM) ); 220 221 /* set number of superstates */ 222 hmm->num_states = state_number; 223 hmm->level = 0; 224 225 /* allocate memory for all states */ 226 all_states = (CvEHMMState *)icvAlloc( real_states * sizeof( CvEHMMState ) ); 227 228 /* assign number of mixtures */ 229 for( i = 0; i < real_states; i++ ) 230 { 231 all_states[i].num_mix = num_mix[i]; 232 } 233 234 /* compute size of inner of all real states */ 235 for( i = 0; i < real_states; i++ ) 236 { 237 total_mix += num_mix[i]; 238 } 239 /* allocate memory for states stuff */ 240 pointers = (float*)icvAlloc( total_mix * (2/*for mu invvar */ * obs_size + 241 2/*for weight and log_var_val*/ ) * sizeof( float) ); 242 243 /* organize memory */ 244 for( i = 0; i < real_states; i++ ) 245 { 246 all_states[i].mu = pointers; pointers += num_mix[i] * obs_size; 247 all_states[i].inv_var = pointers; pointers += num_mix[i] * obs_size; 248 249 all_states[i].log_var_val = pointers; pointers += num_mix[i]; 250 all_states[i].weight = pointers; pointers += num_mix[i]; 251 } 252 hmm->u.state = all_states; 253 254 hmm->transP = icvCreateMatrix_32f( hmm->num_states, hmm->num_states ); 255 hmm->obsProb = NULL; 256 257 /* if all ok - return pointer */ 258 *this_hmm = hmm; 259 return CV_NO_ERR; 260} 261 262CvStatus icvRelease1DHMM( CvEHMM** phmm ) 263{ 264 CvEHMM* hmm = phmm[0]; 265 icvDeleteMatrix( hmm->transP ); 266 267 if (hmm->obsProb != NULL) 268 { 269 int* tmp = ((int*)(hmm->obsProb)) - 3; 270 icvFree( &(tmp) ); 271 } 272 273 icvFree( &(hmm->u.state->mu) ); 274 icvFree( &(hmm->u.state) ); 275 276 phmm[0] = NULL; 277 278 return CV_NO_ERR; 279} 280 281/*can be used in CHMM & DHMM */ 282CvStatus icvUniform1DSegm( Cv1DObsInfo* obs_info, CvEHMM* hmm ) 283{ 284 /* implementation is very bad */ 285 int i; 286 CvEHMMState* first_state; 287 288 /* check arguments */ 289 if ( !obs_info || !hmm ) return CV_NULLPTR_ERR; 290 291 first_state = hmm->u.state; 292 293 for (i = 0; i < obs_info->obs_x; i++) 294 { 295 //bad line (division ) 296 int state = (i * hmm->num_states)/obs_info->obs_x; 297 obs_info->state[i] = state; 298 } 299 return CV_NO_ERR; 300} 301 302 303 304/*F/////////////////////////////////////////////////////////////////////////////////////// 305// Name: InitMixSegm 306// Purpose: The function implements the mixture segmentation of the states of the embedded HMM 307// Context: used with the Viterbi training of the embedded HMM 308// Function uses K-Means algorithm for clustering 309// 310// Parameters: obs_info_array - array of pointers to image observations 311// num_img - length of above array 312// hmm - pointer to HMM structure 313// 314// Returns: error status 315// 316// Notes: 317//F*/ 318CvStatus icvInit1DMixSegm(Cv1DObsInfo** obs_info_array, int num_img, CvEHMM* hmm) 319{ 320 int k, i, j; 321 int* num_samples; /* number of observations in every state */ 322 int* counter; /* array of counters for every state */ 323 324 int** a_class; /* for every state - characteristic array */ 325 326 CvVect32f** samples; /* for every state - pointer to observation vectors */ 327 int*** samples_mix; /* for every state - array of pointers to vectors mixtures */ 328 329 CvTermCriteria criteria = cvTermCriteria( CV_TERMCRIT_EPS|CV_TERMCRIT_ITER, 330 1000, /* iter */ 331 0.01f ); /* eps */ 332 333 int total = hmm->num_states; 334 CvEHMMState* first_state = hmm->u.state; 335 336 /* for every state integer is allocated - number of vectors in state */ 337 num_samples = (int*)icvAlloc( total * sizeof(int) ); 338 339 /* integer counter is allocated for every state */ 340 counter = (int*)icvAlloc( total * sizeof(int) ); 341 342 samples = (CvVect32f**)icvAlloc( total * sizeof(CvVect32f*) ); 343 samples_mix = (int***)icvAlloc( total * sizeof(int**) ); 344 345 /* clear */ 346 memset( num_samples, 0 , total*sizeof(int) ); 347 memset( counter, 0 , total*sizeof(int) ); 348 349 350 /* for every state the number of vectors which belong to it is computed (smth. like histogram) */ 351 for (k = 0; k < num_img; k++) 352 { 353 CvImgObsInfo* obs = obs_info_array[k]; 354 355 for (i = 0; i < obs->obs_x; i++) 356 { 357 int state = obs->state[ i ]; 358 num_samples[state] += 1; 359 } 360 } 361 362 /* for every state int* is allocated */ 363 a_class = (int**)icvAlloc( total*sizeof(int*) ); 364 365 for (i = 0; i < total; i++) 366 { 367 a_class[i] = (int*)icvAlloc( num_samples[i] * sizeof(int) ); 368 samples[i] = (CvVect32f*)icvAlloc( num_samples[i] * sizeof(CvVect32f) ); 369 samples_mix[i] = (int**)icvAlloc( num_samples[i] * sizeof(int*) ); 370 } 371 372 /* for every state vectors which belong to state are gathered */ 373 for (k = 0; k < num_img; k++) 374 { 375 CvImgObsInfo* obs = obs_info_array[k]; 376 int num_obs = obs->obs_x; 377 float* vector = obs->obs; 378 379 for (i = 0; i < num_obs; i++, vector+=obs->obs_size ) 380 { 381 int state = obs->state[i]; 382 383 samples[state][counter[state]] = vector; 384 samples_mix[state][counter[state]] = &(obs->mix[i]); 385 counter[state]++; 386 } 387 } 388 389 /* clear counters */ 390 memset( counter, 0, total*sizeof(int) ); 391 392 /* do the actual clustering using the K Means algorithm */ 393 for (i = 0; i < total; i++) 394 { 395 if ( first_state[i].num_mix == 1) 396 { 397 for (k = 0; k < num_samples[i]; k++) 398 { 399 /* all vectors belong to one mixture */ 400 a_class[i][k] = 0; 401 } 402 } 403 else if( num_samples[i] ) 404 { 405 /* clusterize vectors */ 406 icvKMeans( first_state[i].num_mix, samples[i], num_samples[i], 407 obs_info_array[0]->obs_size, criteria, a_class[i] ); 408 } 409 } 410 411 /* for every vector number of mixture is assigned */ 412 for( i = 0; i < total; i++ ) 413 { 414 for (j = 0; j < num_samples[i]; j++) 415 { 416 samples_mix[i][j][0] = a_class[i][j]; 417 } 418 } 419 420 for (i = 0; i < total; i++) 421 { 422 icvFree( &(a_class[i]) ); 423 icvFree( &(samples[i]) ); 424 icvFree( &(samples_mix[i]) ); 425 } 426 427 icvFree( &a_class ); 428 icvFree( &samples ); 429 icvFree( &samples_mix ); 430 icvFree( &counter ); 431 icvFree( &num_samples ); 432 433 434 return CV_NO_ERR; 435} 436 437/*F/////////////////////////////////////////////////////////////////////////////////////// 438// Name: ComputeUniModeGauss 439// Purpose: The function computes the Gaussian pdf for a sample vector 440// Context: 441// Parameters: obsVeq - pointer to the sample vector 442// mu - pointer to the mean vector of the Gaussian pdf 443// var - pointer to the variance vector of the Gaussian pdf 444// VecSize - the size of sample vector 445// 446// Returns: the pdf of the sample vector given the specified Gaussian 447// 448// Notes: 449//F*/ 450/*float icvComputeUniModeGauss(CvVect32f vect, CvVect32f mu, 451 CvVect32f inv_var, float log_var_val, int vect_size) 452{ 453 int n; 454 double tmp; 455 double prob; 456 457 prob = -log_var_val; 458 459 for (n = 0; n < vect_size; n++) 460 { 461 tmp = (vect[n] - mu[n]) * inv_var[n]; 462 prob = prob - tmp * tmp; 463 } 464 //prob *= 0.5f; 465 466 return (float)prob; 467}*/ 468 469/*F/////////////////////////////////////////////////////////////////////////////////////// 470// Name: ComputeGaussMixture 471// Purpose: The function computes the mixture Gaussian pdf of a sample vector. 472// Context: 473// Parameters: obsVeq - pointer to the sample vector 474// mu - two-dimensional pointer to the mean vector of the Gaussian pdf; 475// the first dimension is indexed over the number of mixtures and 476// the second dimension is indexed along the size of the mean vector 477// var - two-dimensional pointer to the variance vector of the Gaussian pdf; 478// the first dimension is indexed over the number of mixtures and 479// the second dimension is indexed along the size of the variance vector 480// VecSize - the size of sample vector 481// weight - pointer to the wights of the Gaussian mixture 482// NumMix - the number of Gaussian mixtures 483// 484// Returns: the pdf of the sample vector given the specified Gaussian mixture. 485// 486// Notes: 487//F*/ 488/* Calculate probability of observation at state in logarithmic scale*/ 489/*float icvComputeGaussMixture( CvVect32f vect, float* mu, 490 float* inv_var, float* log_var_val, 491 int vect_size, float* weight, int num_mix ) 492{ 493 double prob, l_prob; 494 495 prob = 0.0f; 496 497 if (num_mix == 1) 498 { 499 return icvComputeUniModeGauss( vect, mu, inv_var, log_var_val[0], vect_size); 500 } 501 else 502 { 503 int m; 504 for (m = 0; m < num_mix; m++) 505 { 506 if ( weight[m] > 0.0) 507 { 508 l_prob = icvComputeUniModeGauss(vect, mu + m*vect_size, 509 inv_var + m * vect_size, 510 log_var_val[m], 511 vect_size); 512 513 prob = prob + weight[m]*exp((double)l_prob); 514 } 515 } 516 prob = log(prob); 517 } 518 return (float)prob; 519} 520*/ 521 522/*F/////////////////////////////////////////////////////////////////////////////////////// 523// Name: EstimateObsProb 524// Purpose: The function computes the probability of every observation in every state 525// Context: 526// Parameters: obs_info - observations 527// hmm - hmm 528// Returns: error status 529// 530// Notes: 531//F*/ 532CvStatus icvEstimate1DObsProb(CvImgObsInfo* obs_info, CvEHMM* hmm ) 533{ 534 int j; 535 int total_states = 0; 536 537 /* check if matrix exist and check current size 538 if not sufficient - realloc */ 539 int status = 0; /* 1 - not allocated, 2 - allocated but small size, 540 3 - size is enough, but distribution is bad, 0 - all ok */ 541 542 /*for( j = 0; j < hmm->num_states; j++ ) 543 { 544 total_states += hmm->u.ehmm[j].num_states; 545 }*/ 546 total_states = hmm->num_states; 547 548 if ( hmm->obsProb == NULL ) 549 { 550 /* allocare memory */ 551 int need_size = ( obs_info->obs_x /* * obs_info->obs_y*/ * total_states * sizeof(float) /* + 552 obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f) */); 553 554 int* buffer = (int*)icvAlloc( need_size + 3 * sizeof(int) ); 555 buffer[0] = need_size; 556 buffer[1] = obs_info->obs_y; 557 buffer[2] = obs_info->obs_x; 558 hmm->obsProb = (float**) (buffer + 3); 559 status = 3; 560 561 } 562 else 563 { 564 /* check current size */ 565 int* total= (int*)(((int*)(hmm->obsProb)) - 3); 566 int need_size = ( obs_info->obs_x /* * obs_info->obs_y*/ * total_states * sizeof(float) /* + 567 obs_info->obs_y * hmm->num_states * sizeof( CvMatr32f(float*) )*/ ); 568 569 assert( sizeof(float*) == sizeof(int) ); 570 571 if ( need_size > (*total) ) 572 { 573 int* buffer = ((int*)(hmm->obsProb)) - 3; 574 icvFree( &buffer); 575 buffer = (int*)icvAlloc( need_size + 3); 576 buffer[0] = need_size; 577 buffer[1] = obs_info->obs_y; 578 buffer[2] = obs_info->obs_x; 579 580 hmm->obsProb = (float**)(buffer + 3); 581 582 status = 3; 583 } 584 } 585 if (!status) 586 { 587 int* obsx = ((int*)(hmm->obsProb)) - 1; 588 //int* obsy = ((int*)(hmm->obsProb)) - 2; 589 590 assert( /*(*obsy > 0) &&*/ (*obsx > 0) ); 591 592 /* is good distribution? */ 593 if ( (obs_info->obs_x > (*obsx) ) /* || (obs_info->obs_y > (*obsy) ) */ ) 594 status = 3; 595 } 596 597 assert( (status == 0) || (status == 3) ); 598 /* if bad status - do reallocation actions */ 599 if ( status ) 600 { 601 float** tmp = hmm->obsProb; 602 //float* tmpf; 603 604 /* distribute pointers of ehmm->obsProb */ 605/* for( i = 0; i < hmm->num_states; i++ ) 606 { 607 hmm->u.ehmm[i].obsProb = tmp; 608 tmp += obs_info->obs_y; 609 } 610*/ 611 //tmpf = (float*)tmp; 612 613 /* distribute pointers of ehmm->obsProb[j] */ 614/* for( i = 0; i < hmm->num_states; i++ ) 615 { 616 CvEHMM* ehmm = &( hmm->u.ehmm[i] ); 617 618 for( j = 0; j < obs_info->obs_y; j++ ) 619 { 620 ehmm->obsProb[j] = tmpf; 621 tmpf += ehmm->num_states * obs_info->obs_x; 622 } 623 } 624*/ 625 hmm->obsProb = tmp; 626 627 }/* end of pointer distribution */ 628 629#if 1 630 { 631#define MAX_BUF_SIZE 1200 632 float local_log_mix_prob[MAX_BUF_SIZE]; 633 double local_mix_prob[MAX_BUF_SIZE]; 634 int vect_size = obs_info->obs_size; 635 CvStatus res = CV_NO_ERR; 636 637 float* log_mix_prob = local_log_mix_prob; 638 double* mix_prob = local_mix_prob; 639 640 int max_size = 0; 641 int obs_x = obs_info->obs_x; 642 643 /* calculate temporary buffer size */ 644 //for( i = 0; i < hmm->num_states; i++ ) 645 //{ 646 // CvEHMM* ehmm = &(hmm->u.ehmm[i]); 647 CvEHMMState* state = hmm->u.state; 648 649 int max_mix = 0; 650 for( j = 0; j < hmm->num_states; j++ ) 651 { 652 int t = state[j].num_mix; 653 if( max_mix < t ) max_mix = t; 654 } 655 max_mix *= hmm->num_states; 656 /*if( max_size < max_mix )*/ max_size = max_mix; 657 //} 658 659 max_size *= obs_x * vect_size; 660 661 /* allocate buffer */ 662 if( max_size > MAX_BUF_SIZE ) 663 { 664 log_mix_prob = (float*)icvAlloc( max_size*(sizeof(float) + sizeof(double))); 665 if( !log_mix_prob ) return CV_OUTOFMEM_ERR; 666 mix_prob = (double*)(log_mix_prob + max_size); 667 } 668 669 memset( log_mix_prob, 0, max_size*sizeof(float)); 670 671 /*****************computing probabilities***********************/ 672 673 /* loop through external states */ 674 //for( i = 0; i < hmm->num_states; i++ ) 675 { 676 // CvEHMM* ehmm = &(hmm->u.ehmm[i]); 677 CvEHMMState* state = hmm->u.state; 678 679 int max_mix = 0; 680 int n_states = hmm->num_states; 681 682 /* determine maximal number of mixtures (again) */ 683 for( j = 0; j < hmm->num_states; j++ ) 684 { 685 int t = state[j].num_mix; 686 if( max_mix < t ) max_mix = t; 687 } 688 689 /* loop through rows of the observation matrix */ 690 //for( j = 0; j < obs_info->obs_y; j++ ) 691 { 692 int m, n; 693 694 float* obs = obs_info->obs;/* + j * obs_x * vect_size; */ 695 float* log_mp = max_mix > 1 ? log_mix_prob : (float*)(hmm->obsProb); 696 double* mp = mix_prob; 697 698 /* several passes are done below */ 699 700 /* 1. calculate logarithms of probabilities for each mixture */ 701 702 /* loop through mixtures */ 703 /* !!!! */ for( m = 0; m < max_mix; m++ ) 704 { 705 /* set pointer to first observation in the line */ 706 float* vect = obs; 707 708 /* cycles through obseravtions in the line */ 709 for( n = 0; n < obs_x; n++, vect += vect_size, log_mp += n_states ) 710 { 711 int k, l; 712 for( l = 0; l < n_states; l++ ) 713 { 714 if( state[l].num_mix > m ) 715 { 716 float* mu = state[l].mu + m*vect_size; 717 float* inv_var = state[l].inv_var + m*vect_size; 718 double prob = -state[l].log_var_val[m]; 719 for( k = 0; k < vect_size; k++ ) 720 { 721 double t = (vect[k] - mu[k])*inv_var[k]; 722 prob -= t*t; 723 } 724 log_mp[l] = MAX( (float)prob, -500 ); 725 } 726 } 727 } 728 } 729 730 /* skip the rest if there is a single mixture */ 731 if( max_mix != 1 ) 732 { 733 /* 2. calculate exponent of log_mix_prob 734 (i.e. probability for each mixture) */ 735 res = icvbExp_32f64f( log_mix_prob, mix_prob, 736 max_mix * obs_x * n_states ); 737 if( res < 0 ) goto processing_exit; 738 739 /* 3. sum all mixtures with weights */ 740 /* 3a. first mixture - simply scale by weight */ 741 for( n = 0; n < obs_x; n++, mp += n_states ) 742 { 743 int l; 744 for( l = 0; l < n_states; l++ ) 745 { 746 mp[l] *= state[l].weight[0]; 747 } 748 } 749 750 /* 3b. add other mixtures */ 751 for( m = 1; m < max_mix; m++ ) 752 { 753 int ofs = -m*obs_x*n_states; 754 for( n = 0; n < obs_x; n++, mp += n_states ) 755 { 756 int l; 757 for( l = 0; l < n_states; l++ ) 758 { 759 if( m < state[l].num_mix ) 760 { 761 mp[l + ofs] += mp[l] * state[l].weight[m]; 762 } 763 } 764 } 765 } 766 767 /* 4. Put logarithms of summary probabilities to the destination matrix */ 768 res = icvbLog_64f32f( mix_prob, (float*)(hmm->obsProb),//[j], 769 obs_x * n_states ); 770 if( res < 0 ) goto processing_exit; 771 } 772 } 773 } 774 775processing_exit: 776 777 if( log_mix_prob != local_log_mix_prob ) icvFree( &log_mix_prob ); 778 return res; 779#undef MAX_BUF_SIZE 780 } 781#else 782/* for( i = 0; i < hmm->num_states; i++ ) 783 { 784 CvEHMM* ehmm = &(hmm->u.ehmm[i]); 785 CvEHMMState* state = ehmm->u.state; 786 787 for( j = 0; j < obs_info->obs_y; j++ ) 788 { 789 int k,m; 790 791 int obs_index = j * obs_info->obs_x; 792 793 float* B = ehmm->obsProb[j]; 794 795 // cycles through obs and states 796 for( k = 0; k < obs_info->obs_x; k++ ) 797 { 798 CvVect32f vect = (obs_info->obs) + (obs_index + k) * vect_size; 799 800 float* matr_line = B + k * ehmm->num_states; 801 802 for( m = 0; m < ehmm->num_states; m++ ) 803 { 804 matr_line[m] = icvComputeGaussMixture( vect, state[m].mu, state[m].inv_var, 805 state[m].log_var_val, vect_size, state[m].weight, 806 state[m].num_mix ); 807 } 808 } 809 } 810 } 811*/ 812#endif 813} 814 815 816/*F/////////////////////////////////////////////////////////////////////////////////////// 817// Name: EstimateTransProb 818// Purpose: The function calculates the state and super state transition probabilities 819// of the model given the images, 820// the state segmentation and the input parameters 821// Context: 822// Parameters: obs_info_array - array of pointers to image observations 823// num_img - length of above array 824// hmm - pointer to HMM structure 825// Returns: void 826// 827// Notes: 828//F*/ 829CvStatus icvEstimate1DTransProb( Cv1DObsInfo** obs_info_array, 830 int num_seq, 831 CvEHMM* hmm ) 832{ 833 int i, j, k; 834 835 /* as a counter we will use transP matrix */ 836 837 /* initialization */ 838 839 /* clear transP */ 840 icvSetZero_32f( hmm->transP, hmm->num_states, hmm->num_states ); 841 842 843 /* compute the counters */ 844 for (i = 0; i < num_seq; i++) 845 { 846 int counter = 0; 847 Cv1DObsInfo* info = obs_info_array[i]; 848 849 for (k = 0; k < info->obs_x; k++, counter++) 850 { 851 /* compute how many transitions from state to state 852 occured */ 853 int state; 854 int nextstate; 855 856 state = info->state[counter]; 857 858 if (k < info->obs_x - 1) 859 { 860 int transP_size = hmm->num_states; 861 862 nextstate = info->state[counter+1]; 863 hmm->transP[ state * transP_size + nextstate] += 1; 864 } 865 } 866 } 867 868 /* estimate superstate matrix */ 869 for( i = 0; i < hmm->num_states; i++) 870 { 871 float total = 0; 872 float inv_total; 873 for( j = 0; j < hmm->num_states; j++) 874 { 875 total += hmm->transP[i * hmm->num_states + j]; 876 } 877 //assert( total ); 878 879 inv_total = total ? 1.f/total : 0; 880 881 for( j = 0; j < hmm->num_states; j++) 882 { 883 hmm->transP[i * hmm->num_states + j] = 884 hmm->transP[i * hmm->num_states + j] ? 885 (float)log( hmm->transP[i * hmm->num_states + j] * inv_total ) : -BIG_FLT; 886 } 887 } 888 889 return CV_NO_ERR; 890} 891 892 893/*F/////////////////////////////////////////////////////////////////////////////////////// 894// Name: MixSegmL2 895// Purpose: The function implements the mixture segmentation of the states of the embedded HMM 896// Context: used with the Viterbi training of the embedded HMM 897// 898// Parameters: 899// obs_info_array 900// num_img 901// hmm 902// Returns: void 903// 904// Notes: 905//F*/ 906CvStatus icv1DMixSegmL2(CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm ) 907{ 908 int k, i, m; 909 910 CvEHMMState* state = hmm->u.state; 911 912 for (k = 0; k < num_img; k++) 913 { 914 //int counter = 0; 915 CvImgObsInfo* info = obs_info_array[k]; 916 917 for (i = 0; i < info->obs_x; i++) 918 { 919 int e_state = info->state[i]; 920 float min_dist; 921 922 min_dist = icvSquareDistance((info->obs) + (i * info->obs_size), 923 state[e_state].mu, info->obs_size); 924 info->mix[i] = 0; 925 926 for (m = 1; m < state[e_state].num_mix; m++) 927 { 928 float dist=icvSquareDistance( (info->obs) + (i * info->obs_size), 929 state[e_state].mu + m * info->obs_size, 930 info->obs_size); 931 if (dist < min_dist) 932 { 933 min_dist = dist; 934 /* assign mixture with smallest distance */ 935 info->mix[i] = m; 936 } 937 } 938 } 939 } 940 return CV_NO_ERR; 941} 942 943/*F/////////////////////////////////////////////////////////////////////////////////////// 944// Name: icvEViterbi 945// Purpose: The function calculates the embedded Viterbi algorithm 946// for 1 image 947// Context: 948// Parameters: 949// obs_info - observations 950// hmm - HMM 951// 952// Returns: the Embedded Viterbi probability (float) 953// and do state segmentation of observations 954// 955// Notes: 956//F*/ 957float icvViterbi(Cv1DObsInfo* obs_info, CvEHMM* hmm) 958{ 959 int i, counter; 960 float log_likelihood; 961 962 //CvEHMMState* first_state = hmm->u.state; 963 964 /* memory allocation for superB */ 965 /*CvMatr32f superB = picvCreateMatrix_32f(hmm->num_states, obs_info->obs_x );*/ 966 967 /* memory allocation for q */ 968 int* super_q = (int*)icvAlloc( obs_info->obs_x * sizeof(int) ); 969 970 /* perform Viterbi segmentation (process 1D HMM) */ 971 icvViterbiSegmentation( hmm->num_states, obs_info->obs_x, 972 hmm->transP, (float*)(hmm->obsProb), 0, 973 _CV_LAST_STATE, &super_q, obs_info->obs_x, 974 obs_info->obs_x, &log_likelihood ); 975 976 log_likelihood /= obs_info->obs_x ; 977 978 counter = 0; 979 /* assign new state to observation vectors */ 980 for (i = 0; i < obs_info->obs_x; i++) 981 { 982 int state = super_q[i]; 983 obs_info->state[i] = state; 984 } 985 986 /* memory deallocation for superB */ 987 /*picvDeleteMatrix( superB );*/ 988 icvFree( &super_q ); 989 990 return log_likelihood; 991} 992 993CvStatus icvEstimate1DHMMStateParams(CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm) 994 995{ 996 /* compute gamma, weights, means, vars */ 997 int k, i, j, m; 998 int counter = 0; 999 int total = 0; 1000 int vect_len = obs_info_array[0]->obs_size; 1001 1002 float start_log_var_val = LN2PI * vect_len; 1003 1004 CvVect32f tmp_vect = icvCreateVector_32f( vect_len ); 1005 1006 CvEHMMState* first_state = hmm->u.state; 1007 1008 assert( sizeof(float) == sizeof(int) ); 1009 1010 total+= hmm->num_states; 1011 1012 /***************Gamma***********************/ 1013 /* initialize gamma */ 1014 for( i = 0; i < total; i++ ) 1015 { 1016 for (m = 0; m < first_state[i].num_mix; m++) 1017 { 1018 ((int*)(first_state[i].weight))[m] = 0; 1019 } 1020 } 1021 1022 /* maybe gamma must be computed in mixsegm process ?? */ 1023 1024 /* compute gamma */ 1025 counter = 0; 1026 for (k = 0; k < num_img; k++) 1027 { 1028 CvImgObsInfo* info = obs_info_array[k]; 1029 int num_obs = info->obs_y * info->obs_x; 1030 1031 for (i = 0; i < num_obs; i++) 1032 { 1033 int state, mixture; 1034 state = info->state[i]; 1035 mixture = info->mix[i]; 1036 /* computes gamma - number of observations corresponding 1037 to every mixture of every state */ 1038 ((int*)(first_state[state].weight))[mixture] += 1; 1039 } 1040 } 1041 /***************Mean and Var***********************/ 1042 /* compute means and variances of every item */ 1043 /* initially variance placed to inv_var */ 1044 /* zero mean and variance */ 1045 for (i = 0; i < total; i++) 1046 { 1047 memset( (void*)first_state[i].mu, 0, first_state[i].num_mix * vect_len * 1048 sizeof(float) ); 1049 memset( (void*)first_state[i].inv_var, 0, first_state[i].num_mix * vect_len * 1050 sizeof(float) ); 1051 } 1052 1053 /* compute sums */ 1054 for (i = 0; i < num_img; i++) 1055 { 1056 CvImgObsInfo* info = obs_info_array[i]; 1057 int total_obs = info->obs_x;// * info->obs_y; 1058 1059 float* vector = info->obs; 1060 1061 for (j = 0; j < total_obs; j++, vector+=vect_len ) 1062 { 1063 int state = info->state[j]; 1064 int mixture = info->mix[j]; 1065 1066 CvVect32f mean = first_state[state].mu + mixture * vect_len; 1067 CvVect32f mean2 = first_state[state].inv_var + mixture * vect_len; 1068 1069 icvAddVector_32f( mean, vector, mean, vect_len ); 1070 icvAddSquare_32f_C1IR( vector, vect_len * sizeof(float), 1071 mean2, vect_len * sizeof(float), cvSize(vect_len, 1) ); 1072 } 1073 } 1074 1075 /*compute the means and variances */ 1076 /* assume gamma already computed */ 1077 counter = 0; 1078 for (i = 0; i < total; i++) 1079 { 1080 CvEHMMState* state = &(first_state[i]); 1081 1082 for (m = 0; m < state->num_mix; m++) 1083 { 1084 int k; 1085 CvVect32f mu = state->mu + m * vect_len; 1086 CvVect32f invar = state->inv_var + m * vect_len; 1087 1088 if ( ((int*)state->weight)[m] > 1) 1089 { 1090 float inv_gamma = 1.f/((int*)(state->weight))[m]; 1091 1092 icvScaleVector_32f( mu, mu, vect_len, inv_gamma); 1093 icvScaleVector_32f( invar, invar, vect_len, inv_gamma); 1094 } 1095 1096 icvMulVectors_32f(mu, mu, tmp_vect, vect_len); 1097 icvSubVector_32f( invar, tmp_vect, invar, vect_len); 1098 1099 /* low bound of variance - 0.01 (Ara's experimental result) */ 1100 for( k = 0; k < vect_len; k++ ) 1101 { 1102 invar[k] = (invar[k] > 0.01f) ? invar[k] : 0.01f; 1103 } 1104 1105 /* compute log_var */ 1106 state->log_var_val[m] = start_log_var_val; 1107 for( k = 0; k < vect_len; k++ ) 1108 { 1109 state->log_var_val[m] += (float)log( invar[k] ); 1110 } 1111 1112 state->log_var_val[m] *= 0.5; 1113 1114 /* compute inv_var = 1/sqrt(2*variance) */ 1115 icvScaleVector_32f(invar, invar, vect_len, 2.f ); 1116 icvbInvSqrt_32f(invar, invar, vect_len ); 1117 } 1118 } 1119 1120 /***************Weights***********************/ 1121 /* normilize gammas - i.e. compute mixture weights */ 1122 1123 //compute weights 1124 for (i = 0; i < total; i++) 1125 { 1126 int gamma_total = 0; 1127 float norm; 1128 1129 for (m = 0; m < first_state[i].num_mix; m++) 1130 { 1131 gamma_total += ((int*)(first_state[i].weight))[m]; 1132 } 1133 1134 norm = gamma_total ? (1.f/(float)gamma_total) : 0.f; 1135 1136 for (m = 0; m < first_state[i].num_mix; m++) 1137 { 1138 first_state[i].weight[m] = ((int*)(first_state[i].weight))[m] * norm; 1139 } 1140 } 1141 1142 icvDeleteVector( tmp_vect); 1143 return CV_NO_ERR; 1144} 1145 1146 1147 1148 1149 1150#endif 1151 1152