C++ DNN Opencv3.4 实现人脸计数和人脸检测
前言
OpenCV 3.3正式發(fā)布后,對(duì)深度學(xué)習(xí)(dnn模塊)提供了更好的支持,dnn模塊目前支持Caffe、TensorFlow、Torch、PyTorch等深度學(xué)習(xí)框架。
另外,新版本中使用預(yù)訓(xùn)練深度學(xué)習(xí)模型的API同時(shí)兼容C++和Python,讓系列操作變得非常簡(jiǎn)便
- 從硬盤加載模型;
- 對(duì)輸入圖像進(jìn)行預(yù)處理;
- 將圖像輸入網(wǎng)絡(luò),獲取輸出的分類。
當(dāng)然,我們不能、也不該用OpenCV訓(xùn)練深度學(xué)習(xí)模型,但這個(gè)新版本讓我們能把用深度學(xué)習(xí)框架訓(xùn)練好了的模型拿來,高效地用在OpenCV之中。
在很久很久以前,用Opencv2.4x跟Opencv3.0進(jìn)行人臉檢測(cè)的時(shí)候,都是基于HAAR級(jí)聯(lián),但是我測(cè)試過HAAR級(jí)聯(lián),明顯不太準(zhǔn),而且速度慢。但是現(xiàn)在2020年啦,深度學(xué)習(xí)的快速發(fā)展,使人臉檢測(cè) 越來越精準(zhǔn),在Opencv4發(fā)布以來,官方支持的人臉檢測(cè)方法已經(jīng)轉(zhuǎn)換為支持深度學(xué)習(xí)的快準(zhǔn)狠的方法了,就連HAAR級(jí)聯(lián)訓(xùn)練的工具都在Opencv4中除名了,其實(shí)已經(jīng)有了支持深度學(xué)習(xí)的人臉檢測(cè)算法,并且準(zhǔn)確率和速度都比HAAR好,那再學(xué)HAAR級(jí)聯(lián)無疑是浪費(fèi)時(shí)間和精力了,要學(xué)會(huì)跟著時(shí)代的步伐嘛,所以與時(shí)俱進(jìn)很重要的。
注意:本文不涉及任何原理,只講具體的應(yīng)用。
一、下載模型文件
在OpenCV的\sources\samples\dnn\face_detector目錄下,有一個(gè)download_weights.py腳本文件,首先運(yùn)行一下,下載模型文件。下載的模型文件分別為:
Caffe模型:
res10_300x300_ssd_iter_140000_fp16.caffemodel
deploy.prototxt
tensorflow模型:
opencv_face_detector_uint8.pb
opencv_face_detector.pbtxt
pb文件的能夠保存tensorflow計(jì)算圖中的操作節(jié)點(diǎn)以及對(duì)應(yīng)的各張量,方便我們?nèi)蘸笾苯诱{(diào)用之前已經(jīng)訓(xùn)練好的計(jì)算圖。
其中tensorflow的模型OpenCV官方對(duì)它進(jìn)行了量化處理,大小只有2MB左右,非常適合在各種場(chǎng)景下使用。
如果沒有安裝python,我將這幾個(gè)模型文件上傳到了網(wǎng)盤,直接下載下來就可以了。
鏈接:https://pan.baidu.com/s/19XUTKXBriInd9goHWBwLSg?
提取碼:fye8
二、演示代碼
1.讀入模型文件
String modelDesc = "D:/VC projects/dnn_face_detection-model/opencv_face_detector.pbtxt"; String modelBinary = "D:/VC projects/dnn_face_detection-model/opencv_face_detector_uint8.pb";- 1
- 2
2.初始化網(wǎng)絡(luò),讀入權(quán)重和網(wǎng)絡(luò)結(jié)構(gòu),調(diào)用cv::dnn對(duì)應(yīng)的后端設(shè)置函數(shù)
dnn::Net net = readNetFromTensorflow(modelBinary, modelDesc); net.setPreferableBackend(DNN_BACKEND_OPENCV); net.setPreferableTarget(DNN_TARGET_CPU);- 1
- 2
- 3
這樣子程序再運(yùn)行dnn計(jì)算時(shí),用CPU運(yùn)行。
當(dāng)然也可以用GPU加速:
- 1
- 2
- 3
3.對(duì)輸入數(shù)據(jù)進(jìn)行調(diào)整。
Mat inputBlob = blobFromImage(frame, inScaleFactor, Size(inWidth, inHeight), meanVal, false, false);- 1
4.輸入、輸出
net.setInput(inputBlob, "data"); //detection返回值標(biāo)簽、置信度、目標(biāo)位置的4個(gè)坐標(biāo)信息[xmin ymin xmax ymax] Mat detection = net.forward("detection_out");- 1
- 2
- 3
完整代碼:
#include <opencv2/dnn.hpp> #include <opencv2/opencv.hpp>using namespace cv; using namespace cv::dnn;#include <iostream> #include <cstdio> using namespace std;const size_t inWidth = 300; const size_t inHeight = 300; const double inScaleFactor = 1.0; //為了減去平均值(mean):為了消除同一場(chǎng)景下不同光照的圖片,對(duì)我們最終的分類或者神經(jīng)網(wǎng)絡(luò)的影響,我們常常對(duì)圖片的R、G、B通道的像素求一個(gè)平均值,然后將每個(gè)像素值減去我們的平均值,這樣就可以得到像素之間的相對(duì)值,就可以排除光照的影響。 const Scalar meanVal(104.0, 177.0, 123.0); const float confidenceThreshold = 0.7; void face_detect_dnn(); void mtcnn_demo(); int main(int argc, char** argv) {face_detect_dnn();waitKey(0);return 0; } void face_detect_dnn() {//讀入模型路徑//String modelDesc = "D:/VC projects/dnn_face_detection-model/deploy.prototxt";//String modelBinary = "D:/VC projects/dnn_face_detection-model/res10_300x300_ssd_iter_140000_fp16.caffemodel";String modelDesc = "D:/VC projects/dnn_face_detection-model/opencv_face_detector.pbtxt";String modelBinary = "D:/VC projects/dnn_face_detection-model/opencv_face_detector_uint8.pb";//初始化網(wǎng)絡(luò)//dnn::Net net = readNetFromCaffe(modelDesc, modelBinary);dnn::Net net = readNetFromTensorflow(modelBinary, modelDesc);net.setPreferableBackend(DNN_BACKEND_OPENCV);net.setPreferableTarget(DNN_TARGET_CPU);if (net.empty()) {printf("could not load net...\n");return;}//打開攝像頭//VideoCapture capture("D:/images/video/Boogie_Up.mp4");VideoCapture capture(0);if (!capture.isOpened()) {printf("Could not load camera...\n");return;}Mat frame;int count = 0;while (capture.read(frame)) {//用于返回從操作系統(tǒng)啟動(dòng)到當(dāng)前所經(jīng)的計(jì)時(shí)周期數(shù)int64 start = getTickCount();if (frame.empty()) break;//水平鏡像調(diào)整//flip(frame, frame, 1);imshow("input", frame);if (frame.channels() == 4) cvtColor(frame, frame, COLOR_BGRA2BGR);//輸入數(shù)據(jù)調(diào)整/*深度學(xué)習(xí)或圖片分類的預(yù)處理blobFromImage1.整體像素值減去平均值(mean)2.通過縮放系數(shù)(scalefactor)對(duì)圖片像素值進(jìn)行縮放*/Mat inputBlob = blobFromImage(frame, inScaleFactor, Size(inWidth, inHeight), meanVal, false, false);net.setInput(inputBlob, "data");//人臉檢測(cè)Mat detection = net.forward("detection_out");//detection返回值標(biāo)簽、置信度、目標(biāo)位置的4個(gè)坐標(biāo)信息[xmin ymin xmax ymax]vector<double> layersTimings;//用于返回CPU的頻率,也就是一秒內(nèi)重復(fù)的次數(shù)//1000 *總次數(shù)/一秒內(nèi)重復(fù)的次數(shù)= 時(shí)間(ms)double freq = getTickFrequency() / 1000;double time = net.getPerfProfile(layersTimings) / freq;Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());ostringstream ss;for (int i = 0; i < detectionMat.rows; ++i) {//置信度0-1之間float confidence = detectionMat.at<float>(i, 2);if (confidence > confidenceThreshold) {count++;//坐標(biāo)int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3)*frame.cols);int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * frame.rows);int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * frame.cols);int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * frame.rows);//畫框Rect object((int)xLeftBottom, (int)yLeftBottom,(int)(xRightTop - xLeftBottom),(int)(yRightTop - yLeftBottom));rectangle(frame, object, Scalar(0, 255, 0));ss << confidence;//添加標(biāo)簽String conf(ss.str());String label = "Face: " + conf;int baseLine = 0;Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);rectangle(frame, Rect(Point(xLeftBottom, yLeftBottom - labelSize.height),Size(labelSize.width, labelSize.height + baseLine)),Scalar(255, 255, 255), FILLED);putText(frame, label, Point(xLeftBottom, yLeftBottom),FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0));}}float fps = getTickFrequency() / (getTickCount() - start);ss.str("");ss << "FPS:" << fps << ";inference time: " << time << " ms";putText(frame, ss.str(), Point(20, 20), 0, 0.75, Scalar(0, 0, 255), 2, 8);imshow("dnn_face_detect", frame);if (waitKey(1) >= 0) break;}printf("total face: %d\n", count); }總結(jié)
以上是生活随笔為你收集整理的C++ DNN Opencv3.4 实现人脸计数和人脸检测的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python http 返回json中文
- 下一篇: QT5快速转换路径(/斜杠与\反斜杠转换