正文:
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;
vector<Rect>faces(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類的強大了。因爲每一種模型的訓練只需要三行。
Ptr<FaceRecognizer>model = 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;
}
Ptr<BasicFaceRecognizer>model;//創建人臉分類器
model = FisherFaceRecognizer::create();
model->read("MyFaceFisherModel.xml");//加載以訓練好的模型
CascadeClassifier cascade;
cascade.load("haarcascade_frontalface_alt2.xml");//加載檢測人臉的模型
Mat gray, frame;
string s;
while (1) {
cap >> frame;
vector<Rect>faces(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<opencv2/opencv.hpp>
#include<opencv2/face.hpp>
#include<opencv2/face/facerec.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/core.hpp>
#include<iostream>
#include<fstream>
using namespace std;
using namespace cv;
using namespace cv::face;
Point p;
vector<Mat>images;
string temp, str[10005];
int res[1005], t;
vector<int>labels;
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;
vector<Rect>faces(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);
}
}
Ptr<FaceRecognizer>model = 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;
}
Ptr<BasicFaceRecognizer>model;
model = FisherFaceRecognizer::create();
model->read("MyFaceFisherModel.xml");
CascadeClassifier cascade;
cascade.load("haarcascade_frontalface_alt2.xml");
Mat gray, frame;
string s;
while (1) {
cap >> frame;
vector<Rect>faces(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這個軟件查找文件。