HMM人脸识别用OpenCV2.2

在OpenCV的早期版本中有HMM人脸识别的demo,新版本已经没有了,参照早期版本,我跟踪了代码,写了些注释,与大家分享,希望对大家有用。

 

HMM人脸识别训练算法主要分4部分:

1,准备工作

//用于尺度归一化

int m_useWidth = 1;

int m_useHeight = 0;

bool doRescale = 0;

int m_scaleWidth = 90;

int m_scaleHeight = 0;

 

//是否抑制直流分量

int m_suppress_intensity = 1;

 

//超态及其每个状态的混高斯

int m_stnum[32];

int m_mixnum[128];

 

//DCT(离散余弦变换)系数计算的图像块的大小

CvSize m_dctSize=cvSize(12,12);

 

//dct窗口递进的步长

CvSize m_delta=cvSize(4,4);

 

//存放已经训练完毕又加载的ehmm模型

vector<CvEHMM *> vec_ehmm;

vector<string> vec_pattern_index;

 

//观察值的长度vect_len = 3*3-1

CvSize m_obsSize = cvSize(3,3);

int vect_len = m_obsSize.width*m_obsSize.height-1;

 

int InitStateAndMix()

{

    m_stnum[0] = 5;

    m_stnum[1] = 3;

    m_stnum[2] = 6;

    m_stnum[3] = 6;

    m_stnum[4] = 6;

    m_stnum[5] = 3;

    for( int i = 0; i < 128; i++ )

    {

        m_mixnum[i] = 3;

    }

    return 1;

}

 

构造隐马尔科夫结构体

CvEHMM *hmm = cvCreate2DHMM( m_stnum, m_mixnum, vect_size );

vect_size是每个观察向量的维数,即m_obsSize.width*m_obsSize.height-1

 

2,  循环每张图像,得到每张图像的观察向量,

1CV_COUNT_OBS( &roi, &(m_dctSize), &(m_delta), &num_obs );得到DCT观察值的块信息。

Roi:图像中感兴趣的区域,如果图像已经剪切好,则次之可以设置为图像的宽度与高度。

m_dctSizeDCT采样块的大小。如:12*12

m_deltaDCT采样的步长,如4*4

num_obs:输出参数,结果为DCT在该图像上横向,竖向的采样个数,如20*26,即为在横向上有20DCT的观测向量,竖向有26DCT的观测向量。

 

2)创建结构用于储存图像观察向量的数组。

obsInfoVec[img_index] = cvCreateObsInfo( num_obs, vect_len );

跟踪源码,可知:

static CvStatus CV_STDCALL icvCreateObsInfo(  CvImgObsInfo** obs_info,

                                           CvSize num_obs, int obs_size )

{

    int total = num_obs.height * num_obs.width;

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

    obs->obs_x = num_obs.width;

    obs->obs_y = num_obs.height;

// total为总的DCT采样块的大小如20*26obs_size为每个DCT块获取的向量的长度,如3*3-1

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

 

//对于每个DCT的采样块,分配两个int空间,分别存储各个块对应的超态及其子态索引。

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

 

//对于每个DCT的采样块(观察值),分配int空间,用于存储该观察值对应于那个混高斯(高//斯索引)

    obs->mix = (int*)cvAlloc( total * sizeof(int) );     

    obs->obs_size = obs_size;

    obs_info[0] = obs;

    return CV_NO_ERR;

}

 

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

if( m_suppress_intensity )

{

    float* observations = (float*)malloc( num_obs.height * num_obs.width * (vect_len+1) * sizeof(float) );

 

//从图像中提取的观察向量即DCT系数

cvImgToObs_DCT( ipl_scaled, observations, m_dctSize, m_obsSize, m_delta );      ExtractDCT( observations, info->obs, num_obs.height * num_obs.width, vect_len );

//将观察向量从observations转到info->obs

free( observations);

}

else

{

    cvImgToObs_DCT( ipl_scaled, info->obs, m_dctSize, m_obsSize, m_delta );

}

4)以HMM状态统一分割图像观测值, 填充obs->state = (int*)cvAlloc( 2 * total * sizeof(int) );k+0代表超态索引,k+1代表子态索引。

cvUniformImgSegm( info, hmm );

按照5个超态,每个超态分别为3,6,6,6,3的嵌入子态分割图像,即把每个DCT观察值块标号(包括它本身属于那个超态,属于那个子态),每个嵌入子状态的索引,,1,2,3......23,与它对应的超态无关。

3,  k均值填充obs->mix = (int*)cvAlloc( total * sizeof(int) );

首先计算在每个子状态下,观察值的个数,之后对于每个状态下的所有观察值,

Kmeans算法,k=3聚簇分类,把聚簇后每个向量对应的聚簇的索引所为混高斯的索引。

obs->mix[i]=k,k=1,2,3.

 

 

4,  训练

1

计算各个状态下混高斯的均值、方差和混高斯的权重。

cvEstimateHMMStateParams( obsInfoVec, num_img, hmm);

2

计算超态与超态之间,相邻子态之间的转移矩阵

cvEstimateTransProb( obsInfoVec, num_img, hmm);

3

计算在每个内嵌HMM状态下的每个观测值的高斯概率。得到ehmm->obsProb

对应于每一行(obs_x)所有观测向量,在所有超态下的所有子态发生的概率

(这个概率是每个子态下混高斯的加权),

cvEstimateObsProb( obsInfoVec[j], hmm );

4

1,先对每一行的各个观测向量在所有超态的子态下进行viterbi算法,计算

最能解释当前行观测向量的子态序列,及其最大概率。

2, 把得到的概率最为当前行发生在各个超态下的概率,再在超态下计算viterbi算法,

计算最能解释当前行观测向量的超态序列,并给出最大概率likelihood

3, 最能解释各个超态的子态序列和各个超态序列被放回到obsInfoVec[j]->obs_info->state

4,结果,影响的是obsInfoVec[j]中超态在行上的分布,每个超态在每一行中超态的子态中的分布。

likelihood += cvEViterbi( obsInfoVec[j], hmm );

5各个状态(超态,内嵌子态)发生变化,重新计算各个观察值在其所在的状态中混高斯索引。

cvMixSegmL2( obsInfoVec, num_img, hmm);

 

 

 

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值