日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人工智能 > pytorch >内容正文

pytorch

基于OpenCV与MFC的人脸识别

發布時間:2023/12/10 pytorch 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于OpenCV与MFC的人脸识别 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

基于OpenCV與MFC的人臉識別
本問的完成借鑒了:
基于OpenCV3實現人臉識別(實踐篇)

1、 步驟
數據集制作,數據預處理,模型訓練,人臉識別。
1.1數據集制作
1.1.1準備工作

利用OpenCV基于MFC做的界面獲取自己的數據信息,結合ORL人臉數據庫。ORL庫中共計40人,每人各10張在不同時間、不同光照、不同表情(睜眼閉眼、笑或者不笑)、不同人臉細節(戴眼鏡或者不戴眼鏡)下采集的圖,總計400張圖。
ORL庫可以自行網上下載。
1.1.2個人數據集準備
本文基于OpenCV3.4.5和VS2015實現。
首先是建立一個基于對話框的MFC界面工程我以face1命名,包含兩個Picture Control,和3個按鈕。左側的Picture Control用于實現個人數據獲取,右側的用于之后的識別。兩個Picture Control按照自己設定好ID。雙擊打開攝像頭按鈕進入第一個按鈕的程序編寫。

第一個按鈕程序如下:

Mat frame, myFace; cap.open(0); CascadeClassifier cascada; cascada.load("haarcascade_frontalface_alt2.xml"); //加載分類器 int pic_num = 1; while (flag == 0) {cap >> frame;vector<Rect> faces;//vector容器存檢測到的facesMat frame_gray;//cvtColor(frame, frame_gray,COLOR_BGR2GRAY);//轉灰度化,減少運算frame_gray = frame;cascada.detectMultiScale(frame_gray, faces, 1.1, 4, CV_HAAR_DO_ROUGH_SEARCH, Size(70, 70), Size(1000, 1000));printf("檢測到人臉個數:%zd\n", faces.size());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 = frame_gray(faces[0]);//在灰度圖中將圈出的臉所在區域裁剪出//cout << faces[0].x << endl;//測試下face[0].xresize(faceROI, myFace, Size(92, 112));//將興趣域size為92*112putText(frame, to_string(pic_num), faces[0].tl(), 3, 1.2, (0, 0, 225), 2, 0);//在 faces[0].tl()的左上角上面寫序號string filename = format("%d.jpg", pic_num); //存放在當前項目文件夾以1-10.jpg 命名,format就是轉為字符串imwrite("G:\\實驗室任務\\face1\\face1\\myself\\" + filename, myFace);//存在當前目錄下imshow(filename, myFace);//顯示下size后的臉waitKey(500);//等待500usdestroyWindow(filename);//:銷毀指定的窗口pic_num++;//序號加1if (pic_num == 11){break;//當序號為11時退出循環}}ShowMat(frame, GetDlgItem(IDC_SHOW)->GetSafeHwnd());waitKey(30); }

這部分程序的使用還要進行如下操作,先包含如下頭文件,使用相應的命名空間以及建立一個全局變量。

#include <opencv2\opencv.hpp> #include <vector> #include <iostream> #include<stdio.h> using namespace std; using namespace cv; VideoCapture cap;

因為使用的是MFC的picture control顯示,而我們所用的是OpenCV的Mat來定義圖片變量,要想在picture control上顯示出來需要做變換把Mat轉換為合適的類型。網上用的最多的是已經消失在opencv3中的"Cvvimage.h"來完成,但是大多數都不好用,因此本文中采用的是在查詢了多為大佬后的文章得到的一個方法建立了一個函數轉換成CImage圖來顯示在picture中。(當然我們也可以通過opencv的一個函數的兩次調用也能解決但不方便我們理解原理)
程序如下:

int Cface1Dlg::ShowMat(cv::Mat img, HWND hWndDisplay) {RECT rect;::GetClientRect(hWndDisplay, &rect);cv::Mat imgShow(abs(rect.top - rect.bottom), abs(rect.right - rect.left), CV_8UC3);resize(img, imgShow, imgShow.size());//在控件上顯示要用到的CImage類圖片int w = imgShow.cols;//寬 int h = imgShow.rows;//高 int channels = imgShow.channels();//通道數 CI.Create(w, h, 8 * channels);//CI像素的復制uchar *pS;uchar *pImg = (uchar *)CI.GetBits();//得到CImage數據區地址 int step = CI.GetPitch();if (1 == channels)//調色板改變單通道灰度轉化使得灰度圖可以顯示{RGBQUAD* rgbquadColorTable;int nMaxColors = 256;rgbquadColorTable = new RGBQUAD[nMaxColors];CI.GetColorTable(0, nMaxColors, rgbquadColorTable);for (int nColor = 0; nColor < nMaxColors; nColor++){rgbquadColorTable[nColor].rgbBlue = (uchar)nColor;rgbquadColorTable[nColor].rgbGreen = (uchar)nColor;rgbquadColorTable[nColor].rgbRed = (uchar)nColor;}CI.SetColorTable(0, nMaxColors, rgbquadColorTable);delete[]rgbquadColorTable;}for (int i = 0; i < h; i++){pS = imgShow.ptr<uchar>(i);for (int j = 0; j < w; j++){if (1 == channels){*(pImg + i* step + j) = pS[j];}elseif (3 == channels){for (int k = 0; k < 3; k++)*(pImg + i*step + j * 3 + k) = pS[j * 3 + k];}//注意到這里的step不用乘以3 }}//在控件顯示圖片HDC dc;dc = ::GetDC(hWndDisplay);CI.Draw(dc, 0, 0);::ReleaseDC(hWndDisplay, dc);CI.Destroy();return 0; }

當然我們需要先再MFC界面這個類也就是Cface1Dlg.h中添加函數聲明
int Cface1Dlg::ShowMat(cv::Mat img, HWND hWndDisplay);
然后準備部分的工作就完成了。
當然上述的按鈕中添加的程序還包括了接下來說的數據預處理工作。

1.2數據預處理
在得到自己的人臉照片之后,還需要對這些照片進行一些預處理才能拿去訓練模型。所謂預處理,其實就是檢測并分割出人臉,并改變人臉的大小與下載的數據集中圖片大小一致。
調用opencv訓練好的分類器和自帶的檢測函數檢測人臉人眼等的步驟簡單直接:
1.加載分類器,當然分類器事先要放在工程目錄中去。分類器本來的位置是在*\opencv\sources\data\haarcascades(harr分類器,也有其他的可以用,也可以自己訓練)這個分類器的可以復制到MFC工程文件夾的目錄中,或者直接復制他的路徑調用。
2.調用detectMultiScale()函數檢測,調整函數的參數可以使檢測結果更加精確。
3.把檢測到的人臉等用矩形(或者圓形等其他圖形)畫出來。
下圖來自CSDN的博主快樂成長吧的博客
運行看看可以得到:

框上面的數字對應正在獲得的圖為第幾張。
至此,我們就得到和ORL人臉數據庫人臉大小一致的自己的人臉數據集。得到圖能在工程文件夾中找到,然后我們把自己的作為第41個人,在我們下載的人臉文件夾下建立一個s41的子文件夾,把自己的人臉數據放進去。就成了這樣下面這樣,最后一個文件夾里面是我自己的頭像照片:
(附本文學習時并未使用ORL數據集,只是按起樣子自己準備了一些人物數據,因此并未達到40余人的數據集,這段話也是應引用博主快樂成長吧的博客)。
這里有一點值得注意:保存的圖像格式是*.jpg的,而不是跟原數據集一樣是*.pgm的。經測試仍然可以訓練出可以正確識別我和其他準備識別的人臉的模型來。但是如果大小不一致會報錯,所以大小:92*112。

1.3模型訓練
模型訓練也要做準備工作,首先我們要得到處理后數據集的csv文件,當我們寫人臉模型的訓練程序的時候,我們需要讀取人臉和人臉對應的標簽。直接在數據庫中讀取顯然是低效的。所以我們用csv文件讀取。csv文件中包含兩方面的內容,一是每一張圖片的位置所在,二是每一個人臉對應的標簽,就是為每一個人編號。這個at.txt就是我們需要的csv文件。引用他人的圖做介紹:

前面是圖片的位置,后面是圖片所屬人臉的人的標簽。對于大量的數據時,要生成這樣一個文件直接用手工的方式一個一個輸入顯然不可取的,我們先利用cmd窗口,進入到存放我們的人臉數據的文件夾,然后利用輸入:
dir /b/s *.pgm *.jpg >at.txt生成一個at.txt文件。圖如下(引用他人圖)

這個文件中只有路徑但是沒有標簽,因此選擇利用opencv的python腳本加標簽。opencv教程里面為我們提供了自動生成csv文件的腳本。
路徑類似這樣:

\opencv345\opencv_contrib-3.4.5\modules\face\samples\etc\create_csv.py。

但是opencv_contrib-3.4.5這個屬于拓展庫需要自行去下載以及利用CMake添加生成。這里就不說明了。如果沒安裝我們也可以創建一個create_csv.py文件:程序如下:

import sys import os.path if __name__ == "__main__":#if len(sys.argv) != 2:# print ("usage: create_csv <base_path>")# sys.exit(1)BASE_PATH="數據集的路徑"SEPARATOR=";"fh=open("數據集中at.txt的路徑",'w')label = 0for dirname, dirnames, filenames in os.walk(BASE_PATH):for subdirname in dirnames:subject_path = os.path.join(dirname, subdirname)for filename in os.listdir(subject_path):abs_path = "%s/%s" % (subject_path, filename)print ("%s%s%d" % (abs_path, SEPARATOR, label))fh.write(abs_path)fh.write(SEPARATOR)fh.write(str(label))fh.write("\n")label = label + 1fh.close


填寫如圖然后保存,我們安裝了python3環境的話直接右鍵選擇打開方式為python即可運行產生at.txt在對應的數據集的文件夾中。
接下來在準備工作完成后,開始訓練模型。
在訓練前我們要現在自己下載自己裝的opencv對應的擴展庫opencv_contrib否則無法使用opencv的人臉識別模型,因為現在的opencv功能愈發龐大愈發雜,因此都開始修改為opencv+擴展庫兩部分按需下載。這個可以搜索解決。
現在數據集、csv文件都已經準備好了。接下來要做的就是訓練模型了。
這里我們用到了opencv的Facerecognizer類。opencv中所有的人臉識別模型都是來源于這個類,這個類為所有人臉識別算法提供了一種通用的接口。文檔里的一個小段包含了我們接下來要用到的幾個函數:

OpenCV 自帶了三個人臉識別算法:Eigenfaces(特征臉),Fisherfaces 和局部二進制模式直方圖 (LBPH)。先不深究算法。直接用。接下來就分別訓練這三種人臉模型。Facerecognizer的強大是因為每一種模型的訓練只需要三行代碼:
我們可以新建立一個win32控制臺程序專門做訓練用,修改只要把at.txt的路徑改成自己的即可,程序如下:

#include<opencv2\face\facerec.hpp> //opencv3需要 #include<opencv2\core.hpp> #include<opencv2\face.hpp> #include<opencv2\highgui.hpp> #include<opencv2\imgproc.hpp> #include <math.h> //使用void read_csv()這個函數必須的三個頭文件 #include <iostream> #include <fstream> #include <sstream> using namespace cv; using namespace cv::face; using namespace std;static Mat norm_0_255(InputArray _src) {Mat src = _src.getMat();// 創建和返回一個歸一化后的圖像矩陣: Mat dst;switch (src.channels()) {case 1:cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);break;case 3:cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);break;default:src.copyTo(dst);break;}return dst; } //使用CSV文件去讀圖像和標簽,主要使用stringstream和getline方法 static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {std::ifstream file(filename.c_str(), ifstream::in);//c_str()函數可用可不用,無需返回一個標準C類型的字符串if (!file){string error_message = "No valid input file was given, please check the given filename.";CV_Error(CV_StsBadArg, error_message);}string line, path, classlabel;while (getline(file, line)) //從文本文件中讀取一行字符,未指定限定符默認限定符為“/n”{stringstream liness(line);//這里采用stringstream主要作用是做字符串的分割getline(liness, path, separator);//讀入圖片文件路徑以分好作為限定符getline(liness, classlabel);//讀入圖片標簽,默認限定符if (!path.empty() && !classlabel.empty()) //如果讀取成功,則將圖片和對應標簽壓入對應容器中{images.push_back(imread(path, 0));labels.push_back(atoi(classlabel.c_str()));}} } int main() {//讀取你的CSV文件路徑. //string fn_csv = string(argv[1]); string fn_csv = "G:\\實驗室任務\\face1\\face1\\myself\\at.txt";// 2個容器來存放圖像數據和對應的標簽 vector<Mat> images;vector<int> labels;// 讀取數據. 如果文件不合法就會出錯 // 輸入的文件名已經有了. try{read_csv(fn_csv, images, labels); //從csv文件中批量讀取訓練數據}catch (cv::Exception& e){cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;// 文件有問題,我們啥也做不了了,退出了 exit(1);}// 如果沒有讀取到足夠圖片,也退出. if (images.size() <= 1) {string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";CV_Error(CV_StsError, error_message);}for (int i = 0; i < images.size(); i++){if (images[i].size() != Size(92, 112)){cout << i << endl;cout << images[i].size() << endl;}}// 下面的幾行代碼僅僅是從你的數據集中移除最后一張圖片,作為測試圖片 //[gm:自然這里需要根據自己的需要修改,他這里簡化了很多問題] Mat testSample = images[images.size() - 1];int testLabel = labels[labels.size() - 1];images.pop_back();//刪除最后一張照片,此照片作為測試圖片labels.pop_back();//刪除最有一張照片的labels// 下面幾行創建了一個特征臉模型用于人臉識別, // 通過CSV文件讀取的圖像和標簽訓練它。 // T這里是一個完整的PCA變換 //如果你只想保留10個主成分,使用如下代碼 // cv::createEigenFaceRecognizer(10); // // 如果你還希望使用置信度閾值來初始化,使用以下語句: // cv::createEigenFaceRecognizer(10, 123.0); // // 如果你使用所有特征并且使用一個閾值,使用以下語句: // cv::createEigenFaceRecognizer(0, 123.0); //創建一個PCA人臉分類器,暫時命名為model吧,創建完成后//調用其中的成員函數train()來完成分類器的訓練Ptr<BasicFaceRecognizer> model = EigenFaceRecognizer::create();model->train(images, labels);model->save("MyFacePCAModel.xml");//保存路徑可自己設置,但注意用“\\”Ptr<BasicFaceRecognizer> model1 = FisherFaceRecognizer::create();model1->train(images, labels);model1->save("MyFaceFisherModel.xml");Ptr<LBPHFaceRecognizer> model2 = LBPHFaceRecognizer::create();model2->train(images, labels);model2->save("MyFaceLBPHModel.xml");// 下面對測試圖像進行預測,predictedLabel是預測標簽結果 //注意predict()入口參數必須為單通道灰度圖像,如果圖像類型不符,需要先進行轉換//predict()函數返回一個整形變量作為識別標簽int predictedLabel = model->predict(testSample);//加載分類器int predictedLabel1 = model1->predict(testSample);int predictedLabel2 = model2->predict(testSample);// 還有一種調用方式,可以獲取結果同時得到閾值: // int predictedLabel = -1; // double confidence = 0.0; // model->predict(testSample, predictedLabel, confidence); string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);string result_message1 = format("Predicted class = %d / Actual class = %d.", predictedLabel1, testLabel);string result_message2 = format("Predicted class = %d / Actual class = %d.", predictedLabel2, testLabel);cout << result_message << endl;cout << result_message1 << endl;cout << result_message2 << endl;getchar();//waitKey(0);return 0; }

運行后,模型訓練完,會測試三個模型,產生三個結果。借用大佬圖:

1.4人臉識別:
基本流程如下:
1.打開攝像頭。
2.加載人臉檢測器,加載人臉模型。
3.人臉檢測
4.把檢測到的人臉與人臉模型里面的對比,找出這是誰的臉。
5.如果人臉是自己拍照的人臉,顯示自己的名字。
此處的代碼我們在MFC對話框中的人臉識別按鈕中加入,雙擊這份按鈕進入響應函數中寫代碼。
對比如下的頭文件和命名空間將沒有的補充。

#include<opencv2\opencv.hpp> #include<opencv2\face.hpp> #include<opencv2\core\core.hpp> #include<opencv2\face\facerec.hpp> #include <fstream> #include <sstream> #include<math.h> using namespace std; using namespace cv; using namespace cv::face;

按鈕中的代碼如下:

VideoCapture cap(0); //打開默認攝像頭 if (!cap.isOpened()){return ;}Mat frame;Mat gray;//這個分類器是人臉檢測所用CascadeClassifier cascade;bool stop = false;//訓練好的文件名稱,放置在可執行文件同目錄下 cascade.load("haarcascade_frontalface_alt2.xml");//感覺用lbpcascade_frontalface效果沒有它好,注意哈!要是正臉model = FisherFaceRecognizer::create();//1.加載訓練好的分類器model->read("G:\\實驗室任務\\myface\\MyFaceFisherModel.xml");// opencv2用load//3.利用攝像頭采集人臉并識別while (1){cap >> frame;vector<Rect> faces(0);//建立用于存放人臉的向量容器cvtColor(frame, gray, CV_RGB2GRAY);//測試圖像必須為灰度圖//gray=frame;equalizeHist(gray, gray); //變換后的圖像進行直方圖均值化處理 //檢測人臉cascade.detectMultiScale(gray, faces,1.1, 4, 0//|CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH,//| CV_HAAR_SCALE_IMAGE,Size(70, 70), Size(1000, 1000));Mat* pImage_roi = new Mat[faces.size()]; //定以數組Mat face;Point text_lb;//文本寫在的位置//框出人臉string str;for (int i = 0; i < faces.size(); i++){pImage_roi[i] = gray(faces[i]); //將所有的臉部保存起來text_lb = Point(faces[i].x, faces[i].y);if (pImage_roi[i].empty())continue;switch (Predict(pImage_roi[i])) //對每張臉都識別{case 0:str = "XXX",; break; //case后的數字調整為自己的人臉數據對應的標簽號碼。如標簽為0,str對應相應的名字。case 1:str = "XXX"; break;case 2:str = "XXX"; break;case 3:str = "XXX"; break;default: str = "Error"; break;}Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));//所取的顏色任意值rectangle(frame, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height), color, 3, 8);//放入緩存putText(frame, str, text_lb, FONT_HERSHEY_COMPLEX, 2, Scalar(0, 0, 255));//添加文字}delete[]pImage_roi;ShowMat(frame, GetDlgItem(IDC_SHOW2)->GetSafeHwnd());waitKey(200);}

最后結果如圖:

2、原理
參考:基于OpenCV3實現人臉識別(原理篇)

總結

以上是生活随笔為你收集整理的基于OpenCV与MFC的人脸识别的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。