本篇測(cè)評(píng)由電子工程世界的優(yōu)秀測(cè)評(píng)者“流行科技”提供。此次測(cè)試的開(kāi)源項(xiàng)目,是基于QT+OpenCV的人臉識(shí)別打卡項(xiàng)目。本次體驗(yàn)使用的是開(kāi)源的代碼,此代碼本來(lái)是運(yùn)行在WIN下的,為了測(cè)試稍微進(jìn)行了修改,讓其運(yùn)行在米爾iMX8M Plus開(kāi)發(fā)板上。測(cè)試項(xiàng)目實(shí)際是分了兩個(gè)工程,一個(gè)工程是作為管理員控制功能使用,添加人臉信息。同時(shí)也可以查詢到打卡記錄,對(duì)從機(jī)進(jìn)行下發(fā)通知等等。人臉識(shí)別我們主要需要用到opencv的人臉檢測(cè)分類器。OpenCV編譯完成后已經(jīng)提供好了的。因?yàn)檫@里還需要涉及到訓(xùn)練模型,有了模型后才能更好的識(shí)別,所以還是簡(jiǎn)單介紹下怎么訓(xùn)練的吧。 ??
- CascadeClassifier cascada;
- //將opencv官方訓(xùn)練好的人臉識(shí)別分類器拷貝到自己的工程目錄中
- cascada.load("F:\\video\\ccc\\haarcascade_frontalface_alt2.xml");
- VideoCapture cap(1); //0表示電腦自帶的,如果用一個(gè)外接攝像頭,將0變成1
- Mat frame, myFace;
- int pic_num = 1;
- while (1) {
- //攝像頭讀圖像
- cap >> frame;
- vector faces;//vector容器存檢測(cè)到的faces
- Mat frame_gray;
- cvtColor(frame, frame_gray, COLOR_BGR2GRAY);//轉(zhuǎn)灰度化,減少運(yùn)算
- cascada.detectMultiScale(frame_gray, faces, 1.1, 4, CV_HAAR_DO_ROUGH_SEARCH, Size(70, 70), Size(1000, 1000));
- printf("檢測(cè)到人臉個(gè)數(shù):%d\n", faces.size());
- //識(shí)別到的臉用矩形圈出
- for (int i = 0; i < faces.size(); i++)
- {
- rectangle(frame, faces, Scalar(255, 0, 0), 2, 8, 0);
- }
- //當(dāng)只有一個(gè)人臉時(shí),開(kāi)始拍照
- if (faces.size() == 1)
- {
- Mat faceROI = frame_gray(faces[0]);//在灰度圖中將圈出的臉?biāo)趨^(qū)域裁剪出
- //cout << faces[0].x << endl;//測(cè)試下face[0].x
- resize(faceROI, myFace, Size(92, 112));//將興趣域size為92*112
- putText(frame, to_string(pic_num), faces[0].tl(), 3, 1.2, (0, 0, 225), 2, 0);//在 faces[0].tl()的左上角上面寫(xiě)序號(hào)
- string filename = format("F:\\video\\%d.jpg", pic_num); //圖片的存放位置,frmat的用法跟QString差不對(duì)
- imwrite(filename, myFace);//存在當(dāng)前目錄下
- imshow(filename, myFace);//顯示下size后的臉
- waitKey(500);//等待500us
- destroyWindow(filename);//:銷毀指定的窗口
- pic_num++;//序號(hào)加1
- if (pic_num == 11)
- {
- return 0;//當(dāng)序號(hào)為11時(shí)退出循環(huán),一共拍10張照片
- }
- }
- int c = waitKey(10);
- if ((char)c == 27) { break; } //10us內(nèi)輸入esc則退出循環(huán)
- imshow("frame", frame);//顯示視頻流
- waitKey(100);//等待100us
- }
- return 0;
通過(guò)上面代碼,完成圖像采集。
//讀取你的CSV文件路徑.
//string fn_csv = string(argv[1]);
string fn_csv = "F:\\video\\ccc\\at.txt";
// 2個(gè)容器來(lái)存放圖像數(shù)據(jù)和對(duì)應(yīng)的標(biāo)簽
vector images;
vector<int> labels;
// 讀取數(shù)據(jù). 如果文件不合法就會(huì)出錯(cuò)
// 輸入的文件名已經(jīng)有了.
try
{
read_csv(fn_csv, images, labels); //從csv文件中批量讀取訓(xùn)練數(shù)據(jù)
}
catch (cv::Exception& e)
{
cerr << "Error opening file "" << fn_csv << "". Reason: " << e.msg << endl;
// 文件有問(wèn)題,我們啥也做不了了,退出了
exit(1);
}
// 如果沒(méi)有讀取到足夠圖片,也退出.
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++)
{
//cout<
if (images.size() != Size(92, 112))
{
cout << i << endl;
cout << images.size() << endl;
}
}
// 下面的幾行代碼僅僅是從你的數(shù)據(jù)集中移除最后一張圖片,作為測(cè)試圖片
//[gm:自然這里需要根據(jù)自己的需要修改,他這里簡(jiǎn)化了很多問(wèn)題]
Mat testSample = images[images.size() - 1];
int testLabel = labels[labels.size() - 1];
images.pop_back();//刪除最后一張照片,此照片作為測(cè)試圖片
labels.pop_back();//刪除最有一張照片的labels
// 下面幾行創(chuàng)建了一個(gè)特征臉模型用于人臉識(shí)別,
// 通過(guò)CSV文件讀取的圖像和標(biāo)簽訓(xùn)練它。
// T這里是一個(gè)完整的PCA變換
//如果你只想保留10個(gè)主成分,使用如下代碼
// cv::createEigenFaceRecognizer(10);
//
// 如果你還希望使用置信度閾值來(lái)初始化,使用以下語(yǔ)句:
// cv::createEigenFaceRecognizer(10, 123.0);
//
// 如果你使用所有特征并且使用一個(gè)閾值,使用以下語(yǔ)句:
// cv::createEigenFaceRecognizer(0, 123.0);
//創(chuàng)建一個(gè)PCA人臉?lè)诸惼鳎瑫簳r(shí)命名為model吧,創(chuàng)建完成后
//調(diào)用其中的成員函數(shù)train()來(lái)完成分類器的訓(xùn)練
Ptr model = face::create();
model->train(images, labels);
model->save("MyFacePCAModel.xml");//保存路徑可自己設(shè)置,但注意用“\\”
Ptr model1 = face::create();
model1->train(images, labels);
model1->save("MyFaceFisherModel.xml");
Ptr model2 = face::create();
model2->train(images, labels);
model2->save("MyFaceLBPHModel.xml");
// 下面對(duì)測(cè)試圖像進(jìn)行預(yù)測(cè),predictedLabel是預(yù)測(cè)標(biāo)簽結(jié)果
//注意predict()入口參數(shù)必須為單通道灰度圖像,如果圖像類型不符,需要先進(jìn)行轉(zhuǎn)換
//predict()函數(shù)返回一個(gè)整形變量作為識(shí)別標(biāo)簽
int predictedLabel = model->predict(testSample);//加載分類器
int predictedLabel1 = model1->predict(testSample);
int predictedLabel2 = model2->predict(testSample);
// 還有一種調(diào)用方式,可以獲取結(jié)果同時(shí)得到閾值:
// 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;
通過(guò)上面的代碼進(jìn)行訓(xùn)練,訓(xùn)練使用了python。所以系統(tǒng)環(huán)境需要配置好。
在此文件中,把我們采集到的圖像,放進(jìn)去,新建一個(gè)文件夾。
之后就是把我們的at.txt也加入我們的文件。
訓(xùn)練好后,我們就得到了我們所需要的訓(xùn)練文件。
在我們打卡界面,點(diǎn)擊打卡時(shí)就是這樣的。加載訓(xùn)練好的東西。然后啟動(dòng)定時(shí)器,去獲取攝像頭信號(hào),然后對(duì)比,最終和數(shù)據(jù)庫(kù)一致就認(rèn)為打卡成功。
上面訓(xùn)練部分,其實(shí)提供的另一個(gè)工程就全部完成了。
這是我們win端界面,圓框就是我們攝像頭采集圖像顯示的位置。
我們需要在Ubuntu下把庫(kù)全部替換,這樣就能編譯過(guò)了,然后拷貝到開(kāi)發(fā)板上運(yùn)行。如下:
進(jìn)來(lái)就提示數(shù)據(jù)庫(kù)打開(kāi)失敗了,我們這個(gè)都是基于數(shù)據(jù)庫(kù),所以還是比較尷尬的,后期的話可以嘗試自己全部編譯下,然后更新吧。目前就測(cè)試,看下效果吧。
使用的硬件增加了一個(gè)攝像頭。
這是打開(kāi)攝像頭采集的樣子。
這個(gè)GIF展示了我們的人臉檢測(cè)情況。
由于沒(méi)有數(shù)據(jù)庫(kù),只能打印一些信息。當(dāng)兩個(gè)數(shù)據(jù)相等時(shí)就進(jìn)入下一步,判斷打卡了。由于沒(méi)有數(shù)據(jù)庫(kù),就展示下電腦端的效果吧。
-
開(kāi)發(fā)板
+關(guān)注
關(guān)注
25文章
4898瀏覽量
97061
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論