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