图像处理-PCA人脸识别

在OpenCV2.4.2中有一个FaceRecognizer类,该类用于完成人脸识别,目前其实现的方法有PCA,LDA,LBP三种方法。这里仅对学习其PCA方法进行一下总结。

简单来说,PCA方法就是将图像投影到训练集经过K-L变换所得到的特征空间,然后在投影空间中计算距离,最近的也就是预测到的class了。PCA可以将高维数据降到低维而保证丢失的信息量最少。低维数据也就方便的计算,加快了计算速度。

1. 数学上的事

所有事情只要一牵扯到数学就变成公式一片片的了,但是不看公式又是心里没底,没有办法。数学就是很重要!这里假设有n个向量clip_image002,每个向量有m维,现在这么多向量我想用另一个向量t来表示,那么clip_image002[7]就可以用一个较低维的变换矩阵乘以t来标识,也就是压缩成功了!来上证明!假设误差函数为J(t),那么

clip_image002[12]

最后的结果是通过多步推倒而来。可以看到后项与t没有关系,要想让误差函数最小,t就应该取clip_image002[14](平均值)。
现在不用简单的一个向量t来表示原来的那n个向量,令每一个向量都对应一个值,如下:
clip_image002[19]

其中clip_image002[21]是单位向量,几何意义就是每一个向量都对应直线上的一个点(我感觉就是原来t的元素,其实还是向量t),将image作为新的坐标。代到J里得:
clip_image002[23]

image求微分就可以得到clip_image002[27]clip_image002[21]其实就是方向向量,那么新的坐标就是原始向量平移image后,然后投影到clip_image002[21]方向上就得到了新的坐标。那么什么方向是最合适的呢?
再将clip_image002[27]放到J中,得到
clip_image002[32]
其中image就是n个原始向量(clip_image002)的协方差矩阵。让J最小,就是让image最大。用拉格朗日乘数法:

image

得到:clip_image002[4]。可以看到这个就是求S的特征值与特征向量。
        到此为止,n个原始向量可以用S的特征向量来表示,当然为了压缩空间,就不用全部的特征向量,用特征值最大(方差最大的)的几个就行了。现在从这么一大堆推倒的最后来看,计算的时候给定原始的n个向量clip_image002
1、求出协方差矩阵S
2、对协方差矩阵S求特征向量与特征值。
3、取前q个特征值对应的特征向量clip_image002[40]
4、求新的向量image

然后求距离就可以了。

2.OpenCV中在人脸识别中的实现分析

FaceRecognizer在OpenCV2.4.2是人脸识别的基类,PCA,LDA,LBP三种不同的方法继承于它。PCA相对应的类是Eigenfaces,在文件modules/contrib/src/facerec.cpp中可以找到他的实现。
一组成员变量:

int _num_components;//对应“数学上的事”中所提到的q个主成分。
    double _threshold;
    vector<Mat> _projections;//原始向量投影后的坐标
    Mat _labels;//每幅图像的标签,用于分类
    Mat _eigenvectors;//特征向量
    Mat _eigenvalues;//特征值
    Mat _mean;//均值

三个重要的方法:

image

train 用来对样本进行训练,predict的第一个函数重载是预测给定图像的class,第二个重载会返回相似程度(也就是距离)到dist中。

2.1 train方法

void Eigenfaces::train(InputArray _src, InputArray _local_labels) {
    .....
	//首先进行了有效性检查,检查_local_labels类型,_src类型等
	.....
    // get labels
    Mat labels = _local_labels.getMat();
    // observations in row
    Mat data = asRowMatrix(_src, CV_64FC1);//将_src中存放的图像列表中的每幅图像(reshape成1行)作为data的一行
    // number of samples
   int n = data.rows;
    // assert there are as much samples as labels
    if(static_cast<int>(labels.total()) != n) {
        string error_message = format("The number of samples (src) must equal the number of labels (labels)! len(src)=%d, len(labels)=%d.", n, labels.total());
        CV_Error(CV_StsBadArg, error_message);
    }
    // clip number of components to be valid
    if((_num_components <= 0) || (_num_components > n))
        _num_components = n;
    // perform the PCA
    PCA pca(data, Mat(), CV_PCA_DATA_AS_ROW, _num_components);
    // copy the PCA results
    _mean = pca.mean.reshape(1,1); // store the mean vector
    _eigenvalues = pca.eigenvalues.clone(); // eigenvalues by row
    transpose(pca.eigenvectors, _eigenvectors); // eigenvectors by column
    labels.copyTo(_labels); // store labels for prediction
    // save projections
    for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) {
        Mat p = subspaceProject(_eigenvectors, _mean, data.row(sampleIdx));
        _projections.push_back(p);
    }
}

可以看到PCA这个类完成计算,输入是一个矩阵和主成分个数,得到均值,特征值和特征向量。然后转置特征向量为列向量,然后使用subspaceProject进行一下投影,对应上一部分的第4步。PCA这个类的实现在modules/core/src/matmul.cpp中,其内部调用normalize对特征向量进行了归一化。
2.2 predict方法

void Eigenfaces::predict(InputArray _src, int &minClass, double &minDist) const {
    // get data
    Mat src = _src.getMat();
    .......
	//有效性检查
	.......
    // 投影到PCA的主成分空间
    Mat q = subspaceProject(_eigenvectors, _mean, src.reshape(1,1));
    minDist = DBL_MAX;
    minClass = -1;
	//求L2范数也就是欧式距离
    for(size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) {
        double dist = norm(_projections[sampleIdx], q, NORM_L2);
        if((dist < minDist) && (dist < _threshold)) {
            minDist = dist;
            minClass = _labels.at<int>((int)sampleIdx);
        }
    }
}

OK,先写这么多,高手拍砖。

转载于:https://my.oschina.net/MichaelBJFU/blog/97257

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值