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*/ 69static 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 91static 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*/ 126static 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 200static 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 */ 228static 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 */ 257static CvStatus CV_STDCALL 258icvUniformImgSegm( 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*/ 375static CvStatus CV_STDCALL 376icvInitMixSegm( 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 557icvComputeGaussMixture( 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*/ 600static 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*/ 886static CvStatus CV_STDCALL 887icvEstimateTransProb( 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*/ 1005static CvStatus CV_STDCALL 1006icvMixSegmL2( 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/* 1048CvStatus 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*/ 1093static CvStatus CV_STDCALL 1094icvViterbiSegmentation( 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*/ 1277static 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 1365static CvStatus CV_STDCALL 1366icvEstimateHMMStateParams( 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/* 1521CvStatus 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 1606CvStatus 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 1621CV_IMPL CvEHMM* 1622cvCreate2DHMM( 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 1637CV_IMPL void 1638cvRelease2DHMM( CvEHMM ** hmm ) 1639{ 1640 CV_FUNCNAME( "cvRelease2DHMM" ); 1641 1642 __BEGIN__; 1643 1644 IPPI_CALL( icvRelease2DHMM( hmm )); 1645 __END__; 1646} 1647 1648CV_IMPL CvImgObsInfo* 1649cvCreateObsInfo( 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 1664CV_IMPL void 1665cvReleaseObsInfo( CvImgObsInfo ** obs_info ) 1666{ 1667 CV_FUNCNAME( "cvReleaseObsInfo" ); 1668 1669 __BEGIN__; 1670 1671 IPPI_CALL( icvReleaseObsInfo( obs_info )); 1672 1673 __END__; 1674} 1675 1676 1677CV_IMPL void 1678cvUniformImgSegm( 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 1689CV_IMPL void 1690cvInitMixSegm( 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 1701CV_IMPL void 1702cvEstimateHMMStateParams( 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 1713CV_IMPL void 1714cvEstimateTransProb( 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 1726CV_IMPL void 1727cvEstimateObsProb( 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 1738CV_IMPL float 1739cvEViterbi( 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 1757CV_IMPL void 1758cvMixSegmL2( 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