0.前言
重要說(shuō)明:此項(xiàng)目直接跟進(jìn)操作的話(huà)只能在Ubuntu16.04上面編譯成功!目前已經(jīng)補(bǔ)上18.04上的編譯操作。
????????本文主要跟隨B站Up主【物聯(lián)網(wǎng)小學(xué)妹】上傳的【從0到1做一個(gè)物聯(lián)網(wǎng)人臉識(shí)別考勤機(jī)項(xiàng)目!】視頻教程做一個(gè)簡(jiǎn)要筆記
視頻地址:【大廠(chǎng)敲門(mén)磚】從0到1做一個(gè)物聯(lián)網(wǎng)人臉識(shí)別考勤機(jī)項(xiàng)目?。ǜ皆创a)_嗶哩嗶哩_bilibili
?視頻對(duì)應(yīng)資源(沒(méi)必要下載,幫助不大):?
鏈接:https://pan.baidu.com/s/1rEhfDg_Yc1SMD40fGdVqhw?pwd=yjgn?
提取碼:yjgn
學(xué)習(xí)所需前置條件:
? ? ? ? 1.Linux系統(tǒng)安裝? 2.Linux操作基礎(chǔ)? 3.C++編程
我的Linux學(xué)習(xí)筆記:Linux學(xué)習(xí)筆記_Jenlibein的博客-CSDN博客
C++學(xué)習(xí)跟進(jìn)可以看這個(gè):【2023最新版C++】實(shí)戰(zhàn)項(xiàng)目教程,清華武老師帶你零基礎(chǔ)一套快速學(xué)會(huì)c++_嗶哩嗶哩_bilibili
目錄
1.安裝與配置
1.1下載
1.2安裝
1.3中文配置
2.C++程序編寫(xiě)
3.OpenCV 初次認(rèn)識(shí)?/ 安裝
3.1介紹
3.2安裝
3.3更多學(xué)習(xí)
4.OpenCV編程
4.0確保攝像頭打開(kāi)
4.1圖像采集
4.2圖像處理
4.3人臉檢測(cè)
4.4圖像截圖/圖片解碼和編碼
5.百度智能云平臺(tái)
5.1人臉庫(kù)創(chuàng)建
5.2 SDK環(huán)境搭建
5.3百度智能云平臺(tái)接入
6.數(shù)據(jù)處理
6.1Json數(shù)據(jù)解析
6.2記錄考勤時(shí)間
6.3考勤信息記錄及顯示
7.最終實(shí)現(xiàn)
8.文章結(jié)束
1.安裝與配置
1.1下載
視頻中使用的Linux發(fā)行版為Ubuntu16.04,可以在我給出的?視頻對(duì)應(yīng)資源?中下載得到。
????????但是,百度網(wǎng)盤(pán)的必須要VIP才能下載這么大的文件,不然就不知道要下載到猴年馬月了。
????????所以,我建議在國(guó)內(nèi)鏡像源中下載:ubuntu 16.04 鏡像下載(國(guó)內(nèi)開(kāi)源鏡像站)_ubuntu16.04-CSDN博客
????????按常理說(shuō),下載選擇的文件后綴應(yīng)該是【desktop-amd64.iso】,選擇好下載即可。
1.2安裝
? ? ? ? 可以參考Linux學(xué)習(xí)筆記那的三個(gè)方法
1.3中文配置
? ? ? ? 在左欄菜單選中【System Settings】
????????進(jìn)入設(shè)置菜單選中【Language Support】
????????第一次進(jìn)入會(huì)有個(gè)提示安裝的窗口,點(diǎn)確認(rèn)。
? ? ? ? 然后點(diǎn)【Install / Remove Languages...】選項(xiàng),進(jìn)入窗口后下拉找到Chinese(simplified)并勾選,然后點(diǎn)Apply,進(jìn)入下載。
? ? ? ? 回到【Language Support】窗口,然后在上列菜單中,將下面的 [? 漢語(yǔ)(中國(guó))] 拖動(dòng)到最上面位置,確保該文字由灰色?變?yōu)?em>黑色 并處于第一位 ,然后重啟電腦。
? ? ? ? 進(jìn)到中文語(yǔ)言的系統(tǒng)。
? ? ? ? 拼音設(shè)置:可以查看Linux下使用拼音的相關(guān)教程
? ? ? ??
2.C++程序編寫(xiě)
? ? ? ? B站教程中用gedit進(jìn)行創(chuàng)建文本,然后在文本里寫(xiě)C++代碼。
? ? ? ? 然后用
g++ file.cpp -o 輸出名稱(chēng)
? ? ? ? 來(lái)輸出可執(zhí)行文件
????????
? ? ? ? 用到第三方庫(kù)時(shí),編譯時(shí)要加上鏈接(例如OpenCv的highgui庫(kù))
g++ main.cpp -o main -lopencv_highgui
? ? ? ? 我認(rèn)為:還是用vscode等專(zhuān)業(yè)的IDE來(lái)編寫(xiě)代碼更好,有利于編寫(xiě)時(shí)候的視覺(jué)觀看和找bug。
? ? ? ? 編寫(xiě)時(shí)候主要用OpenCV庫(kù)
#include "opencv2/opencv.hpp"
? ? ? ? 并使用命名空間
using namespace cv;
3.OpenCV 初次認(rèn)識(shí)?/ 安裝
3.1介紹
????????OpenCV是一個(gè)開(kāi)源的計(jì)算機(jī)視覺(jué)和機(jī)器學(xué)習(xí)軟件庫(kù)其使用一系列C語(yǔ)言函數(shù)和少量C++類(lèi)實(shí)現(xiàn),內(nèi)部實(shí)現(xiàn)了很多圖像處理和計(jì)算機(jī)視覺(jué)的通用算法。
????????OpenCV可以運(yùn)行在Linux系統(tǒng)上,且其輕量、高效所以在嵌入式領(lǐng)域得到廣泛的應(yīng)用。
3.2安裝
終端中輸入命令:
sudo apt-get install libopencv-dev
3.3更多學(xué)習(xí)
官方在線(xiàn)文檔(深入學(xué)習(xí)使用):OpenCV - Open Computer Vision Library
網(wǎng)上OpenCV的教程大多數(shù)是以python作為編程語(yǔ)言,C++作為編程語(yǔ)言的教程較少。
我在B站上發(fā)現(xiàn)一個(gè)OpenCV的C++教程:2023年度最佳 Open Cv 學(xué)習(xí)教程,C++向!_嗶哩嗶哩_bilibili
當(dāng)然之后也可以通過(guò)Python學(xué)習(xí)其他的OpenCV教程。
4.OpenCV編程
4.0確保攝像頭打開(kāi)
?? ? ? ??如何確認(rèn)Linux下有無(wú)攝像頭接入:進(jìn)入dev文件夾查看有無(wú)vedio文件。
????????虛擬機(jī)內(nèi)沒(méi)有識(shí)別,需要另外設(shè)置:虛擬機(jī)設(shè)置 - USB控制器 - USB兼容性 ---> 改為USB3.0或3.1并點(diǎn)確定
然后在虛擬機(jī)主窗口 左上角菜單 - 虛擬機(jī)(M) - 可移動(dòng)設(shè)備 - 找到攝像頭設(shè)備 --->?點(diǎn)擊鏈接
如果還是不行,觀察虛擬機(jī)主窗口右下角有無(wú)對(duì)應(yīng)攝像頭的USB圖標(biāo)--->有則右鍵?- 選擇連接
4.1圖像采集
庫(kù):highgui
函數(shù):VideoCapture(攝像頭開(kāi)啟)
攝像頭設(shè)置參數(shù):
VideoCapture cap(0);
?cap.set(CV_CAP_PROP_FRAME_WIDTH, 1080);//寬度?
?cap.set(CV_CAP_PROP_FRAME_HEIGHT, 960);//高度
?cap.set(CV_CAP_PROP_FPS, 30);//幀率 幀/秒
?cap.set(CV_CAP_PROP_BRIGHTNESS, 1);//亮度 1
?cap.set(CV_CAP_PROP_CONTRAST,40);//對(duì)比度 40
?cap.set(CV_CAP_PROP_SATURATION, 50);//飽和度 50
?cap.set(CV_CAP_PROP_HUE, 50);//色調(diào) 50
?cap.set(CV_CAP_PROP_EXPOSURE, 50);//曝光 50
獲取參數(shù):
cap.get(CV_CAP_PROP_FRAME_WIDTH);
cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cap.get(CV_CAP_PROP_FPS);
cap.get(CV_CAP_PROP_BRIGHTNESS);
cap.get(CV_CAP_PROP_CONTRAST);
cap.get(CV_CAP_PROP_SATURATION);
cap.get(CV_CAP_PROP_HUE);
cap.get(CV_CAP_PROP_EXPOSURE);
庫(kù):core
函數(shù):Mat(定義圖像容器)
具體可通過(guò)代碼注釋了解:
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(){
VideoCapture cap(0); //括號(hào)內(nèi)數(shù)字代表攝像頭編號(hào),一般為0 -> 打開(kāi)編號(hào)為0的攝像頭并命名為cap
if(!cap.isOpened()){ //檢測(cè)是否成功打開(kāi)攝像頭
cout<< "Camera open failed" <<endl;
return -1;
}else{
cout<< "Camera open success" <<endl;
}
Mat ColorImage; //實(shí)例化一個(gè)Mat類(lèi)型數(shù)據(jù)(類(lèi)似于 int a)
for(;;){
cap >> ColorImage; //從相機(jī)獲取一個(gè)新的框架(拍照)
imshow("video",ColorImage); //圖片展示,引號(hào)內(nèi)為終端窗口名稱(chēng),第二個(gè)參數(shù)為顯示的具體照片
waitKey(100); //暫停100ms
}//想退出循環(huán)直接在終端中按Ctrl+C
return 0;
}
編譯要加上庫(kù),不然會(huì)報(bào)錯(cuò)?
VideoCapture位于highgui
Mat位于core
g++ main.cpp -o main -lopencv_highgui -lopencv_core
opencv讀取視頻有延遲解決方法:
????????opencv在攝像機(jī)每次獲取的新幀時(shí)候總是先把上一次讀取的幀拿出來(lái)先用,再把新幀加入緩存.
????????所以要想獲取最新的幀,一定要連續(xù)讀兩次才是當(dāng)前最新的。
? ? ? ? 也就是把 cap >> ColorImage; 重復(fù)兩行。
4.2圖像處理
庫(kù):imgproc - Image Processing
函數(shù)1:cvtColor(色彩轉(zhuǎn)換):void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0)
第一個(gè)參數(shù) src - source輸入容器;輸入圖像:8位無(wú)符號(hào),16位無(wú)符號(hào)(CV_16UC…),或單精度浮點(diǎn)。
第二個(gè)參數(shù) dst -?Destination輸出容器,輸出目標(biāo)與原圖像具有同樣的大小與類(lèi)型。
第三個(gè)參數(shù) code
????????轉(zhuǎn)換方式::CV_BGR2GRAY,CV RGB2GRAY,CY GRAY2BGR, CY GRAY2RGB
????????分別對(duì)應(yīng):1,2對(duì)應(yīng)彩轉(zhuǎn)灰 ,3,4對(duì)應(yīng)灰轉(zhuǎn)彩。
函數(shù)2:equalizeHist(直方圖均衡):void equalizeHist (InputArray src, OutputArray dst)
第一個(gè)參數(shù),輸入8位單通道的圖像;
第二個(gè)參數(shù),輸出目標(biāo)圖像,與原圖像具有同樣的大小與類(lèi)型;
上面兩個(gè)函數(shù)處理圖像后可以利于人臉檢測(cè)運(yùn)行。
函數(shù)3:調(diào)整大小(此步驟非必要):
resize( InputArray src, OutputArray dst, Size(width, height), code );
code:
INTER_AREA 使用像素面積關(guān)系進(jìn)行重采樣。這最適合減小圖像的大小(縮小)。當(dāng)用于放大圖像時(shí),它使用INTER_NEAREST方法。
INTER_CUBIC 這使用雙三次插值來(lái)調(diào)整圖像大小。在調(diào)整大小和插入新像素時(shí),此方法作用于圖像的4x4相鄰像素。然后取16個(gè)像素的權(quán)重平均值來(lái)創(chuàng)建新的插值像素。
INTER LINEAR:這個(gè)方法有點(diǎn)類(lèi)似于INTER CUBI插值。與不同INTER CUBIC的是這使用2x2相像素來(lái)獲得插值像素的加權(quán)平均值。
INTER_NEAREST:該INTER_NEAREST方法使用最近鄰概念進(jìn)行插值。這是最簡(jiǎn)單的方法之一,僅使用圖像中的一個(gè)相鄰像素進(jìn)行插值。
代碼實(shí)現(xiàn)(4.1原有代碼為基礎(chǔ)):
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(){
VideoCapture cap(0);
if(!cap.isOpened()){
cout<< "Camera open failed" <<endl;
return -1;
}else{
cout<< "Camera open success" <<endl;
}
Mat ColorImage;
Mat GrayImage; //創(chuàng)建灰度圖容器
for(;;){
cap >> ColorImage;
cvtColor(ColorImage, GrayImage, CV_BGR2GRAY); //轉(zhuǎn)為灰度圖
equalizeHist(GrayImage, GrayImage); //均衡化;輸入輸出容器一致,可以省一些內(nèi)存。
imshow("video",GrayImage);
waitKey(100);
}
return 0;
}
編譯:
g++ main.cpp -o main -lopencv_highgui -lopencv_core -lopencv_imgproc
4.3人臉檢測(cè)
庫(kù):objdetect - Object Detection
類(lèi):CascadeClassifier(級(jí)聯(lián)分類(lèi)器)?需要先導(dǎo)入一個(gè)后綴名為.xml的分類(lèi)器文件,它是前人已經(jīng)創(chuàng)建好的分類(lèi)器,我們可以直接使用
OpenCV安裝時(shí)自帶的一些訓(xùn)練好的模型文件位置:/usr/share/opencv/haarcascades/
函數(shù)1:CascadeClassifier :: detectMultiScale
功能:從輸入的圖片中檢測(cè)不同尺寸的物體(載入人臉識(shí)別模型后這個(gè)物體就是人臉),并返回一個(gè)矩形組成的列表(矩形框起來(lái)的就是臉)。
void CascadeClassifier:: detectlultiScale(const Mat& image,?vector<Rect>& objects, double scaleFactor=1.1, int?minNeighbors=3, int flags=0, Size minSize=Size(), Size maxSize=Size())
第一個(gè)參數(shù):輸入目標(biāo),要檢測(cè)的圖像
第二個(gè)參數(shù):輸出目標(biāo),存儲(chǔ)矩形框的容器
其他參數(shù):有默認(rèn)值,使用默認(rèn)值即可
庫(kù):core
方法:rectangle(在圖形上畫(huà)矩形)
void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness=1, int lineType=8, int shift=0 )?
第一個(gè)參數(shù):要畫(huà)的圖像
第二個(gè)參數(shù):輸入的矩形
第三個(gè)參數(shù):矩形顏色
其他參數(shù):默認(rèn)值即可
代碼實(shí)現(xiàn)(基于以前代碼增加):
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(){
VideoCapture cap(0);
if(!cap.isOpened()){
cout<< "Camera open failed" <<endl;
return -1;
}else{
cout<< "Camera open success" <<endl;
}
實(shí)例化一個(gè)級(jí)聯(lián)分類(lèi)器,此處加載opencv現(xiàn)成的模型
CascadeClassifier Classifier("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml");
定義一個(gè)儲(chǔ)存所輸出矩形的容器
vector<Rect> AllFace;
Mat ColorImage;
Mat GrayImage;
for(;;){
cap >> ColorImage;
cvtColor(ColorImage, GrayImage, CV_BGR2GRAY);
equalizeHist(GrayImage, GrayImage);
人臉檢測(cè)并輸出;
Classifier.detectMultiScale(GrayImage, AllFace);
if( AllFace.size()!=0 ){ //判斷是否有臉,避免程序出錯(cuò)
圖像上畫(huà)出矩形
rectangle(GrayImage, AllFace[0], Scalar(255,0,0));
}
imshow("video",GrayImage);
waitKey(100);
}
return 0;
}
編譯:
g++ main.cpp -o main -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_objdetect
4.4圖像截圖/圖片解碼和編碼
庫(kù):highgui
函數(shù)1:imdecode(函數(shù)解碼)
函數(shù)2:imencode(函數(shù)編碼)
bool imencode(const string& ext, InputArray img, vectoreuchar>& buf, const vector<int> & params=vector <int>0)
第一個(gè)參數(shù):輸出后所希望獲得的格式
第二個(gè)參數(shù):輸入的圖像
第三個(gè)參數(shù):存儲(chǔ)編碼完圖像的容器
其他參數(shù):保持默認(rèn)
代碼實(shí)現(xiàn)(基于以前代碼增加):
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(){
VideoCapture cap(0);
if(!cap.isOpened()){
cout<< "Camera open failed" <<endl;
return -1;
}else{
cout<< "Camera open success" <<endl;
}
CascadeClassifier Classifier("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml");
vector<Rect> AllFace;
Mat ColorImage;
Mat GrayImage;
創(chuàng)建人臉截圖容器
Mat MatFace;
創(chuàng)建用于存儲(chǔ)編碼完圖像的容器
vector<uchar> JpgFace;
for(;;){
cap >> ColorImage;
cvtColor(ColorImage, GrayImage, CV_BGR2GRAY);
equalizeHist(GrayImage, GrayImage);
Classifier.detectMultiScale(GrayImage, AllFace);
if( AllFace.size()!=0 ){
rectangle(GrayImage, AllFace[0], Scalar(255,0,0));
用矩形截出人臉(相當(dāng)于截圖)
MatFace = GrayImage(AllFace[0]);
編碼
imencode(".jpg", MatFace, JpgFace);
}
imshow("video",GrayImage);
waitKey(100);
}
return 0;
}
5.百度智能云平臺(tái)
5.1人臉庫(kù)創(chuàng)建
人臉識(shí)別區(qū):人臉識(shí)別_人臉識(shí)別_準(zhǔn)確率99.99%_免費(fèi)試用-百度AI開(kāi)放平臺(tái) (baidu.com)
進(jìn)入網(wǎng)站點(diǎn)立即使用,之后先登錄,登錄完后進(jìn)入默認(rèn)界面。
此時(shí)退出該登錄主頁(yè),重新進(jìn)入人臉識(shí)別區(qū)主頁(yè),再次點(diǎn)擊立即使用。?
之后點(diǎn)如圖處
進(jìn)入頁(yè)面后,領(lǐng)取人臉識(shí)別接口免費(fèi)資源
下一步如圖進(jìn)入-可視化人臉庫(kù)
點(diǎn)【新建組】
點(diǎn)擊用戶(hù)組ID
點(diǎn)擊新建用戶(hù),添加你自己的照片和其他人的照片,比如某些明星的正臉照。
5.2 SDK環(huán)境搭建
SDK開(kāi)發(fā)包下載:C++-SDK - 人臉識(shí)別_人臉檢測(cè)_人臉對(duì)比_人臉?biāo)阉鱛活體檢測(cè)_百度智能云 (baidu.com)
將SDK壓縮包解壓縮后的文件夾放到Ubuntu里面
SDK包相關(guān)依賴(lài)下載:安裝依賴(lài)庫(kù)libcurl(需要支持https), openssl,jsoncpp(>1.6.2版本,0.x版本將不被支持)。
libcurl(網(wǎng)絡(luò)通信的協(xié)議庫(kù))
openssl(網(wǎng)絡(luò)通信加密)
jsoncpp(提取信息)
安裝:
sudo apt-get install libcurl4-openssl-dev
sudo apt-get install openssl
sudo apt-get install libjsoncpp-dev
sudo apt-get install libssl-dev
檢測(cè)是否安裝成功(install ok字樣,同時(shí)觀察版本是否合適)
dpkg -s libcurl4-openssl-dev
dpkg -s openssl
dpkg -s libjsoncpp-dev
sudo apt-get install libssl-dev
編譯(文件庫(kù)支持C++11版本,同時(shí)需要加上第三方庫(kù))
將cpp文件放置于SDK文件夾里面,方便編譯時(shí)找到頭文件
編譯文件時(shí)候在最后加入 ( -std=c++11 -lcurl -lcrypto -ljsoncpp)
g++ main.cpp -o main -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_objdetect -std=c++11 -lcurl -lcrypto -ljsoncpp
修改 base.h 和 http.h 文件中json頭文件的目錄位置
????????#include <jsoncpp/json/json.h>
(未解決)評(píng)論區(qū)反應(yīng)face.h的search函數(shù)出現(xiàn)問(wèn)題
編寫(xiě)
加入相關(guān)頭文件和命名空間
????????#include "face.h"
? ? ? ? using namespace aip;
5.3百度智能云平臺(tái)接入
百度提供代碼:
// 設(shè)置APPID/AK/SK std::string app_id = "你的 App ID"; std::string api_key = "你的 Api key"; std::string secret_key = "你的 Secret Key"; aip::Face client(app_id, api_key, secret_key);
?回到 百度智能云平臺(tái)-應(yīng)用列表
查看相應(yīng)參數(shù),寫(xiě)到所給代碼對(duì)應(yīng)位置
函數(shù):(注意,視頻所給的函數(shù)是search,但官方文檔已經(jīng)更新成search_v3):
// 調(diào)用人臉?biāo)阉?result = client.face_search_v3(image, image_type, group_id_list, aip::null);
// 帶參數(shù)調(diào)用人臉?biāo)阉?result = client.face_search_v3(image, image_type, group_id_list, options);
//此處options填你最終儲(chǔ)存容器
// 如果有可選參數(shù)
std::map<std::string, std::string> options;
options["match_threshold"] = "70";
options["quality_control"] = "NORMAL";
options["liveness_control"] = "LOW";
options["user_id"] = "233451";
options["max_user_num"] = "3";
image :圖片信息(總數(shù)據(jù)大小應(yīng)小于10M)
image_type:圖片類(lèi)型?BASE64:(圖片大小不超過(guò)2M),URL:圖片的 URL地址,FACE_TOKEN: 人臉圖片的唯一標(biāo)識(shí)。
group_id_list:從指定的group中進(jìn)行查找 用逗號(hào)分隔,上限10個(gè)
這里我們使用base64編碼:
base64_encode(const char* bytes_to_encode, unsigned int int_len);
接收返回?cái)?shù)據(jù):
百度提供代碼(最終獲取的容器):
Json::Value result;
?返回?cái)?shù)據(jù)示例:
{ "face_token": "fid", "user_list": [ { "group_id" : "test1", "user_id": "u333333", "user_info": "Test User", "score": 99.3 } ] }
代碼實(shí)現(xiàn)(基于前面寫(xiě)的代碼修改):
#include <iostream>
#include "opencv2/opencv.hpp"
#include "face.h" //庫(kù)
using namespace std;
using namespace cv;
using namespace aip; //命名空間
int main(){
VideoCapture cap(0);
if(!cap.isOpened()){
cout<< "Camera open failed" <<endl;
return -1;
}else{
cout<< "Camera open success" <<endl;
}
CascadeClassifier Classifier("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml");
//寫(xiě)上對(duì)參數(shù)到所給代碼
aip::Face client("******", "******", "******");
vector<Rect> AllFace;
Mat ColorImage;
Mat GrayImage;
Mat MatFace;
vector<uchar> JpgFace;
//定義轉(zhuǎn)換完成base64格式的圖片
string Base64Face;
//定義獲取返回結(jié)果的容器
Json::Value result;
for(;;){
cap >> ColorImage;
cvtColor(ColorImage, GrayImage, CV_BGR2GRAY);
equalizeHist(GrayImage, GrayImage);
Classifier.detectMultiScale(GrayImage, AllFace);
if( AllFace.size()!=0 ){
rectangle(GrayImage, AllFace[0], Scalar(255,0,0));
MatFace = GrayImage(AllFace[0]);
imencode(".jpg", MatFace, JpgFace);
//編碼成base64
Base64Face = base64_encode((char *)JpgFace.data(), JpgFace.size());
//傳輸?shù)桨俣?,獲取返回結(jié)果
result = client.face_search_v3(Base64Face, "BASE64", "Teaching", result);
//打印結(jié)果
cout<<result<<endl;
}
imshow("video",GrayImage);
waitKey(100);
}
return 0;
}
編譯:
g++ main.cpp -o main -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_objdetect -std=c++11 -lcurl -lcrypto -ljsoncpp
運(yùn)行后成功獲取返回信息:
6.數(shù)據(jù)處理
6.1Json數(shù)據(jù)解析
? ? ? ? 觀察百度所給的返回?cái)?shù)據(jù)形式
? ? ? ? 我們要獲取的目標(biāo)是人臉?biāo)鶎?duì)應(yīng)的人的信息,所以我們只需要從數(shù)據(jù)中提取特定信息
? ? ? ? 1.判斷是否檢測(cè)到人臉
????????????????opencv所給模型不太精確,會(huì)將疑似為人臉的物體也上傳。百度會(huì)進(jìn)行第二次檢測(cè)是否有人臉。如果返回為空則不打印信息
? ? ? ? 2.判斷人臉匹配得分
? ? ? ? ? ? ? ? 如果匹配得分很低說(shuō)明只是有人臉,百度會(huì)返回得分最高的人,即使得分很低,所以結(jié)果會(huì)不準(zhǔn)確。所以我們要控制得分在80以上
? ? ? ? 3.只返回人臉?biāo)ヅ涞娜说拿?/p>
? ? ? ? ? ? ? ? 其他信息對(duì)我們獲取人的身份信息沒(méi)有什么作用,我們只需要獲取匹配人的名字。
代碼實(shí)現(xiàn)(基于前面寫(xiě)的代碼修改):
#include <iostream>
#include "opencv2/opencv.hpp"
#include "face.h"
using namespace std;
using namespace cv;
using namespace aip;
int main(){
VideoCapture cap(0);
if(!cap.isOpened()){
cout<< "Camera open failed" <<endl;
return -1;
}else{
cout<< "Camera open success" <<endl;
}
CascadeClassifier Classifier("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml");
aip::Face client("******", "lNW******5EF", "XItO******FzS");
vector<Rect> AllFace;
Mat ColorImage;
Mat GrayImage;
Mat MatFace;
vector<uchar> JpgFace;
string Base64Face;
Json::Value result;
for(;;){
cap >> ColorImage;
cvtColor(ColorImage, GrayImage, CV_BGR2GRAY);
equalizeHist(GrayImage, GrayImage);
Classifier.detectMultiScale(GrayImage, AllFace);
if( AllFace.size()!=0 ){
rectangle(GrayImage, AllFace[0], Scalar(255,0,0));
MatFace = GrayImage(AllFace[0]);
imencode(".jpg", MatFace, JpgFace);
Base64Face = base64_encode((char *)JpgFace.data(), JpgFace.size());
result = client.face_search_v3(Base64Face, "BASE64", "Teaching", result);
if( !result["result"].isNull() )//判斷是否檢測(cè)到人臉(opencv所給模型不一定準(zhǔn)確,百度會(huì)進(jìn)行第二次檢測(cè)是否有人臉)
{
if( result["result"]["user_list"][0]["score"].asInt() > 80 )//判斷人臉匹配得分是否大于80
{
cout<<result["result"]["user_list"][0]["user_id"]<<endl;//輸出人名
}
}
}
imshow("video",GrayImage);
waitKey(500);
}
return 0;
}
編譯運(yùn)行,成功獲取打印對(duì)應(yīng)信息。
6.2記錄考勤時(shí)間
時(shí)間容器:time_sec?
時(shí)間獲取 (從1970.1.1 0:0:0到現(xiàn)在的秒數(shù))?? time(NULL);
時(shí)間轉(zhuǎn)換(轉(zhuǎn)換為正常時(shí)間)?ctime()
代碼實(shí)現(xiàn):
#include <iostream>
#include "opencv2/opencv.hpp"
#include "face.h"
using namespace std;
using namespace cv;
using namespace aip;
int main(){
VideoCapture cap(0);
if(!cap.isOpened()){
cout<< "Camera open failed" <<endl;
return -1;
}else{
cout<< "Camera open success" <<endl;
}
CascadeClassifier Classifier("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml");
aip::Face client("******", "lNW******5EF", "XItO******FzS");
vector<Rect> AllFace;
Mat ColorImage;
Mat GrayImage;
Mat MatFace;
vector<uchar> JpgFace;
string Base64Face;
Json::Value result;
//時(shí)間容器
time_t sec;
for(;;){
cap >> ColorImage;
cvtColor(ColorImage, GrayImage, CV_BGR2GRAY);
equalizeHist(GrayImage, GrayImage);
Classifier.detectMultiScale(GrayImage, AllFace);
if( AllFace.size()!=0 ){
rectangle(GrayImage, AllFace[0], Scalar(255,0,0));
MatFace = GrayImage(AllFace[0]);
imencode(".jpg", MatFace, JpgFace);
Base64Face = base64_encode((char *)JpgFace.data(), JpgFace.size());
result = client.face_search_v3(Base64Face, "BASE64", "Teaching", result);
if( !result["result"].isNull() )
{
if( result["result"]["user_list"][0]["score"].asInt() > 80 )
{
cout<<result["result"]["user_list"][0]["user_id"]<<endl;
//時(shí)間獲取(從1970.1.1 0:0:0到現(xiàn)在的秒數(shù))
sec = time(NULL);
//ctime()時(shí)間轉(zhuǎn)換(轉(zhuǎn)換為正常時(shí)間)
//輸出時(shí)間信息
cout<<ctime(&sec)<<endl;
}
}
}
imshow("video",GrayImage);
waitKey(500);
}
return 0;
}
編譯運(yùn)行,成功返回時(shí)間信息
6.3考勤信息記錄及顯示
記錄考勤信息:運(yùn)行程序時(shí)將信息定向到文本文件中
./main >> log.txt
問(wèn)題:這樣執(zhí)行就只會(huì)將信息存在log.txt中,不再?gòu)慕K端窗口顯示.
解決:我們可以從攝像頭窗口的人臉識(shí)別框上直接顯示人名和時(shí)間
庫(kù):core
函數(shù):putText (圖像上寫(xiě)字)
void putText(Mat& img, const string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness=1, int?lineType=8, bool bottomLeftOrigin=false )?
第一個(gè)參數(shù):要寫(xiě)字的圖像
第二個(gè)參數(shù):要寫(xiě)的字
第三個(gè)參數(shù):字在圖像上的坐標(biāo)
第四個(gè)參數(shù):圖像的字體(具體看官方文檔)
第五個(gè)參數(shù):字的大小
第六個(gè)參數(shù):字的顏色
代碼實(shí)現(xiàn)(在原有代碼下加入)
編譯運(yùn)行:
左上角出現(xiàn)字
7.最終實(shí)現(xiàn)
虛擬機(jī)記得改攝像頭兼容性!?。。。?!
文件:
代碼:
#include <iostream>
#include "opencv2/opencv.hpp"
#include "face.h"
using namespace std;
using namespace cv;
using namespace aip;
int main(){
VideoCapture cap(0);
if(!cap.isOpened()){
cout<< "Camera open failed" <<endl;
return -1;
}else{
cout<< "Camera open success" <<endl;
}
CascadeClassifier Classifier("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml");
aip::Face client("4******8", "lN************EF", "XIt******8FzS");
vector<Rect> AllFace;
Mat ColorImage;
Mat GrayImage;
Mat MatFace;
vector<uchar> JpgFace;
string Base64Face;
Json::Value result;
time_t sec;
for(;;){
cap >> ColorImage;
cvtColor(ColorImage, GrayImage, CV_BGR2GRAY);
equalizeHist(GrayImage, GrayImage);
Classifier.detectMultiScale(GrayImage, AllFace);
if( AllFace.size()!=0 ){
rectangle(GrayImage, AllFace[0], Scalar(255,0,0));
MatFace = GrayImage(AllFace[0]);
imencode(".jpg", MatFace, JpgFace);
Base64Face = base64_encode((char *)JpgFace.data(), JpgFace.size());
result = client.face_search_v3(Base64Face, "BASE64", "Teaching", result);
if( !result["result"].isNull() )
{
if( result["result"]["user_list"][0]["score"].asInt() > 80 )
{
cout<<result["result"]["user_list"][0]["user_id"]<<endl;
sec = time(NULL);
cout<<ctime(&sec)<<endl;
putText(GrayImage, result["result"]["user_list"][0]["user_id"].asString(), Point(0,50), FONT_HERSHEY_SIMPLEX, 1, Scalar(255,255,255));
putText(GrayImage,ctime(&sec), Point(0,100), FONT_HERSHEY_SIMPLEX, 1, Scalar(255,255,255));
}
}
}
imshow("video",GrayImage);
waitKey(2);
}
return 0;
}
安裝:
opencv:
sudo apt-get install libopencv-dev
百度云相關(guān)支持:
sudo apt-get install libcurl4-openssl-dev
sudo apt-get install openssl
sudo apt-get install libjsoncpp-dev
sudo apt-get install libssl-dev
編譯:
g++ main.cpp -o main -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_objdetect -std=c++11 -lcurl -lcrypto -ljsoncpp
18.04:
g++ main.cpp -o main -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_objdetect -std=c++11 -lcurl -lcrypto -ljsoncpp -lopencv_imgcodecs -lopencv_videoio
運(yùn)行:
./main >> log.txt
一切正常(我把我的API隱藏了,所以文章中的代碼無(wú)法直接運(yùn)行,需要加上你的API)
8.文章結(jié)束
? ? ? ? 感謝大家觀看!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-855569.html
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-855569.html
到了這里,關(guān)于做一個(gè)人臉識(shí)別考勤機(jī)項(xiàng)目(利用OpenCV)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!