/*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 "_cvaux.h" #if 0 #define LN2PI 1.837877f #define BIG_FLT 1.e+10f #define _CV_ERGODIC 1 #define _CV_CAUSAL 2 #define _CV_LAST_STATE 1 #define _CV_BEST_STATE 2 //*F/////////////////////////////////////////////////////////////////////////////////////// // Name: icvForward1DHMM // Purpose: The function performs baum-welsh algorithm // 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 // // Notes: //F*/ #if 0 CvStatus icvForward1DHMM( int num_states, int num_obs, CvMatr64d A, CvMatr64d B, double* scales) { // assume that observation and transition // probabilities already computed int m_HMMType = _CV_CAUSAL; double* m_pi = icvAlloc( num_states* sizeof( double) ); /* alpha is matrix rows throuhg states columns through time */ double* alpha = icvAlloc( num_states*num_obs * sizeof( double ) ); /* All calculations will be in non-logarithmic domain */ /* Initialization */ /* set initial state probabilities */ m_pi[0] = 1; for (i = 1; i < num_states; i++) { m_pi[i] = 0.0; } for (i = 0; i < num_states; i++) { alpha[i] = m_pi[i] * m_b[ i]; } /******************************************************************/ /* Induction */ if ( m_HMMType == _CV_ERGODIC ) { int t; for (t = 1 ; t < num_obs; t++) { for (j = 0; j < num_states; j++) { double sum = 0.0; int i; for (i = 0; i < num_states; i++) { sum += alpha[(t - 1) * num_states + i] * A[i * num_states + j]; } alpha[(t - 1) * num_states + j] = sum * B[t * num_states + j]; /* add computed alpha to scale factor */ sum_alpha += alpha[(t - 1) * num_states + j]; } double scale = 1/sum_alpha; /* scale alpha */ for (j = 0; j < num_states; j++) { alpha[(t - 1) * num_states + j] *= scale; } scales[t] = scale; } } #endif //*F/////////////////////////////////////////////////////////////////////////////////////// // Name: icvCreateObsInfo // Purpose: The function allocates memory for CvImgObsInfo structure // 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 // // Notes: //F*/ /*CvStatus icvCreateObsInfo( CvImgObsInfo** obs_info, CvSize num_obs, int obs_size ) { int total = num_obs.height * num_obs.width; CvImgObsInfo* obs = (CvImgObsInfo*)icvAlloc( sizeof( CvImgObsInfo) ); obs->obs_x = num_obs.width; obs->obs_y = num_obs.height; obs->obs = (float*)icvAlloc( total * obs_size * sizeof(float) ); obs->state = (int*)icvAlloc( 2 * total * sizeof(int) ); obs->mix = (int*)icvAlloc( total * sizeof(int) ); obs->obs_size = obs_size; obs_info[0] = obs; return CV_NO_ERR; }*/ /*CvStatus icvReleaseObsInfo( CvImgObsInfo** p_obs_info ) { CvImgObsInfo* obs_info = p_obs_info[0]; icvFree( &(obs_info->obs) ); icvFree( &(obs_info->mix) ); icvFree( &(obs_info->state) ); icvFree( &(obs_info) ); p_obs_info[0] = NULL; return CV_NO_ERR; } */ //*F/////////////////////////////////////////////////////////////////////////////////////// // Name: icvCreate1DHMM // Purpose: The function allocates memory for 1-dimensional HMM // and its inner stuff // Context: // Parameters: hmm - addres of pointer to CvEHMM structure // state_number - number of states in HMM // num_mix - number of gaussian mixtures in HMM states // size of array is defined by previous parameter // obs_size - length of observation vectors // // Returns: error status // Notes: //F*/ CvStatus icvCreate1DHMM( CvEHMM** this_hmm, int state_number, int* num_mix, int obs_size ) { int i; int real_states = state_number; CvEHMMState* all_states; CvEHMM* hmm; int total_mix = 0; float* pointers; /* allocate memory for hmm */ hmm = (CvEHMM*)icvAlloc( sizeof(CvEHMM) ); /* set number of superstates */ hmm->num_states = state_number; hmm->level = 0; /* allocate memory for all states */ all_states = (CvEHMMState *)icvAlloc( 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]; } /* allocate memory for states stuff */ pointers = (float*)icvAlloc( total_mix * (2/*for mu invvar */ * obs_size + 2/*for weight and log_var_val*/ ) * sizeof( float) ); /* organize memory */ for( i = 0; i < real_states; i++ ) { all_states[i].mu = pointers; pointers += num_mix[i] * obs_size; 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]; } hmm->u.state = all_states; hmm->transP = icvCreateMatrix_32f( hmm->num_states, hmm->num_states ); hmm->obsProb = NULL; /* if all ok - return pointer */ *this_hmm = hmm; return CV_NO_ERR; } CvStatus icvRelease1DHMM( CvEHMM** phmm ) { CvEHMM* hmm = phmm[0]; icvDeleteMatrix( hmm->transP ); if (hmm->obsProb != NULL) { int* tmp = ((int*)(hmm->obsProb)) - 3; icvFree( &(tmp) ); } icvFree( &(hmm->u.state->mu) ); icvFree( &(hmm->u.state) ); phmm[0] = NULL; return CV_NO_ERR; } /*can be used in CHMM & DHMM */ CvStatus icvUniform1DSegm( Cv1DObsInfo* obs_info, CvEHMM* hmm ) { /* implementation is very bad */ int i; CvEHMMState* first_state; /* check arguments */ if ( !obs_info || !hmm ) return CV_NULLPTR_ERR; first_state = hmm->u.state; for (i = 0; i < obs_info->obs_x; i++) { //bad line (division ) int state = (i * hmm->num_states)/obs_info->obs_x; obs_info->state[i] = state; } return CV_NO_ERR; } /*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 // // Parameters: obs_info_array - array of pointers to image observations // num_img - length of above array // hmm - pointer to HMM structure // // Returns: error status // // Notes: //F*/ CvStatus icvInit1DMixSegm(Cv1DObsInfo** obs_info_array, int num_img, CvEHMM* hmm) { int k, i, j; int* num_samples; /* number of observations in every state */ int* counter; /* array of counters for every state */ int** a_class; /* for every state - characteristic array */ CvVect32f** samples; /* for every state - pointer to observation vectors */ int*** samples_mix; /* for every state - array of pointers to vectors mixtures */ CvTermCriteria criteria = cvTermCriteria( CV_TERMCRIT_EPS|CV_TERMCRIT_ITER, 1000, /* iter */ 0.01f ); /* eps */ int total = hmm->num_states; CvEHMMState* first_state = hmm->u.state; /* for every state integer is allocated - number of vectors in state */ num_samples = (int*)icvAlloc( total * sizeof(int) ); /* integer counter is allocated for every state */ counter = (int*)icvAlloc( total * sizeof(int) ); samples = (CvVect32f**)icvAlloc( total * sizeof(CvVect32f*) ); samples_mix = (int***)icvAlloc( total * sizeof(int**) ); /* clear */ memset( num_samples, 0 , total*sizeof(int) ); memset( counter, 0 , total*sizeof(int) ); /* for every state the number of vectors which belong to it is computed (smth. like histogram) */ for (k = 0; k < num_img; k++) { CvImgObsInfo* obs = obs_info_array[k]; for (i = 0; i < obs->obs_x; i++) { int state = obs->state[ i ]; num_samples[state] += 1; } } /* for every state int* is allocated */ a_class = (int**)icvAlloc( total*sizeof(int*) ); for (i = 0; i < total; i++) { a_class[i] = (int*)icvAlloc( num_samples[i] * sizeof(int) ); samples[i] = (CvVect32f*)icvAlloc( num_samples[i] * sizeof(CvVect32f) ); samples_mix[i] = (int**)icvAlloc( num_samples[i] * sizeof(int*) ); } /* for every state vectors which belong to state are gathered */ for (k = 0; k < num_img; k++) { CvImgObsInfo* obs = obs_info_array[k]; int num_obs = obs->obs_x; float* vector = obs->obs; for (i = 0; i < num_obs; i++, vector+=obs->obs_size ) { int state = obs->state[i]; samples[state][counter[state]] = vector; samples_mix[state][counter[state]] = &(obs->mix[i]); counter[state]++; } } /* clear counters */ memset( counter, 0, total*sizeof(int) ); /* do the actual clustering using the K Means algorithm */ for (i = 0; i < total; i++) { if ( first_state[i].num_mix == 1) { for (k = 0; k < num_samples[i]; k++) { /* all vectors belong to one mixture */ a_class[i][k] = 0; } } else if( num_samples[i] ) { /* clusterize vectors */ icvKMeans( first_state[i].num_mix, samples[i], num_samples[i], obs_info_array[0]->obs_size, criteria, a_class[i] ); } } /* 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]; } } for (i = 0; i < total; i++) { icvFree( &(a_class[i]) ); icvFree( &(samples[i]) ); icvFree( &(samples_mix[i]) ); } icvFree( &a_class ); icvFree( &samples ); icvFree( &samples_mix ); icvFree( &counter ); icvFree( &num_samples ); return CV_NO_ERR; } /*F/////////////////////////////////////////////////////////////////////////////////////// // Name: ComputeUniModeGauss // Purpose: The function computes the Gaussian pdf for a sample vector // 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 // // Returns: the pdf of the sample vector given the specified Gaussian // // Notes: //F*/ /*float icvComputeUniModeGauss(CvVect32f vect, CvVect32f mu, CvVect32f inv_var, float log_var_val, int vect_size) { int n; 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; return (float)prob; }*/ /*F/////////////////////////////////////////////////////////////////////////////////////// // Name: ComputeGaussMixture // Purpose: The function computes the mixture Gaussian pdf of a sample vector. // Context: // Parameters: obsVeq - pointer to the sample vector // mu - two-dimensional pointer to the mean vector of the Gaussian pdf; // the first dimension is indexed over the number of mixtures and // the second dimension is indexed along the size of the mean vector // var - two-dimensional pointer to the variance vector of the Gaussian pdf; // the first dimension is indexed over the number of mixtures and // 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 // // Returns: the pdf of the sample vector given the specified Gaussian mixture. // // Notes: //F*/ /* Calculate probability of observation at state in logarithmic scale*/ /*float icvComputeGaussMixture( CvVect32f vect, float* mu, float* inv_var, float* log_var_val, int vect_size, float* weight, int num_mix ) { double prob, l_prob; prob = 0.0f; if (num_mix == 1) { return icvComputeUniModeGauss( vect, mu, inv_var, log_var_val[0], vect_size); } else { int m; for (m = 0; m < num_mix; m++) { if ( weight[m] > 0.0) { l_prob = icvComputeUniModeGauss(vect, mu + m*vect_size, inv_var + m * vect_size, log_var_val[m], vect_size); prob = prob + weight[m]*exp((double)l_prob); } } prob = log(prob); } return (float)prob; } */ /*F/////////////////////////////////////////////////////////////////////////////////////// // Name: EstimateObsProb // Purpose: The function computes the probability of every observation in every state // Context: // Parameters: obs_info - observations // hmm - hmm // Returns: error status // // Notes: //F*/ CvStatus icvEstimate1DObsProb(CvImgObsInfo* obs_info, CvEHMM* hmm ) { int j; int total_states = 0; /* check if matrix exist and check current size if not sufficient - realloc */ int status = 0; /* 1 - not allocated, 2 - allocated but small size, 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; }*/ total_states = hmm->num_states; if ( hmm->obsProb == NULL ) { /* 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*)icvAlloc( 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; } else { /* 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) ); if ( need_size > (*total) ) { int* buffer = ((int*)(hmm->obsProb)) - 3; icvFree( &buffer); buffer = (int*)icvAlloc( need_size + 3); buffer[0] = need_size; buffer[1] = obs_info->obs_y; buffer[2] = obs_info->obs_x; hmm->obsProb = (float**)(buffer + 3); status = 3; } } if (!status) { int* obsx = ((int*)(hmm->obsProb)) - 1; //int* obsy = ((int*)(hmm->obsProb)) - 2; assert( /*(*obsy > 0) &&*/ (*obsx > 0) ); /* is good distribution? */ if ( (obs_info->obs_x > (*obsx) ) /* || (obs_info->obs_y > (*obsy) ) */ ) status = 3; } assert( (status == 0) || (status == 3) ); /* if bad status - do reallocation actions */ if ( status ) { float** tmp = hmm->obsProb; //float* tmpf; /* distribute pointers of ehmm->obsProb */ /* for( i = 0; i < hmm->num_states; i++ ) { hmm->u.ehmm[i].obsProb = tmp; 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] ); for( j = 0; j < obs_info->obs_y; j++ ) { ehmm->obsProb[j] = tmpf; tmpf += ehmm->num_states * obs_info->obs_x; } } */ hmm->obsProb = tmp; }/* end of pointer distribution */ #if 1 { #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; 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 = hmm->u.state; int max_mix = 0; for( j = 0; j < hmm->num_states; j++ ) { int t = state[j].num_mix; if( max_mix < t ) max_mix = t; } max_mix *= hmm->num_states; /*if( max_size < max_mix )*/ max_size = max_mix; //} max_size *= obs_x * vect_size; /* allocate buffer */ if( max_size > MAX_BUF_SIZE ) { log_mix_prob = (float*)icvAlloc( 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***********************/ /* loop through external states */ //for( i = 0; i < hmm->num_states; i++ ) { // CvEHMM* ehmm = &(hmm->u.ehmm[i]); CvEHMMState* state = hmm->u.state; int max_mix = 0; int n_states = hmm->num_states; /* determine maximal number of mixtures (again) */ for( j = 0; j < hmm->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; float* obs = obs_info->obs;/* + j * obs_x * vect_size; */ float* log_mp = max_mix > 1 ? log_mix_prob : (float*)(hmm->obsProb); double* mp = mix_prob; /* several passes are done below */ /* 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 ) { /* 2. calculate exponent of log_mix_prob (i.e. probability for each mixture) */ res = icvbExp_32f64f( log_mix_prob, mix_prob, max_mix * obs_x * n_states ); if( res < 0 ) goto processing_exit; /* 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 */ res = icvbLog_64f32f( mix_prob, (float*)(hmm->obsProb),//[j], obs_x * n_states ); if( res < 0 ) goto processing_exit; } } } processing_exit: if( log_mix_prob != local_log_mix_prob ) icvFree( &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; int obs_index = j * obs_info->obs_x; float* B = ehmm->obsProb[j]; // cycles through obs and states for( k = 0; k < obs_info->obs_x; k++ ) { CvVect32f vect = (obs_info->obs) + (obs_index + k) * vect_size; float* matr_line = B + k * ehmm->num_states; for( m = 0; m < ehmm->num_states; m++ ) { matr_line[m] = icvComputeGaussMixture( vect, state[m].mu, state[m].inv_var, state[m].log_var_val, vect_size, state[m].weight, state[m].num_mix ); } } } } */ #endif } /*F/////////////////////////////////////////////////////////////////////////////////////// // Name: EstimateTransProb // Purpose: The function calculates the state and super state transition probabilities // of the model given the images, // the state segmentation and the input parameters // Context: // Parameters: obs_info_array - array of pointers to image observations // num_img - length of above array // hmm - pointer to HMM structure // Returns: void // // Notes: //F*/ CvStatus icvEstimate1DTransProb( Cv1DObsInfo** obs_info_array, int num_seq, CvEHMM* hmm ) { int i, j, k; /* as a counter we will use transP matrix */ /* initialization */ /* clear transP */ icvSetZero_32f( hmm->transP, hmm->num_states, hmm->num_states ); /* compute the counters */ for (i = 0; i < num_seq; i++) { int counter = 0; Cv1DObsInfo* info = obs_info_array[i]; for (k = 0; k < info->obs_x; k++, counter++) { /* compute how many transitions from state to state occured */ int state; int nextstate; state = info->state[counter]; if (k < info->obs_x - 1) { int transP_size = hmm->num_states; nextstate = info->state[counter+1]; hmm->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; for( j = 0; j < hmm->num_states; j++) { hmm->transP[i * hmm->num_states + j] = hmm->transP[i * hmm->num_states + j] ? (float)log( hmm->transP[i * hmm->num_states + j] * inv_total ) : -BIG_FLT; } } return CV_NO_ERR; } /*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 // // Parameters: // obs_info_array // num_img // hmm // Returns: void // // Notes: //F*/ CvStatus icv1DMixSegmL2(CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm ) { int k, i, m; CvEHMMState* state = hmm->u.state; for (k = 0; k < num_img; k++) { //int counter = 0; CvImgObsInfo* info = obs_info_array[k]; for (i = 0; i < info->obs_x; i++) { int e_state = info->state[i]; float min_dist; min_dist = icvSquareDistance((info->obs) + (i * info->obs_size), state[e_state].mu, info->obs_size); info->mix[i] = 0; for (m = 1; m < state[e_state].num_mix; m++) { float dist=icvSquareDistance( (info->obs) + (i * info->obs_size), state[e_state].mu + m * info->obs_size, info->obs_size); if (dist < min_dist) { min_dist = dist; /* assign mixture with smallest distance */ info->mix[i] = m; } } } } return CV_NO_ERR; } /*F/////////////////////////////////////////////////////////////////////////////////////// // Name: icvEViterbi // Purpose: The function calculates the embedded Viterbi algorithm // for 1 image // Context: // Parameters: // obs_info - observations // hmm - HMM // // Returns: the Embedded Viterbi probability (float) // and do state segmentation of observations // // Notes: //F*/ float icvViterbi(Cv1DObsInfo* obs_info, CvEHMM* hmm) { int i, counter; float log_likelihood; //CvEHMMState* first_state = hmm->u.state; /* memory allocation for superB */ /*CvMatr32f superB = picvCreateMatrix_32f(hmm->num_states, obs_info->obs_x );*/ /* memory allocation for q */ int* super_q = (int*)icvAlloc( obs_info->obs_x * sizeof(int) ); /* perform Viterbi segmentation (process 1D HMM) */ icvViterbiSegmentation( hmm->num_states, obs_info->obs_x, hmm->transP, (float*)(hmm->obsProb), 0, _CV_LAST_STATE, &super_q, obs_info->obs_x, obs_info->obs_x, &log_likelihood ); log_likelihood /= obs_info->obs_x ; counter = 0; /* assign new state to observation vectors */ for (i = 0; i < obs_info->obs_x; i++) { int state = super_q[i]; obs_info->state[i] = state; } /* memory deallocation for superB */ /*picvDeleteMatrix( superB );*/ icvFree( &super_q ); return log_likelihood; } CvStatus icvEstimate1DHMMStateParams(CvImgObsInfo** obs_info_array, int num_img, CvEHMM* hmm) { /* compute gamma, weights, means, vars */ int k, i, j, m; int counter = 0; 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 ); CvEHMMState* first_state = hmm->u.state; assert( sizeof(float) == sizeof(int) ); total+= hmm->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; } } /* maybe gamma must be computed in mixsegm process ?? */ /* compute gamma */ counter = 0; 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[i]; mixture = info->mix[i]; /* computes gamma - number of observations corresponding to every mixture of every state */ ((int*)(first_state[state].weight))[mixture] += 1; } } /***************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++) { memset( (void*)first_state[i].mu, 0, first_state[i].num_mix * vect_len * sizeof(float) ); memset( (void*)first_state[i].inv_var, 0, first_state[i].num_mix * vect_len * sizeof(float) ); } /* 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 ) { int state = info->state[j]; int mixture = info->mix[j]; CvVect32f mean = first_state[state].mu + mixture * vect_len; CvVect32f mean2 = first_state[state].inv_var + mixture * vect_len; icvAddVector_32f( mean, vector, mean, vect_len ); icvAddSquare_32f_C1IR( vector, vect_len * sizeof(float), mean2, vect_len * sizeof(float), cvSize(vect_len, 1) ); } } /*compute the means and variances */ /* assume gamma already computed */ counter = 0; for (i = 0; i < total; i++) { CvEHMMState* state = &(first_state[i]); for (m = 0; m < state->num_mix; m++) { int k; CvVect32f mu = state->mu + m * vect_len; CvVect32f invar = state->inv_var + m * vect_len; if ( ((int*)state->weight)[m] > 1) { float inv_gamma = 1.f/((int*)(state->weight))[m]; icvScaleVector_32f( mu, mu, vect_len, inv_gamma); icvScaleVector_32f( invar, invar, vect_len, inv_gamma); } icvMulVectors_32f(mu, mu, tmp_vect, vect_len); icvSubVector_32f( invar, tmp_vect, invar, vect_len); /* low bound of variance - 0.01 (Ara's experimental result) */ for( k = 0; k < vect_len; k++ ) { invar[k] = (invar[k] > 0.01f) ? invar[k] : 0.01f; } /* 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] ); } state->log_var_val[m] *= 0.5; /* compute inv_var = 1/sqrt(2*variance) */ icvScaleVector_32f(invar, invar, vect_len, 2.f ); icvbInvSqrt_32f(invar, invar, vect_len ); } } /***************Weights***********************/ /* normilize gammas - i.e. compute mixture weights */ //compute weights for (i = 0; i < total; i++) { int gamma_total = 0; float norm; for (m = 0; m < first_state[i].num_mix; m++) { gamma_total += ((int*)(first_state[i].weight))[m]; } norm = gamma_total ? (1.f/(float)gamma_total) : 0.f; for (m = 0; m < first_state[i].num_mix; m++) { first_state[i].weight[m] = ((int*)(first_state[i].weight))[m] * norm; } } icvDeleteVector( tmp_vect); return CV_NO_ERR; } #endif