正文:
1.既然说做个小软件那就,先做个简单的软件封面。
随便找一个图片,然后手动画上自己需要的按钮,然后设置鼠标反应。
画按钮:
void buttonset() {
rectangle(image, Point(48, 340), Point(154, 300), Scalar(0, 0, 255), -1, 8, 0);
putText(image, "storeface", Point(51, 335), 0, 0.7, Scalar(255, 0, 0), 1, 8, 0);
rectangle(image, Point(48, 400), Point(154, 360), Scalar(0, 0, 255), -1, 8, 0);
putText(image, "CHECK", Point(51, 395), 0, 1, Scalar(255, 0, 0), 1, 8, 0);
rectangle(image, Point(165, 400), Point(271, 360), Scalar(0, 0, 255), -1, 8, 0);
putText(image, "CLOSE", Point(168, 395), 0, 1, Scalar(255, 0, 0), 1, 8, 0);
}
2,按钮storcefoce是储存人脸,然后训练成模型,其中我们可以用到ORL人脸数据集40个人,每人10张照片。照片在不同时间、不同光照、不同表情(睁眼闭眼、笑或者不笑)、不同人脸细节(戴眼镜或者不戴眼镜)下采集。所有的图像都在一个黑暗均匀的背景下采集的,正面竖直人脸(有些有有轻微旋转)。
准备识别人脸的数据集,并把自己的人脸拍10张,和ORL数据集储存到一起。
opencv自带的有人脸检查的模型比如 haarcascade_frontalface_alt2.xml
拍照程序:
void storeface() {
bool flag = false;
CascadeClassifier cascade;
cascade.load("haarcascade_frontalface_alt2.xml");//加载模型
VideoCapture cap(0);//打开摄像头
Mat myface, frame;
int num = 1;
t += 1;
string f = "ORL\\s";
string command;
command = "mkdir -p " + f + to_string(t);
system(command.c_str());//在ORL文件夹里新建一个储存这次检测到的脸部的文件夹,t为文件名表示数字,t是现在数据集里有多少人的脸,初始是40,第一个人脸是41
while (1) {
cap >> frame;
vectorfaces(0);//vector容器储存检测到的faces
Mat gray;
cvtColor(frame, gray, COLOR_BGR2GRAY);//转灰度化,减少运算
equalizeHist(gray, gray);
cascade.detectMultiScale(gray, faces, 1.1, 4, CV_HAAR_DO_ROUGH_SEARCH, Size(70, 70), Size(1000, 1000));//检测人脸,百度可找到该函数用法
for (int i = 0; i < faces.size(); i++)
rectangle(frame, faces[i], Scalar(255, 0, 0), 2, 8, 0);//在每张人脸上画矩形
if (faces.size() == 1) {
Mat faceROI = gray(faces[0]);//检测到的人脸局部照片
resize(faceROI, myface, Size(92, 112));//改变照片的大小为 92,112
putText(frame, to_string(num), faces[0].tl(), 3, 1.2, (0, 0, 255), 2, 0);//在举行上标数字
string filename = format("ORL\\s%d\\%d.jpg", t, num);//将人脸照片储存到刚才新建的文件夹里
imwrite(filename, myface);
waitKey(500);
num++;
if (num == 11)break;//当已经储存10张后退出
}
imshow("项目", frame);
waitKey(50);
}
//将ORL里的所有照片存进images vector容器内
for (int i = 1; i <= 40; i++) {
for (int j = 1; j <= 10; j++) {
temp = format("ORL\\s%d\\%d.pgm", i, j);
images.push_back(imread(temp, 0));//储存照片
labels.push_back(i);//该组照片的序号
}
}
for (int i = 41; i <= t; i++) {
for (int j = 1; j <= 10; j++) {
temp = format("ORL\\s%d\\%d.jpg", i, j);
images.push_back(imread(temp, 0));
labels.push_back(i);
}
}
//OpenCV 自带了三个人脸识别算法:Eigenfaces(特征脸),Fisherfaces 和局部二进制模式直方图 (LBPH)。这里先不去深究这些算法的具体内容,直接用就是了。如果有兴趣可以去看相关论文。接下来就分别训练这三种人脸模型。这个时候就能体现出Facerecognizer类的强大了。因为每一种模型的训练只需要三行。
Ptrmodel = FisherFaceRecognizer::create();//创建一个PCA人脸分类器,暂时命名为model吧,创建完成后
model->train(images, labels);//调用其中的成员函数train()来完成分类器的训练
model->save("MyFaceFisherModel.xml");//将训练好的模型保存下来
fstream file1;
file1.open("成员.txt", ios::in | ios::app);//打开已建好的txt文件
string name;
cout << "请输入你的姓名:" << endl;//输入以储存此人的姓名,只能用字母
cin >> name;
file1 << name << endl;//写入姓名
file1.close();
str[t] = name;//储存起来
res[t] = 1;
}
这里有一点值得注意:保存的图像格式是*.jpg的,而不是跟原数据集一样是*.pgm的。经测试仍然可以训练出可以正确识别我和其他准备识别的人脸的模型来。但是如果大小不一致会报错,所以大小:92*112。
3,按钮check就是识别人脸了
void checkface() {
VideoCapture cap(0);//打开摄像头
if (!cap.isOpened()) {
cout << "error" << endl;
return;
}
Ptrmodel;//创建人脸分类器
model = FisherFaceRecognizer::create();
model->read("MyFaceFisherModel.xml");//加载以训练好的模型
CascadeClassifier cascade;
cascade.load("haarcascade_frontalface_alt2.xml");//加载检测人脸的模型
Mat gray, frame;
string s;
while (1) {
cap >> frame;
vectorfaces(0);
cvtColor(frame, gray, COLOR_BGR2GRAY);//转化灰度
equalizeHist(gray, gray);//直方图均值化
cascade.detectMultiScale(gray, faces, 1.1, 4, 0 | CV_HAAR_DO_ROUGH_SEARCH, Size(30, 30), Size(500, 500));//检测人脸
Mat myface, face_test;
int predict;
for (int i = 0; i < faces.size(); i++) {
myface = gray(faces[i]);//找到人脸
resize(myface, face_test, Size(92, 112));//改变照片大小
predict = model->predict(face_test);识别人脸,得到预测值,这个预测值就是之前训练模型时与人脸一起训练的序号
if (res[predict]) {//如果储存过此脸
s = str[predict];//s为该人脸的名字
}
else {
s = "error";
}
rectangle(frame, faces[i], Scalar(255, 0, 0), 2, 8, 0);//在人脸上画框
putText(frame, s, faces[i].tl(), 3, 1.2, Scalar(0, 0, 255), 2, 0);//显示该人脸的名字
}
imshow("项目", frame);
waitKey(20);
}
}
4,整个代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
using namespace cv::face;
Point p;
vectorimages;
string temp, str[10005];
int res[1005], t;
vectorlabels;
bool f = false, g = false, h = false;
Mat image = imread("1.jpg");
void buttonset() {
rectangle(image, Point(48, 340), Point(154, 300), Scalar(0, 0, 255), -1, 8, 0);
putText(image, "storeface", Point(51, 335), 0, 0.7, Scalar(255, 0, 0), 1, 8, 0);
rectangle(image, Point(48, 400), Point(154, 360), Scalar(0, 0, 255), -1, 8, 0);
putText(image, "CHECK", Point(51, 395), 0, 1, Scalar(255, 0, 0), 1, 8, 0);
rectangle(image, Point(165, 400), Point(271, 360), Scalar(0, 0, 255), -1, 8, 0);
putText(image, "CLOSE", Point(168, 395), 0, 1, Scalar(255, 0, 0), 1, 8, 0);
}
void on_Mouse(int event, int x, int y, int flags, void* param) {
switch (event) {
case CV_EVENT_LBUTTONDOWN:
{
if (x <= 154 && x >= 48 && y >= 300 && y <= 340)
f = true;
if (x <= 154 && x >= 48 && y >= 360 && y <= 400)
g = true;
if (x <= 271 && x >= 165 && y >= 360 && y <= 400)
h = true;
}break;
case CV_EVENT_LBUTTONUP:
{
f = false;
}break;
}
}
void Mouse() {
namedWindow("项目");
while (1) {
setMouseCallback("项目", on_Mouse, (void*)&image);
if (f || g || h) {
break;
}
imshow("项目", image);
waitKey(20);
}
}
void storeface() {
bool flag = false;
CascadeClassifier cascade;
cascade.load("haarcascade_frontalface_alt2.xml");
VideoCapture cap(0);
Mat myface, frame;
int num = 1;
t += 1;
string f = "ORL\\s";
string command;
command = "mkdir -p " + f + to_string(t);
system(command.c_str());
while (1) {
cap >> frame;
vectorfaces(0);
Mat gray;
cvtColor(frame, gray, COLOR_BGR2GRAY);
equalizeHist(gray, gray);
cascade.detectMultiScale(gray, faces, 1.1, 4, CV_HAAR_DO_ROUGH_SEARCH, Size(70, 70), Size(1000, 1000));
for (int i = 0; i < faces.size(); i++)
rectangle(frame, faces[i], Scalar(255, 0, 0), 2, 8, 0);
if (faces.size() == 1) {
Mat faceROI = gray(faces[0]);
resize(faceROI, myface, Size(92, 112));
putText(frame, to_string(num), faces[0].tl(), 3, 1.2, (0, 0, 255), 2, 0);
string filename = format("ORL\\s%d\\%d.jpg", t, num);
imwrite(filename, myface);
waitKey(500);
num++;
if (num == 11)break;
}
imshow("项目", frame);
waitKey(50);
}
for (int i = 1; i <= 40; i++) {
for (int j = 1; j <= 10; j++) {
temp = format("ORL\\s%d\\%d.pgm", i, j);
images.push_back(imread(temp, 0));
labels.push_back(i);
}
}
for (int i = 41; i <= t; i++) {
for (int j = 1; j <= 10; j++) {
temp = format("ORL\\s%d\\%d.jpg", i, j);
images.push_back(imread(temp, 0));
labels.push_back(i);
}
}
Ptrmodel = FisherFaceRecognizer::create();
model->train(images, labels);
model->save("MyFaceFisherModel.xml");
fstream file1;
file1.open("成员.txt", ios::in | ios::app);
string name;
cout << "请输入你的姓名:" << endl;
cin >> name;
file1 << name << endl;
file1.close();
str[t] = name;
res[t] = 1;
}
void checkface() {
VideoCapture cap(0);
if (!cap.isOpened()) {
cout << "error" << endl;
return;
}
Ptrmodel;
model = FisherFaceRecognizer::create();
model->read("MyFaceFisherModel.xml");
CascadeClassifier cascade;
cascade.load("haarcascade_frontalface_alt2.xml");
Mat gray, frame;
string s;
while (1) {
cap >> frame;
vectorfaces(0);
cvtColor(frame, gray, COLOR_BGR2GRAY);
equalizeHist(gray, gray);
cascade.detectMultiScale(gray, faces, 1.1, 4, 0 | CV_HAAR_DO_ROUGH_SEARCH, Size(30, 30), Size(500, 500));
Mat myface, face_test;
int predict;
for (int i = 0; i < faces.size(); i++) {
myface = gray(faces[i]);
resize(myface, face_test, Size(92, 112));
predict = model->predict(face_test);
if (res[predict]) {
s = str[predict];
}
else {
s = "error";
}
rectangle(frame, faces[i], Scalar(255, 0, 0), 2, 8, 0);
putText(frame, s, faces[i].tl(), 3, 1.2, Scalar(0, 0, 255), 2, 0);
}
imshow("项目", frame);
waitKey(20);
}
}
int main() {
int i = 1;
memset(res, 0, sizeof(res));
string line;
t = 40;
fstream file1;
file1.open("成员.txt", ios::in | ios::app);
while (getline(file1, line)) {
cout << line << endl;
str[t + i] = line;
res[t + i] = 1;
i++;
}
file1.close();
t += (i - 1);//靠成员.txt得到t
cout << t << endl;
images.empty();
labels.empty();
buttonset();
while (1) {
Mouse();
if (f)
storeface();
if (g)
checkface();
if (h)
break;
f = false;
g = false;
}
return 0;
}
已经储存过的人脸不能再次储存
5,按钮close就是关闭
6,软件使用流程,打开后点击storeface可以储存你想储存的人脸,储存10张后等待一会可以在exe文件内输入姓名,
点击check就可以检测人脸,点击close关闭软件。
7,把程序封装成exe安装包程序
https://blog.csdn.net/qq_40810653/article/details/89681925
另外如果想添加程序需要用到的dll文件,可以在vs调试程序,然后在输出窗口就可以看到程序加载了哪些dll库,然后在电脑里找到在打包的时候添加进去,推荐用everything这个软件查找文件。