1 Star 0 Fork 6

欣欣然阿/opencv

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
_13人脸识别(手写).py 8.00 KB
一键复制 编辑 原始数据 按行查看 历史
[email protected] 提交于 2022-02-26 18:26 . Initial commit
# -*- coding: utf-8 -*-
"""
Created on Fri Aug 17 17:53:30 2018
@author: lenovo
"""
'''
自己实现一个人脸识别
'''
'''
人脸识别经典算法实现(一)——特征脸法:https://blog.csdn.net/freedom098/article/details/52088064
第一种比较经典的算法就是特征脸法,本质上其实就是PCA降维,这种算法的基本思路是,把二维的图像先灰度化,
转化为一通道的图像,之后再把它首尾相接转化为一个列向量,假设图像大小是20*20的,那么这个向量就是400维
,理论上讲组织成一个向量,就可以应用任何机器学习算法了,但是维度太高算法复杂度也会随之升高,所以需要
使用PCA算法降维,然后使用简单排序或者KNN都可以。
PCA降维:将一组N维向量降到K维,PCA通过寻找K个单位正交基,使得原始数据变换到这组基后各个字段两两间协方差
为0,而字段的方差尽可能大
http://blog.codinglabs.org/articles/pca-tutorial.html
'''
import numpy as np
import cv2
import os
from sklearn import neighbors
def load_images(data):
'''
加载数据集
params:
data:训练集数据所在的目录,要求数据尺寸大小一样
ret:
images:[m,height,width] m为样本数,height为高,width为宽
names:名字的集合
labels:标签
'''
images = []
labels = []
names = []
label = 0
#过滤所有的文件夹
for subDirname in os.listdir(data):
subjectPath = os.path.join(data,subDirname)
if os.path.isdir(subjectPath):
#每一个文件夹下存放着一个人的照片
names.append(subDirname)
for fileName in os.listdir(subjectPath):
imgPath = os.path.join(subjectPath,fileName)
img = cv2.imread(imgPath,cv2.IMREAD_GRAYSCALE)
images.append(img)
labels.append(label)
label += 1
images = np.asarray(images)
labels = np.asarray(labels)
return images,labels,names
class EigenFace(object):
def __init__(self,dimNum=150,n_neighbors=3,dsize=(100,100)):
'''
构造函数:初始化参数
params:
dimNum:PCA降维后的维度k
n_neighbors:knn的参数n_neighbors
dsize:对输入图像进行预处理,指定图像预处理时缩放的尺寸
'''
self.__dimNum = dimNum
self.__dsize = dsize
self.__mean = 0.0
self.__knn = neighbors.KNeighborsClassifier(n_neighbors)
def __pca(self,X):
'''
使用PCA对数据进行降维
params:
X:源数据,形状为[m,n] m为样本数,n为样本的维数
return:
降维后的训练集数据[m,k] 和变换矩阵P = [k,n]
'''
#[n,m]
X = X.T
#均值化矩阵 [n,]
mean = np.reshape(np.mean(X,axis=1),(-1,1))
self.__mean = mean
#去均值 [n,m] - [n,1]
diff = X - mean
'''
求协方差矩阵
这里不去直接去求np.dot(diff,diff.T)的的特征向量和特征值,而是通过求np.dot(diff.T,diff)的特征向量和特征值变换得到
主要是因为np.dot(diff,diff.T)为[n,n]
np.dot(diff.T,diff)为[m,m]
特征数远大于样本数,所以直接对[n,n]矩阵求特征值比较慢
'''
cov = np.dot(diff.T,diff)/diff.shape[1]
'''
计算[m,m]的协方差矩阵的特征值[m,]和特征向量[m,m]
'''
eigVals,eigVects = np.linalg.eig(cov)
#通过左乘diff得到[n,n]矩阵的特征向量[n,m]
eigVects = np.dot(diff,eigVects)
print('特征向量维度:',eigVects.shape)
#对特征值进行排序 返回排序后的索引顺序,从小到大排序
eigValIndex = np.argsort(eigVals)
#从大到小排序
eigValIndex = eigValIndex[::-1]
#取出指定个数的前k大的特征值
eigValIndex = eigValIndex[:self.__dimNum]
#归一化特征向量
eigVects = eigVects/np.linalg.norm(eigVects,axis=0)
#变换矩阵[k,n]
transMat = (eigVects.T)[eigValIndex,:]
#计算经过变换矩阵变换后的新数据 [k,n]x[n,m] = [k,m]
lowMat = np.dot(transMat,diff)
#[m,k]
lowMat = lowMat.T
print('降维后的矩阵lowMat维度为:',lowMat.shape)
return lowMat,transMat
def __prepare(self,images):
'''
对图片进行预处理,统一尺寸,直方图均衡化(防止曝光不均衡)
params:
images:训练集数据,要求为灰度图片 [m,height,width] m为样本数,height为高,width为宽
return:
处理之后的数据 [m,n] n = dsize[0]x dsize[1] 即特征数
'''
new_images = []
for image in images:
#缩放
re_img = cv2.resize(image,self.__dsize)
#直方图均衡化
hist_img = cv2.equalizeHist(re_img)
#转换成一行数据
hist_img = np.reshape(hist_img,-1)
new_images.append(hist_img)
new_images = np.asarray(new_images)
return new_images
def fit(self,X_train,Y_train):
'''
训练,这里使用KNN算法
params:
X_train:训练集数据,要求为灰度图片 [m,height,width] m为样本数,height为高,width为宽
Y_train:训练集标签 [m,]
'''
#对图片数据进行预处理 [M,N]
X_train = self.__prepare(X_train)
#对图片数据进行降维处理 X_train_pca:[m,k] __transMat:[n,k]
X_train_pca,self.__transMat = self.__pca(X_train)
#开始训练
self.__knn.fit(X_train_pca,Y_train)
def predict(self,X_test):
'''
开始预测
params:
X_test:测试图片,要求为灰度图片 [m,hight,width]
return:
Y_pred:[m,1] 返回预测的标签
'''
if len(X_test.shape) == 2:
X_test = np.expand_dims(X_test,axis=0)
#对数据进行预处理 [m,n]
X_test = self.__prepare(X_test)
#计算经过变换矩阵变换后的新数据 [m,k]
X_test_pca = np.dot(self.__transMat,X_test.T-self.__mean)
X_test_pca = X_test_pca.T
Y_pred = self.__knn.predict(X_test_pca)
return Y_pred
if __name__=='__main__':
face = EigenFace(100)
#准备训练集数据
X_train,Y_train,names = load_images('./face')
face.fit(X_train,Y_train)
#创建一个级联分类器 加载一个 .xml 分类器文件. 它既可以是Haar特征也可以是LBP特征的分类器.
face_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml')
#打开摄像头
camera = cv2.VideoCapture(0)
cv2.namedWindow('Dynamic')
print('开始预测')
while(True):
#读取一帧图像
ret,frame = camera.read()
#判断图片读取成功?
if ret:
gray_img = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
#人脸检测
faces = face_cascade.detectMultiScale(gray_img,1.3,5)
for (x,y,w,h) in faces:
#在原图像上绘制矩形
frame = cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray_img[y:y+h,x:x+w]
Y_pred = face.predict(roi_gray)
name = names[Y_pred[0]]
print('Label:%s'%(name))
cv2.putText(frame,name,(x,y-20),cv2.FONT_HERSHEY_SIMPLEX,1,255,2)
cv2.imshow('Dynamic',frame)
#如果按下q键则退出
if cv2.waitKey(100) & 0xff == ord('q') :
break
camera.release()
cv2.destroyAllWindows()
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/top_xiong/opencv.git
[email protected]:top_xiong/opencv.git
top_xiong
opencv
opencv
master

搜索帮助