2018华中赛数学建模总结整理


转眼已经大四了,非常荣幸能拿到学校推免的资格,加上大四也没什么课程,所以闲下来整理一下大学的一些比赛和项目的经历,希望能重新学习到一些东西,本篇主要是大二下劳动节的时候参加的18年数学建模华中赛,也是大学的第一个比赛,比较幸运的是拿到了一等奖,特此整理一下当时的思路和代码

题目:人脸识别

题目简介

2017年7月,国务院印发了《新一代人工智能发展规划》,欲创建规模达1万亿元的国内人工智能产业,到2030年使中国成为世界主要人工智能创新中心。教育部也推出了“中国高校人工智能人才国际培养计划”,拟在五年内培训顶尖高校至少500名教师和5000名学生。同时,教育部公布了全面的《高等学校人工智能创新行动计划》,培养人才以支持中国2030年人工智能目标。
什么是人工智能?简而言之就是,让机器人能够学习并模仿人类行为,甚至能够像人一样思考。人工智能机器人认识和接触这个世界最主要的途径是“看”和“听”,而第一步就是要让人工智能机器人能够“看”。特别地,人脸识别在人工智能中显得特别重要,机器人通过人脸识别技术认识周围的人,判断他们的心情,和人们面对面打交道。
人脸识别除了在人工智能中有不少应用之外,这项技术走进了我们的日常生活:美图秀秀等手机APP把人脸识别技术用于“一键美颜”;学校和公司逐步安装了人脸识别考勤机;警方在刑事侦查时,也经常采用人脸识别技术从海量信息中寻找犯罪嫌疑人;交互式机器人通过人脸识别技术判断用户的心情……

曾经神秘的人脸识别技术,由于越来越贴近生活,现在也变得平常起来。只要你有一台普普通通的电脑,学过一点编程知识,就可以DIY自己的人脸识别技术。大家是不是已经跃跃欲试了呢?嘿,别急,在DIY前先来看看“大牛们”用人脸识别干了些什么事。比如说有些手机,自拍时你能看到有一个小方框框住了你的脸,你一动,小方框也会跟着你动,在相册里,系统能够挑出照片里的各个人物,还能找到这个人物的其他照片。比如说“How-old.Net”这个APP,它能看脸猜年龄,曾经风靡了朋友圈。

好了,大家一定等不及想要DIY人脸识别技术了,在开始之前,先介绍一种常用的人脸识别方法:第一步,确定人脸的位置;第二步,对人脸做一些技术处理;第三步,提取人脸的细节特征。还有啊,图像处理这样的小伎俩我相信大家都没什么问题,那么,还废话什么,放手去做吧!
最后提醒大家:学习新知识是一件让人开心的事情,不要为了比赛能拿奖而用Photoshop等软件滥竽充数。我希望看到大家渴望知识的眼神,看到大家在DIY成功之后的欣喜笑容,或者是失败后默默钻研的认真态度。但绝不希望大家为了提交比赛论文而随随便便写一篇自己都不信的东西出来,尽管你提交论文了,但你失去的是了解新知识、挖掘自己潜力的机会!

请建立数学模型,解决下列三个问题:
(1)建立人脸位置判断的数学模型,判断人脸在照片中的大致位置,并在图1和图2中用你设计的模型“框出”人脸的大致位置。
(2)在问题(1)的基础上,建立人脸精确识别的数学模型,判断图2中各个人物的脸型、鼻型、眼型、唇形等。(提示:如果你在DIY过程中遇到了困难,不妨降低要求,比如说鼻型可以分为“大鼻子”和“小鼻子”。)
(3)在问题(2)的基础上,建立人脸匹配的数学模型,判断图2、图3中是否有人物与图1的人物是同一人,如果有,请在图片中框出具体是哪个人物与图1的人物一样。

附件:1. 附件_图1.jpg
2. 附件_图2.jpg
3. 附件_图3.jpg
由于原件比较大,就用截图代替吧:)

第一题思路

我们人类可以一眼看出RGB图像中人脸在图片的什么位置,但是计算机却不能准确判断,所以有没有一种色彩空间能让计算机通过像素值的大小判断出皮肤的位置呢?

答案是肯定的,这种色彩空间叫做YCbCr

我们根据RGB图像建立色彩空间YCbCr,为原始图像在该色彩空间中的肤色检测奠定基础。

根据网上查阅相关文献资料得出肤色的范围如下:

100=<cb<=127
138=<cr<=170

整体思路就是先通过RGB图像变换为YCbCr图像,然后根据通道范围的筛选出肤色区域,经过图像的腐蚀与去噪填充处理图像,形成二值图像,根据人脸的形态学特征删除不符合长宽比的区域最后定位到原图像,输出即可。

第二题思路

第二题要求是判断脸型如何,我们处理的思路是先检测出人脸的一些关键点,通过这些关键点的位置信息和比例来判断,并且通过搜集网上的一些实例图片来作为判断的依据。
第二题我是用C++做的,
主要做法是导入外部的库识别人脸的68个特征点,通过访问这68个特征点的位置坐标信息,判断出人的脸型和一些特征,期间用一些网上的典型实例做标准来确定(比如大眼睛小眼睛)的阈值进行判断,具体操作我在这里就不赘述了。

第三题思路

由于人脸图像的维度非常高,可以通过PCA变换,消除数据的相关性,找到一个空间,使得各个类别的数据在该空间上能够很好地分离。首先将训练样本在该空间进行投影,得到投影样本的特征系数,然后将测试样本也在该空间进行投影,得到每个测试样本的投影特征系数,此时只需将测试某个样本的特征系数与训练样本投影特征系数进行欧式距离度量,看要测试的那个样本与训练集中哪个样本的欧式距离最近,就可以将该测试样本归为与之距离最近那个样本的类别,即这两个样本是同一个人。

第一题结果

易烊千玺的检测效果
在这里插入图片描述
在这里插入图片描述

第二题结果

根据第一题分割出来的脸部区域,下面是对三个人的识别结果:
在这里插入图片描述

第三题结果

首先检查第二个图片中有没有易烊千玺
在这里插入图片描述
然后在第三张图片中检查
在这里插入图片描述

第一题代码

这里只贴出一张图片的代码,其他图片类似

src=imread('pic1.jpg');
f=src;
f=rgb2ycbcr(f);%rgb转换为ycbcr空间
f_cb=f(:,:,2);%取Cb通道的值
f_cr=f(:,:,3);%取Cr通道的值
f=(f_cb>=100)&(f_cb<=127)&(f_cr>=138)&(f_cr<=170);%皮肤在YCbCr空间的分布范围
figure(1),imshow(f),title('皮肤区域');
figure(2),imshow(~f),title('取反图像');%没什么作用,可以删除

se=strel('square',3);%创建3*3的正方形模板
f=imopen(f,se);%开操作,先腐蚀后膨胀
f=imclose(f,se);%闭操作,先膨胀后腐蚀
f=imfill(f,'holes');%填充孔洞
figure(3),imshow(f),title('去噪填孔');

fe=imerode(f,ones(8,8));%腐蚀图像
fo=imopen(f,ones(8,8));%开操作
f=imreconstruct(fe,fo);%恢复图像到腐蚀之前的图像
figure(4),imshow(f),title('重构图像');

sel=strel('square',8);
f=imerode(f,sel);%先腐蚀
f=imdilate(f,sel);%后膨胀,目的是断开头部与衣服的连接,使面部更好的分离
res=f;
figure(5),imshow(res),title('闭运算断开连接');

figure(6),imshow(src);
[L,num]=bwlabeln(f,4);%对图像的连通域进行处理
stats=regionprops(L,'basic');%计算连通域的属性,比如面积,边界
k=1;
for i=1:num%对每个连通域进行循环
    [r,c]=find(L==i);
    area=stats(i).Area;%得出面积
    temp=size(r);
    if area>650000||area<100000%面积不在范围内的肤色区域去除
        for j=1:temp(1)
            L(r(j),c(j))=0;
        end
    else%头部区域访问边界信息,在原图上用红框标出
        tempBound = stats(i).BoundingBox;
        rectangle('position',tempBound,'edgecolor','r');
        cut=imcrop(src,tempBound);
        cut=imresize(cut,[460,460],'bicubic');
        imwrite(cut,'cut1-1.jpg');
    end
end
figure(7),imshow(L);

第二题代码

#include <dlib/opencv.h>  
#include <opencv2/opencv.hpp>  
#include <dlib/image_processing/frontal_face_detector.h>  
#include <dlib/image_processing/render_face_detections.h>  
#include <dlib/image_processing.h>  
#include <dlib/gui_widgets.h>  
#include <vector>
#include<math.h>

using namespace dlib;
using namespace std;

#define PI 3.1415926535

double Angle(cv::Point o, cv::Point s, cv::Point e)
{
	double cosfi = 0, fi = 0, norm = 0;
	double dsx = s.x - o.x;
	double dsy = s.y - o.y;
	double dex = e.x - o.x;
	double dey = e.y - o.y;

	cosfi = dsx * dex + dsy * dey;
	norm = (dsx * dsx + dsy * dsy) * (dex * dex + dey * dey);
	cosfi /= sqrt(norm);

	if (cosfi >= 1.0) return 0;
	if (cosfi <= -1.0) return PI;
	fi = acos(cosfi);

	if (180 * fi / PI < 180)
	{
		return 180 * fi / PI;
	}
	else
	{
		return 360 - 180 * fi / PI;
	}
}

void FittingCurve(std::vector<cv::Point> vec, double * index, int len)
{
	double *px = new double[vec.size()];
	double *py = new double[len*vec.size()];
	int i = 0;
	for (std::vector<cv::Point>::iterator itr = vec.begin(); itr != vec.end(); ++itr)
	{
		px[i] = (*itr).x;
		int j = 0;
		while (j<len)
		{
			py[len*i + j] = pow((*itr).y, double(j));
			j++;
		}
		i++;
	}

	CvMat xMat = cvMat(vec.size(), 1, CV_64FC1, px);
	CvMat yMat = cvMat(vec.size(), len, CV_64FC1, py);
	CvMat *yTransposedMat = cvCreateMat(yMat.cols, yMat.rows, CV_64FC1);
	cvTranspose(&yMat, yTransposedMat);//求yMat的转置

	double *a = new double[len*len];
	for (int i = 0; i<len*len; ++i)
	{
		a[i] = 0;
	}
	CvMat invMat1 = cvMat(len, len, CV_64FC1, a);
	cvGEMM(yTransposedMat, &yMat, 1, NULL, 0, &invMat1, 0);//yMat的转置与yMat矩阵相乘
	cvInvert(&invMat1, &invMat1, 0);//求invMat的逆矩阵

	double *b = new double[len];
	for (int i = 0; i<len; ++i)
	{
		b[i] = 0;
	}
	CvMat invMat2 = cvMat(len, 1, CV_64FC1, b);
	cvGEMM(yTransposedMat, &xMat, 1, NULL, 0, &invMat2, 0);//求yMat的转置矩阵与xMat矩阵相乘


	cvGEMM(yTransposedMat, &xMat, 1, NULL, 0, &invMat2, 0);//求yTransposedMat矩阵与xMat 矩阵的乘积
	CvMat indexMat = cvMat(len, 1, CV_64FC1, index);
	cvGEMM(&invMat1, &invMat2, 1, NULL, 0, &indexMat, 0);


	cvReleaseMat(&yTransposedMat);
	delete[] a;
	delete[] b;
	delete[] px;
	delete[] py;
}

bool polynomial_curve_fit(std::vector<cv::Point>& key_point, int n, cv::Mat& A)
{
	//Number of key points  
	int N = key_point.size();

	//构造矩阵X  
	cv::Mat X = cv::Mat::zeros(n + 1, n + 1, CV_64FC1);
	for (int i = 0; i < n + 1; i++)
	{
		for (int j = 0; j < n + 1; j++)
		{
			for (int k = 0; k < N; k++)
			{
				X.at<double>(i, j) = X.at<double>(i, j) +
					std::pow(key_point[k].x, i + j);
			}
		}
	}

	//构造矩阵Y  
	cv::Mat Y = cv::Mat::zeros(n + 1, 1, CV_64FC1);
	for (int i = 0; i < n + 1; i++)
	{
		for (int k = 0; k < N; k++)
		{
			Y.at<double>(i, 0) = Y.at<double>(i, 0) +
				std::pow(key_point[k].x, i) * key_point[k].y;
		}
	}

	A = cv::Mat::zeros(n + 1, 1, CV_64FC1);
	//求解矩阵A  
	cv::solve(X, Y, A, cv::DECOMP_LU);
	return true;
}

void facetype(full_object_detection face)
{
	//0-16
	int x[17], y[17];
	for (int i = 0, j = 0; i <= 16; i++, j++)
	{
		x[j] = face.part(i).x();
		y[j] = face.part(i).y();
	}
	double len = sqrt((x[0] - x[16])*(x[0] - x[16]));
	double high = sqrt((y[4] - y[8])*(y[4] - y[8]));
	double s_all = len*high;
	double a = sqrt((x[4] - x[8])*(x[4] - x[8]) + (y[4] - y[8])*(y[4] - y[8]));
	double b = sqrt((x[12] - x[8])*(x[12] - x[8]) + (y[12] - y[8])*(y[12] - y[8]));
	double c = sqrt((x[4] - x[12])*(x[4] - x[12]) + (y[4] - y[12])*(y[4] - y[12]));
	double q = (a + b + c) / 2;
	double s_part = sqrt(q*(q - a)*(q - b)*(q - c));
	double ratio = s_part / s_all;
	cout << "下巴比例:" << ratio << endl;
	if (ratio > 0.48)
		cout << "该目标下巴偏粗" << endl;
	else
		cout << "该目标下巴偏细" << endl;
}

void faceout(full_object_detection face)
{
	ofstream ofile;               //定义输出文件
	ofile.open("facedata.txt");     //作为输出文件打开
	for (int i = 0, j = 0; i <= 16; i++, j++)
		ofile << face.part(i).x() <<" "<< face.part(i).y()<<endl;
	ofile.close();
}

void facetype2(full_object_detection face)
{
	std::vector<cv::Point> vec;
	//0-16
	int x[17], y[17];
	for (int i = 0, j = 0; i <= 16; i++, j++)
	{
		x[j] = face.part(i).x();
		y[j] = face.part(i).y();
	}
	cv::Mat image = cv::Mat::zeros(800, 700, CV_8UC3);
	image.setTo(cv::Scalar(100, 0, 0));
	//输入拟合点    
	for (int i = 0; i < 17; i++)
	{
		vec.push_back(cv::Point(x[i], y[i]));
	}

	//将拟合点绘制到空白图上    
	for (int i = 0; i < vec.size(); i++)
	{
		cv::circle(image, vec[i], 5, cv::Scalar(0, 0, 255), 2, 8, 0);
	}

	//绘制折线  
	cv::polylines(image, vec, false, cv::Scalar(0, 255, 0), 1, 8, 0);

	double index[3];
	FittingCurve(vec, index, 3);
	std::cout << "A(face) = " << index[0] << ";" << endl << index[1] << ";" <<endl << index[2] << ";" << endl;

	std::vector<cv::Point> points_fitted;

	for (int x = 0; x < 700; x++)
	{
		/*double y = A.at<double>(0, 0) + A.at<double>(1, 0) * x +
		A.at<double>(2, 0)*std::pow(x, 2) + A.at<double>(3, 0)*std::pow(x, 3);*/
		double y = index[0] + index[1] * x +index[2]*std::pow(x, 2);

		points_fitted.push_back(cv::Point(x, y));
	}
	cv::polylines(image, points_fitted, false, cv::Scalar(0, 255, 255), 1, 8, 0);

	cv::imshow("facetype", image);
}

void nosetype(full_object_detection face)
{
	//27-35
	double a = sqrt((face.part(27).x() - face.part(31).x())*(face.part(27).x() - face.part(31).x()) +
		(face.part(27).y() - face.part(31).y())*(face.part(27).y() - face.part(31).y()));
	double b = sqrt((face.part(27).x() - face.part(35).x())*(face.part(27).x() - face.part(35).x()) +
		(face.part(27).y() - face.part(35).y())*(face.part(27).y() - face.part(35).y()));
	double c = sqrt((face.part(35).x() - face.part(31).x())*(face.part(35).x() - face.part(31).x()) + 
		(face.part(35).y() - face.part(31).y())*(face.part(35).y() - face.part(31).y()));
	double p = (a + b + c) / 2;
	double len = sqrt((face.part(1).x() - face.part(15).x())*(face.part(1).x() - face.part(15).x()) +
		(face.part(1).y() - face.part(15).y())*(face.part(1).y() - face.part(15).y()));
	double wid1 = sqrt((face.part(0).x() - face.part(2).x())*(face.part(0).x() - face.part(2).x()) + 
		(face.part(0).y() - face.part(2).y())*(face.part(0).y() - face.part(2).y()));
	double wid2 = sqrt((face.part(14).x() - face.part(16).x())*(face.part(14).x() - face.part(16).x()) + 
		(face.part(14).y() - face.part(16).y())*(face.part(14).y() - face.part(16).y()));
	double wid = (wid1 + wid2) / 2;
	double s_nose = sqrt(p*(p - a)*(p - b)*(p - c));
	double s_face = len*wid;
	double ratio = s_nose / s_face;
	cout << "目标鼻子比例为:" << ratio << endl;
	if (ratio > 0.13)
		cout << "该目标为大鼻子" << endl;
	else
		cout << "该目标为小鼻子" << endl;

}

void eyetype(full_object_detection face,double *k)
{
	int x[4], y[4];
	for (int i = 36, j = 0; i <= 39; i++, j++)
	{
		x[j] = face.part(i).x();
		y[j] = face.part(i).y();
	}

	/*for (int i = 0; i < 4; i++)
	{
		vec.push_back(cvPoint2D64f(x[i], y[i]));
	}
	double index[3];
	FittingCurve(vec, index, 3);
	for (int i = 0; i < 3; ++i)
	{
		cout << index[i] << endl;
	}*/
	cv::Mat image = cv::Mat::zeros(480, 640, CV_8UC3);
	image.setTo(cv::Scalar(100, 0, 0));

	//输入拟合点    
	std::vector<cv::Point> points;
	for (int i = 0; i < 4; i++)
	{
		points.push_back(cv::Point(x[i], y[i]));
	}

	//将拟合点绘制到空白图上    
	for (int i = 0; i < points.size(); i++)
	{
		cv::circle(image, points[i], 5, cv::Scalar(0, 0, 255), 2, 8, 0);
	}

	//绘制折线  
	cv::polylines(image, points, false, cv::Scalar(0, 255, 0), 1, 8, 0);

	cv::Mat A;

	polynomial_curve_fit(points, 2, A);
	std::cout << "A(eye) = " << A << std::endl;

	std::vector<cv::Point> points_fitted;

	for (int x = 0; x < 400; x++)
	{
		/*double y = A.at<double>(0, 0) + A.at<double>(1, 0) * x +
			A.at<double>(2, 0)*std::pow(x, 2) + A.at<double>(3, 0)*std::pow(x, 3);*/
		double y = A.at<double>(0, 0) + A.at<double>(1, 0) * x +
			A.at<double>(2, 0)*std::pow(x, 2);

		points_fitted.push_back(cv::Point(x, y));
	}

	for (int i = 0; i < 4; i++)
	{
		k[i] = A.at<double>(1, 0) + A.at<double>(2, 0)*points[i].x;
	}

	cv::polylines(image, points_fitted, false, cv::Scalar(0, 255, 255), 1, 8, 0);

	cv::imshow("eyetype", image);
}

double eyecal(double *k1,double *k2)
{
	double addson = 0;
	double addmo1 = 0;
	double addmo2 = 0;
	for (int i = 0; i < 4; i++)
	{
		addson += k1[i] * k2[i];
		addmo1 += k1[i] * k1[i];
		addmo2 += k2[i] * k2[i];
	}
	double addmo = sqrt(addmo1*addmo2);
	double similarity = addson / addmo;
	return similarity;
}

void eyejudge(full_object_detection face1, full_object_detection face2, full_object_detection face3)
{
	double k0[4];
	double k1[4];
	double k2[4];
	eyetype(face1, k0);
	eyetype(face2, k1);
	eyetype(face3, k2);
	double sim1 = eyecal(k0, k1);
	double sim2 = eyecal(k0, k2);
	cout << "与大眼睛样本相似度为:" << sim1 << endl;
	cout << "与小眼睛样本相似度为:" << sim2 << endl;
	if (sim1 > sim2)
	{
		cout << "该目标眼睛偏大" << endl;
	}
	else
	{
		cout << "该目标眼睛偏小" << endl;
	}
}

void mousetype(full_object_detection face)
{
	double b = sqrt((face.part(66).x() - face.part(57).x())*(face.part(66).x() - face.part(57).x()) +
		(face.part(66).y() - face.part(57).y())*(face.part(66).y() - face.part(57).y()));
	double a = sqrt((face.part(48).x() - face.part(54).x())*(face.part(48).x() - face.part(54).x()) + 
		(face.part(48).y() - face.part(54).y())*(face.part(48).y() - face.part(54).y())) / 2;
	double c = sqrt(a*a - b*b);
	double e = c / a;
	cout <<"目标嘴唇离心率为:" << e << endl;
	if (e > 0.85)
		cout << "该目标为薄嘴唇" << endl;
	else
		cout << "该目标为厚嘴唇" << endl;
}

int main()
{
	clock_t start, end;
	start = clock();
	frontal_face_detector detector = get_frontal_face_detector();
	shape_predictor pose_model;
	deserialize("shape_predictor_68_face_landmarks.dat") >> pose_model;

	// Grab and process frames until the main window is closed by the user.  
	// Grab a frame  
	cv::Mat temp = cv::imread("mat3.jpg");
	/*cv::Mat tempbig = cv::imread("bigeye.jpg");
	cv::Mat tempsmall = cv::imread("smalleye.jpg");*/

	cv_image<bgr_pixel> cimg(temp);
	/*cv_image<bgr_pixel> cimgbig(tempbig);
	cv_image<bgr_pixel> cimgsmall(tempsmall);*/
	// Detect faces   
	std::vector<rectangle> faces = detector(cimg);
	/*std::vector<rectangle> facesbig = detector(cimgbig);
	std::vector<rectangle> facessmall = detector(cimgsmall);*/
	// Find the pose of each face.  
	std::vector<full_object_detection> shapes;
	/*std::vector<full_object_detection> shapesbig;
	std::vector<full_object_detection> shapessmall;*/
	int num_per;
	for (unsigned long i = 0; i < faces.size(); ++i)
	{
		shapes.push_back(pose_model(cimg, faces[i]));
		num_per = i + 1;
	}
	for (int i = 0; i < num_per;i++)
	{
		for (int j = 0; j < 68; j++) 
		{
			circle(temp, cvPoint(shapes[i].part(j).x(), shapes[i].part(j).y()), 3, cv::Scalar(0, 0, 255), -1);
			//  shapes[0].part(i).x();//68个  
			putText(temp, to_string(j), cvPoint(shapes[i].part(j).x(), shapes[i].part(j).y()), CV_FONT_HERSHEY_PLAIN, 1, cv::Scalar(255, 0, 0), 1, 4);
		}
		/*nosetype(shapes[i]);
		mousetype(shapes[i]);
		eyetype(shapes[i]);
		faceout(shapes[i]);*/
		/*eyejudge(shapes[i], shapesbig[0], shapessmall[0]);*/
		facetype(shapes[i]);
		nosetype(shapes[i]);
		mousetype(shapes[i]);
	}
	//Display it all on the screen  
	end = clock();
	cout << "程序运行时间为:" << (double)(end - start) / 1000 << "秒" << endl;
	imshow("Dlib特征点", temp);
	cv::waitKey(0);
}

第三题代码

img=imread('cut1-1.jpg');
img=rgb2gray(img);
[m,n] = size(img);
img=reshape(img,1,m*n);
facepath='C:\Users\Administrator\Desktop\yi';
filesjpg = ls(strcat(facepath,'\*.jpg'));
files =(cellstr(filesjpg));
len = length(files);
cachepath=facepath;
for i = 1:len
    facepath=cachepath;
    facepath = strcat(facepath,'\',files(i));
    libface{i} = imread(cell2mat(facepath));
    libface{i}=rgb2gray(libface{i});
    lib_face(i,:)=reshape(libface{i},1,n*m);
end

facepath='C:\Users\Administrator\Desktop\yi';
filesjpg = ls(strcat(facepath,'\*.jpg'));
files =(cellstr(filesjpg));
len = length(files);
cachepath=facepath;
for i = 1:len
    facepath=cachepath;
    facepath = strcat(facepath,'\',files(i));
    testface{i} = imread(cell2mat(facepath));
    testface{i}=rgb2gray(testface{i});
    test_face0(i,:)=reshape(testface{i},1,n*m);
end

testface{1}=imread('cut2-1.jpg');
testface{1}=rgb2gray(testface{1});
test_2(1,:) = reshape(testface{1},1,m*n);
testface{2}=imread('cut2-2.jpg');
testface{2}=rgb2gray(testface{2});
test_2(2,:) = reshape(testface{2},1,m*n);
testface{3}=imread('cut2-3.jpg');
testface{3}=rgb2gray(testface{3});
test_2(3,:) = reshape(testface{3},1,m*n);

for i=1:10
    name=strcat("cut3-",num2str(i));
    name=strcat(name,".jpg");
    testface{i}=imread(cell2mat(name));
    testface{i}=rgb2gray(testface{i});
    test_3(i,:) = reshape(testface{i},1,m*n);
end

[img_new,img_mean,V] = PCA(lib_face,16);
facefind(img_new,img_mean,V,test_2,1);


function [img_new,img_mean,V] = PCA(img,k)  
%用法:  [img_new,img_mean,V] = PCA(train_face,k)  
%reshape函数:改变句矩阵的大小,矩阵的总元素个数不能变  
img = double(img);  
[m,n] = size(img);  %取大小  
img_mean = mean(img); %求每列平均值  
img_mean_all = repmat(img_mean,m,1);%复制m行平均值至整个矩阵  
Z = img - img_mean_all;  
T=Z*Z';  %协方差矩阵(非原始所求矩阵的协方差)    
[V,D] = eigs(T,k);%计算T中最大的前k个特征值与特征向量  
V=Z'*V;         %协方差矩阵的特征向量    
for i=1:k       %特征向量单位化    
    l=norm(V(:,i));    
    V(:,i)=V(:,i)/l;    
end    
img_new = (Z*V)';  %低维度下的各个脸的数据 
end

function facefind(img_new,img_mean,V,test_face,k) 
find=0;
place=0;
num_train = size(img_new,1);  %训练脸总数  
num_test = size(test_face,1); %测试脸总数  
for i = 1:num_test  
    pic = double(test_face(i,:));  
    pic1 = pic - img_mean;  
    pic2 = pic1*V;   
    error(i) = norm(img_new(1,:) - pic2);  %求取范数距离
    if(error(i)<=4.2000e+04&&error(i)>=4.0000e+04)%平均范数距离为4.1089e+04
        find=1;
        place=i;
    end
    disp(error(i));
    
end
if(find==0)
    disp('该组照片没有目标人物');
else
     str=strcat("该组照片有目标人物,为第"+num2str(place));
    str=strcat(str,"个老吊");
    disp(str);
end
end

猜你喜欢

转载自blog.csdn.net/weixin_39478524/article/details/103186395