1.绘制训练集ex7data1.mat的二维图像,所有点在二维平面上的位置:
2.所求的特征向量U的主元1为-0.70711-0.70711i,主元2为-0.70711+0.70711i。所以主成分1的大致方向与横轴夹角为45°,主成分2的方向与横轴夹角为135°。完成PCA主成分分析的操作并截图显示结果,该操作分为两步:首先,计算协方差矩阵前,需要利用featureNormalize .m中的代码将数据集标准化;(提示:调用featureNormalize(X)函数,使得数据集X中的每个特征的均值为0,方差为1,要求结合bsxfun(fun,A,B)函数的帮助文件分析bsxfun(@minus, X, mu); bsxfun(@rdivide, X_norm, sigma)等相关语句的作用);
featureNormalize指特性一般化,它将导入的数据进行预处理,用特性放缩让数据的范围缩小,使得梯度下降计算的更快。这里是用原特征数据减去均值再除以方差之后的特征值代替原有特征值。
bsxfun(fun, A,B)函数对两个矩阵进行数据的处理。作用是:对两个矩阵A和B之间的每一个元素进行指定的计算(函数fun指定);并且具有自动扩维的作用。使用@minus作为参数表示对于X中的每个元素都与mu进行减法,即各列的数据减去相应列的平均值,使得每列的数据的平均值再次计算后为0的状态。
使用std函数来计算处理平均值后的数据的标准差。最后除以标准差得到最终返回处理的数据。
bsxfun(@minus,X,mu)函数用于计算X与mu两个矩阵对应元素相减所得到的矩阵。
bsxfun(@rdivide,X_norm,sigma)函数用于计算X_nom矩阵对应元素除以 sigma 矩阵对应元素所得到的矩阵。
下图是经过特性一般化之后的数据图像,它与原图像大致方位一样,但是更集中,梯度下降的更快。
3.计算数据集的协方差矩阵并使用SVD()函数计算该矩阵的特征向量.
奇异值分解(SVD):
m×n的实数矩阵A,把它分解为A=UΣVT其中U和V均为单位正交阵,即有UUT=I和VVT=I,U称为左奇异矩阵,V称为右奇异矩阵,分别放奇异向量,Σ仅在主对角线上有值,非负且按降序排列,我们称它为奇异值,其它元素均为0。上面矩阵的维度分别为U∈Rm×m, Σ∈Rm×n, V∈Rn×n。
svd(X)函数的使用方法,[U,S,V]=svd(X),S即Σ,即返回的是一个与X同大小的主对角矩阵S,和两个正交矩阵U和V。
主成分所在方向如下图:
由两个特征向量可得出两个特征向量与x轴夹角分别为-45°和45°且两个特征向量相互垂直。
4.完成基于PCA的维度缩减操作,该操作首先从高维空间向低维空间投影,然后反向投影以重建数据集.
投影过程如下图:原来的二维数据降维到一维,红点即投影后的点,为原来数据投影到主要特征向量上所构成。
5.压缩后还原重建的数据:
function X_rec = recoverData(Z, U, K)
X_rec = zeros(size(Z, 1), size(U, 1));
X_rec=Z*U(:,1:K)’;
%降维之后的数据集乘以前 K 个特征向量的转置
End
6.在人脸数据集下使用主成分分析。取出该数据集中的前100张人脸并通过截图显示出来;
7.对人脸数据进行特征标准化操作和pca主成分分析,每个主成分都是一个1024维的向量(可转化为一张32*32的图片)
左边图像绘制了前36个特征向量构成的人脸图像,右边为绘制了前49个特征向量构成的人脸图像。这些特征向量是构成5000张人脸图像的基础,前面的几幅图尚且能大致看出人脸,后面的几乎只有五官的位置凸显出来。
对比截图如下:
8.通过projectData()函数将原始数据投影到前100个特征之上,并通过recoverData()函数重建压缩后的人脸图像,最终对比分析一下原始人脸图像(X_norm)与压缩后的人脸图像(X_rec)
左侧为原始人脸,右侧为使用PCA后提取前100个特征降维处理再还原后的人脸。降维处理还原后的人脸相较原始人脸是要模糊一些,因为降维时舍弃了一部分特征向量,所以还原有所损失,导致模糊。原本的每张人脸都有1024个数据,而我们使用PCA降维使之只保留了前100个主要的特征向量,而舍弃了后100到1024个特征向量,所以还原后较于原始人脸模糊一些。
原始人脸图像(X_norm)与压缩后的人脸图像(X_rec)如下图所示:
10.实时表情识别:
表情识别包括六种表情的识别,分别是’angry’、‘fear’、 ‘happy’、 ‘sad’、 ‘surprise’、 ‘neutral’。
过程:
- 捕获指定摄像头的实时视频流;
- 每5ms从摄像头读取一帧图片,然后执行以下操作
1> 截取图片预处理:将图片灰化(以达到减小图片的大小,增加检测速度)
2> 调用人脸分类器检测脸部
3> 如果检测到脸部则执行下一操作,否则重新检测;
4> 将检测到的人脸大小设置为48(图像预处理:减小图片大小,增加检测速度)
5> 由预处理的图片获取四张图片:原图,水平翻转的图片(镜像),原图和镜像垂直翻转的图片。截取图片中2-45的部分,即舍去了1,26,47,48,尽可能只保留有表情的部分人脸(其中原图的权值设置为2,其他三张权值为1,这样以提高准确率)
6> 同时判断四张图片剩余部分的表情,将各个图片的表情概率相加
7> 相加的结果的最大索引(表情)将被显示在屏幕上即被检测到的人脸的表情结果
3.按键盘‘Q’退出实时表情识别,结束识别。
表情识别重要代码
while True:
_, frame = cap.read() #读取一帧视频
#注:_返回的是一个布尔值,fram返回的是一帧图像(三维矩阵)
#图像灰化,降低计算复杂度 frame_gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
#使用人脸识别分类器,读入分类器
cascade = cv2.CascadeClassifier(cascade_path)
#利用分类器检测脸部
faceRects=cascade.detectMultiScale(frame_gray, scaleFactor = 1.1,minNeighbors = 1, minSize = (120, 120))
if len(faceRects) > 0:
for faceRect in faceRects:
x, y, w, h = faceRect
images=[]
rs_sum=np.array([0.0]num_class)
#得到一个数组(矩阵)
#截取脸部图像提交给模型识别这是谁
image = frame_gray[y: y + h, x: x + w ]
image=cv2.resize(image,(img_size,img_size))
image=image(1./255)
images.append(image)
images.append(image)
images.append(cv2.flip(image,1))
#图像翻转(1,水平翻转;0,垂直翻转;-1,水
平垂直翻转)
images.append(cv2.flip(image,0))
images.append(cv2.resize(image[2:45,:],(I mg_size,img_size)))
for img in images:#把预测的结果累加并且输出
image=img.reshape(1,img_size,img_size,1)
list_of_list = model.predict_proba(image,batch_size=32,verbose=1)#predict预测
result = [prob for lst in list_of_list for prob in lst]
rs_sum+=np.array(result)
print(rs_sum)
label=np.argmax(rs_sum)
#得出每一列矩阵中的最大索引 (概率)
emo = emo_labels[label]
识别效果:
结果分析:
按照实验要求及实验步骤,我们实验达到了在不损失更多细节的前提下完成图片的压缩以及将压缩后的图片进行重构还原;在拓展部分也成功实现了对摄像头实时捕捉的人脸进行表情识别。
心得体会:
通过本次实验,我对PCA主程序分析有了一定的认识,在查阅资料和实验过程中,我了解到本实验进行的操作,是将数据提取出重要的主成分特征向量后,舍弃一部分较不重要的特征向量,从而达到将原始数据降维的操作,但进行主程序分析前,我们要将数据进行特性一般化,重要的一点是找出原始数据的特征向量和特征值。通过人脸降维操作,我发现,降维还原后的人脸变得模糊,即降维后的数据是可以重构出原始数据但会有所损失,即在降维时所舍弃的较不重要的特征向量被遗失,虽然与原图存在差异,但这并不影响我们的识别,降维的处理将各个数据的价值变得更加明显,方便后续对数据进行分析,这就是PCA主程序分析的强大和数据降维的意义。
代码链接:https://pan.baidu.com/s/11DfwzB4WVz_eeBbusixuIQ
提取码:zk2n