医疗电子技术网|技术阅读
登录|注册

您现在的位置是:医疗电子技术网 > 技术阅读 > 人脸识别经典算法实现

人脸识别经典算法实现

最近研究了一下人脸识别,发现里面很有门道啊,我是初入,还不是很理解,只能到时看看论坛,到处学习啊。感谢各位先人的帖子和代码。本帖部分原创,部分借用,如有雷同,纯属巧合!!!
首先需要2个第三方的库
opencv-python、numpy

安装完成后,可以编程了,还是先说明一下需要的算法:

特征子脸技术的基本思想是:从统计的观点,寻找人脸图像分布的基本元素,即人脸图像样本集协方差矩阵的特征向量,以此近似地表征人脸图像。这些特征向量称为特征脸(Eigenface)。

实际上,特征脸反映了隐含在人脸样本集合内部的信息和人脸的结构关系。将眼睛、面颊、下颌的样本集协方差矩阵的特征向量称为特征眼、特征颌和特征唇,统称特征子脸。特征子脸在相应的图像空间中生成子空间,称为子脸空间。计算出测试图像窗口在子脸空间的投影距离,若窗口图像满足阈值比较条件,则判断其为人脸。 
    基于特征分析的方法,也就是将人脸基准点的相对比率和其它描述人脸脸部特征的形状参数或类别参数等一起构成识别特征向量,这种基于整体脸的识别不仅保留了人脸部件之间的拓扑关系,而且也保留了各部件本身的信息,而基于部件的识别则是通过提取出局部轮廓信息及灰度信息来设计具体识别算法。现在Eigenface(PCA)算法已经与经典的模板匹配算法一起成为测试人脸识别系统性能的基准算法;而自1991年特征脸技术诞生以来,研究者对其进行了各种各样的实验和理论分析,FERET'96测试结果也表明,改进的特征脸算法是主流的人脸识别技术,也是具有最好性能的识别方法之一。
    该方法是先确定眼虹膜、鼻翼、嘴角等面像五官轮廓的大小、位置、距离等属性,然后再计算出它们的几何特征量,而这些特征量形成一描述该面像的特征向量。其技术的核心实际为“局部人体特征分析”和“图形/神经识别算法。”这种算法是利用人体面部各器官及特征部位的方法。如对应几何关系多数据形成识别参数与数据库中所有的原始参数进行比较、判断与确认。Turk和Pentland提出特征脸的方法,它根据一组人脸训练图像构造主元子空间,由于主元具有脸的形状,也称为特征脸  ,识别时将测试  图像投影到主元子空间上,得到一组投影系数,和各个已知人的人脸图像比较进行识别。Pentland等报告了相当好的结果,在 200个人的 3000幅图像中得到 95%的正确识别率,在FERET数据库上对 150幅正面人脸象只有一个误识别。但系统在进行特征脸方法之前需要作大量预处理工作如归一化等。
    在传统特征脸的基础上,研究者注意到特征值大的特征向量 (即特征脸 )并不一定是分类性能好的方向,据此发展了多种特征 (子空间 )选择方法,如Peng的双子空间方法、Weng的线性歧义分析方法、Belhumeur的FisheRFace方法等。事实上,特征脸方法是一种显式主元分析人脸建模,一些线性自联想、线性压缩型BP网则为隐式的主元分析方法,它们都是把人脸表示为一些向量的加权和,这些向量是训练集叉积阵的主特征向量,Valentin对此作了详细讨论。总之,特征脸方法是一种简单、快速、实用的基于变换系数特征的算法,但由于它在本质上依赖于训练集和测试集图像的灰度相关性,而且要求测试图像与训练集比较像,所以它有着很大的局限性。

基于KL 变换的特征人脸识别方法
基本原理:
    KL变换是图象压缩中的一种最优正交变换,人们将它用于统计特征提取,从而形成了子空间法模式识别的基础,若将KL变换用于人脸识别,则需假设人脸处于低维线性空间,且不同人脸具有可分性,由于高维图象空间KL变换后可得到一组新的正交基,因此可通过保留部分正交基,以生成低维人脸空间,而低维空间的基则是通过分析人脸训练样本集的统计特性来获得,KL变换的生成矩阵可以是训练样本集的总体散布矩阵,也可以是训练样本集的类间散布矩阵,即可采用同一人的数张图象的平均来进行训练,这样可在一定程度上消除光线等的干扰,且计算量也得到减少,而识别率不会下降。


下面开始编程,过程中发现pcv好复杂啊,增加了些打印,方便调试用。


#encoding=utf-8  

import numpy as np  

import cv2  

import os  

  

class EigenFace(object):  

    def __init__(self,threshold,dimNum,dsize):  

        self.threshold = threshold # 阈值暂未使用  

        self.dimNum = dimNum  

        self.dsize = dsize  

  

    def loadImg(self,fileName,dsize):  

        ''''' 

        载入图像,灰度化处理,统一尺寸,直方图均衡化 

        :param fileName: 图像文件名 

        :param dsize: 统一尺寸大小。元组形式 

        :return: 图像矩阵 

        '''  

        img = cv2.imread(fileName)  

        retImg = cv2.resize(img,dsize)  

        retImg = cv2.cvtColor(retImg,cv2.COLOR_RGB2GRAY)  

        retImg = cv2.equalizeHist(retImg)  

        # cv2.imshow('img',retImg)  

        # cv2.waitKey()  

        return retImg  

  

  

    def createImgMat(self,dirName):  

        ''''' 

        生成图像样本矩阵,组织形式为行为属性,列为样本 

        :param dirName: 包含训练数据集的图像文件夹路径 

        :return: 样本矩阵,标签矩阵 

        '''  

        dataMat = np.zeros((10,1))  

        label = []  

        for parent,dirnames,filenames in os.walk(dirName):  

            # print parent  

            # print dirnames  

            # print filenames  

            index = 0  

            for dirname in dirnames:  

                for subParent,subDirName,subFilenames in os.walk(parent+'/'+dirname):  

                    for filename in subFilenames:  

                        img = self.loadImg(subParent+'/'+filename,self.dsize)  

                        tempImg = np.reshape(img,(-1,1))  

                        IF index == 0 :  

                            dataMat = tempImg  

                        else:  

                            dataMat = np.column_stack((dataMat,tempImg))  

                        label.append(subParent+'/'+filename)  

                        index += 1  

        return dataMat,label  

  

  

    def PCA(self,dataMat,dimNum):  

        ''''' 

        PCA函数,用于数据降维 

        :param dataMat: 样本矩阵 

        :param dimNum: 降维后的目标维度 

        :return: 降维后的样本矩阵和变换矩阵 

        '''  

        # 均值化矩阵  

        meanMat = np.mat(np.mean(dataMat,1)).T  

        print u'平均值矩阵维度',meanMat.shape  

        diffMat = dataMat-meanMat  

        # 求协方差矩阵,由于样本维度远远大于样本数目,所以不直接求协方差矩阵,采用下面的方法  

        covMat = (diffMat.T*diffMat)/float(diffMat.shape[1]) # 归一化  

        #covMat2 = np.cov(dataMat,bias=True)  

        #print '基本方法计算协方差矩阵为',covMat2  

        print u'协方差矩阵维度',covMat.shape  

        eigVals, eigVects = np.linalg.eig(np.mat(covMat))  

        print u'特征向量维度',eigVects.shape  

        print u'特征值',eigVals  

        eigVects = diffMat*eigVects  

        eigValInd = np.argsort(eigVals)  

        eigValInd = eigValInd[::-1]  

        eigValInd = eigValInd[:dimNum] # 取出指定个数的前n大的特征值  

        print u'选取的特征值',eigValInd  

        eigVects = eigVects/np.linalg.norm(eigVects,axis=0) #归一化特征向量  

        redEigVects = eigVects[:,eigValInd]  

        print u'选取的特征向量',redEigVects.shape  

        print u'均值矩阵维度',diffMat.shape  

        lowMat = redEigVects.T*diffMat  

        print u'低维矩阵维度',lowMat.shape  

        return lowMat,redEigVects  

  

    def compare(self,dataMat,testImg,label):  

        ''''' 

        比较函数,这里只是用了最简单的欧氏距离比较,还可以使用KNN等方法,如需修改修改此处即可 

        :param dataMat: 样本矩阵 

        :param testImg: 测试图像矩阵,最原始形式 

        :param label: 标签矩阵 

        :return: 与测试图片最相近的图像文件名 

        '''  

        testImg = cv2.resize(testImg,self.dsize)  

        testImg = cv2.cvtColor(testImg,cv2.COLOR_RGB2GRAY)  

        testImg = np.reshape(testImg,(-1,1))  

        lowMat,redVects = self.PCA(dataMat,self.dimNum)  

        testImg = redVects.T*testImg  

        print u'检测样本变换后的维度',testImg.shape  

        disList = []  

        testVec = np.reshape(testImg,(1,-1))  

        for sample in lowMat.T:  

            disList.append(np.linalg.norm(testVec-sample))  

        print disList  

        sortIndex = np.argsort(disList)  

        return label[sortIndex[0]]  

  

  

    def predict(self,dirName,testFileName):  

        ''''' 

        预测函数 

        :param dirName: 包含训练数据集的文件夹路径 

        :param testFileName: 测试图像文件名 

        :return: 预测结果 

        '''  

        testImg = cv2.imread(testFileName)  

        dataMat,label = self.createImgMat(dirName)  

        print u'加载图片标签',label  

        ans = self.compare(dataMat,testImg,label)  

        return ans  

  

  

if __name__ == '__main__':  

    eigenface = EigenFace(200,500,(500,500))  

    print eigenface.predict('d:/face/11.bmp','D:/face1/1.bmp')  


免责声明:本文转自电子发烧友论坛,传播仅为学习交流,版权归原作者所有,如有侵权,请联系删除