Opencv 深度学习识别性别和检测年龄
目錄
1基于CNN的性別分類建模原理
1.1 人臉識別
1.2 性別預測
1.3 年齡預測
1.4 結果
2 代碼
參考
本教程中,我們將討論應用于面部的深層學習的有趣應用。我們將估計年齡,并從單個圖像中找出該人的性別。模型由GilLevi和TalHassner訓練(https://talhassner.github.io/home/publication/2015_CVPR)。本文介紹了如何在OpenCV中使用該模型的步驟說明。Opencv版本3.4.3以上。代碼教程代碼可以分為四個部分:
1基于CNN的性別分類建模原理
作者使用非常簡單的卷積神經網絡結構,類似于Caffenet和Alexnet。網絡使用3個卷積層、2個全連接層和一個最終的輸出層。下面給出了這些層的細節。COV1:第一卷積層具有96個內核大小7的節點。COV2:第二個卷積層Conv層具有256個具有內核大小5的節點。CONV3:第三個CONV層具有384個內核大小為3的節點。兩個完全連接的層各自具有512個節點。
訓練數據來源:https://talhassner.github.io/home/projects/Adience/Adience-data.html
檢測程序主要有四塊:檢測人臉檢測、性別檢測、年齡顯示和輸出。
1.1 人臉識別
我們將使用人臉檢測器(tensorflow模型)進行人臉檢測。該模型很簡單,即使在CPU上也是相當快的。詳細見論文:
https://arxiv.org/pdf/1502.00046.pdf
1.2 性別預測
將性別預測設定為一個分類問題。性別預測網絡(caffe模型)中的輸出層類型為兩類,2個節點表示“男性”和“女性”兩類。以這兩個輸出的最大值作為最終的性別。
1.3 年齡預測
理想情況下,年齡預測應該作為一個回歸問題來處理。然而通過回歸準確估計年齡是很有挑戰性的。即使是人類也無法通過觀察一個人來準確預測年齡。但是我們能夠知道他們是20多歲還是30多歲。由于這個原因,把這個問題描述為一個分類問題是明智的,因為我們試圖估計這個人所處的年齡組。例如,0-2范圍內的年齡是一個類,4-6是另一個類,依此類推。因此數據集分為以下8個年齡組[(0-2)、(4-6)、(8-12)、(15-20)、(25-32)、(38-43)、(48-53)、(60-100)]。因此,年齡預測網絡在最后一層有8個節點,表示所述年齡范圍。
應該記住,從一幅圖像中預測年齡并不是一個很容易解決的問題,因為感知到的年齡取決于許多因素,而同齡的人在世界各地可能看起來很不一樣。而且,人們非常努力地隱藏他們的真實年齡!
我們加載年齡網絡(caffe模型)并使用前向通道獲得輸出。由于網絡結構類似于性別網絡,所以我們可以從所有輸出中提取出最大值來得到預測的年齡組
1.4 結果
盡管性別預測網絡表現良好,但年齡預測網絡仍未達到我們的預期。所以添加人臉對齊算法或者數據樣本很多時候,可以通過回歸的模型來檢測。但是性別人臉檢測還是很準確的。
2 代碼
在VS2017下運行了C++代碼,其中OpenCV版本至少要3.4.5以上。不然模型讀取會有問題。三個模型文件太大,見下載鏈接:
https://download.csdn.net/download/luohenyj/10993309
https://github.com/luohenyueji/OpenCV-Practical-Exercise
如果沒有積分(系統自動設定資源分數)看看參考鏈接。我搬運過來的,大修改沒有。
其中tensorflow和caffe模型都可以用opencv中的readnet函數讀取,流程很簡單。看看代碼就會。
代碼提供了C++和Python版本,但是python版本沒有運行,原因opencv版本太低,不想升級。代碼都有詳細的注釋。
C++版本:
#include <tuple>#include <iostream>#include <opencv2/opencv.hpp>#include <opencv2/dnn.hpp>#include <iterator>using namespace cv;using namespace cv::dnn;using namespace std;/*** @brief Get the Face Box object 人臉定位** @param net 人臉檢測網絡* @param frame 檢測圖像* @param conf_threshold 閾值* @return tuple<Mat, vector<vector<int>>> 元組容器,可返回多個值*/tuple<Mat, vector<vector<int>>> getFaceBox(Net net, Mat &frame, double conf_threshold){//圖像復制Mat frameOpenCVDNN = frame.clone();int frameHeight = frameOpenCVDNN.rows;int frameWidth = frameOpenCVDNN.cols;//縮放尺寸double inScaleFactor = 1.0;//檢測圖大小Size size = Size(300, 300);// std::vector<int> meanVal = {104, 117, 123};Scalar meanVal = Scalar(104, 117, 123);cv::Mat inputBlob;inputBlob = cv::dnn::blobFromImage(frameOpenCVDNN, inScaleFactor, size, meanVal, true, false);net.setInput(inputBlob, "data");//四維矩陣輸出cv::Mat detection = net.forward("detection_out");//提取結果信息cv::Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());vector<vector<int>> bboxes;for (int i = 0; i < detectionMat.rows; i++){//預測概率float confidence = detectionMat.at<float>(i, 2);if (confidence > conf_threshold){//左上角點,坐標被歸一化int x1 = static_cast<int>(detectionMat.at<float>(i, 3) * frameWidth);int y1 = static_cast<int>(detectionMat.at<float>(i, 4) * frameHeight);//右下角角點,坐標被歸一化int x2 = static_cast<int>(detectionMat.at<float>(i, 5) * frameWidth);int y2 = static_cast<int>(detectionMat.at<float>(i, 6) * frameHeight);vector<int> box = { x1, y1, x2, y2 };//人臉坐標bboxes.push_back(box);//圖像框選cv::rectangle(frameOpenCVDNN, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 255, 0), 2, 4);}}return make_tuple(frameOpenCVDNN, bboxes);}int main(void){//人臉模型string faceProto = "model/opencv_face_detector.pbtxt";string faceModel = "model/opencv_face_detector_uint8.pb";//年齡模型string ageProto = "model/age_deploy.prototxt";string ageModel = "model/age_net.caffemodel";//性別模型string genderProto = "model/gender_deploy.prototxt";string genderModel = "model/gender_net.caffemodel";//均值Scalar MODEL_MEAN_VALUES = Scalar(78.4263377603, 87.7689143744, 114.895847746);//年齡段標簽vector<string> ageList = { "(0-2)", "(4-6)", "(8-12)", "(15-20)", "(25-32)","(38-43)", "(48-53)", "(60-100)" };//性別標簽vector<string> genderList = { "Male", "Female" };//導入網絡Net ageNet = cv::dnn::readNet(ageProto, ageModel);Net genderNet = cv::dnn::readNet(genderProto, genderModel);Net faceNet = cv::dnn::readNetFromTensorflow(faceModel, faceProto);//打開攝像頭VideoCapture cap;cap.open(0);if (cap.isOpened()){cout << "camera is opened!" << endl;}else{return 0;}int padding = 20;while (waitKey(1) < 0){// read frame 讀圖Mat frame;cap.read(frame);if (frame.empty()){waitKey();break;}frame = imread("./images/couple1.jpg");//人臉坐標vector<vector<int>> bboxes;//人臉檢測結果圖Mat frameFace;//人臉定位//tie()函數解包frameFace和bboxestie(frameFace, bboxes) = getFaceBox(faceNet, frame, 0.7);//人臉判斷if (bboxes.size() == 0){cout << "No face detected, checking next frame." << endl;continue;}//逐個提取人臉檢測for (auto it = begin(bboxes); it != end(bboxes); ++it){//框選人臉Rect rec(it->at(0) - padding, it->at(1) - padding, it->at(2) - it->at(0) + 2 * padding, it->at(3) - it->at(1) + 2 * padding);//避免人臉框選超過圖像邊緣rec.width = ((rec.x + rec.width) > frame.cols) ? (frame.cols - rec.x - 1) : rec.width;rec.height = ((rec.y + rec.height) > frame.rows) ? (frame.rows - rec.y - 1) : rec.height;// take the ROI of box on the frame,原圖中提取人臉Mat face = frame(rec);//性別檢測Mat blob;blob = blobFromImage(face, 1, Size(227, 227), MODEL_MEAN_VALUES, false);genderNet.setInput(blob);// string gender_preds; 獲取前向傳播softmax結果vector<float> genderPreds = genderNet.forward();// find max element index max_element用于找尋最大值// distance function does the argmax() work in C++ distance返回最大值和第一個值下標的距離int max_index_gender = std::distance(genderPreds.begin(), max_element(genderPreds.begin(), genderPreds.end()));//獲得檢測結果string gender = genderList[max_index_gender];cout << "Gender: " << gender << endl;//年齡識別ageNet.setInput(blob);vector<float> agePreds = ageNet.forward();// finding maximum indicd in the age_preds vector 找到年齡預測最大下表int max_indice_age = std::distance(agePreds.begin(), max_element(agePreds.begin(), agePreds.end()));string age = ageList[max_indice_age];cout << "Age: " << age << endl;// label 輸出標簽string label = gender + ", " + age;//在人臉定位圖上顯示結果cv::putText(frameFace, label, Point(it->at(0), it->at(1) - 15), cv::FONT_HERSHEY_SIMPLEX, 0.9, Scalar(0, 255, 255), 2, cv::LINE_AA);}//保存結果imshow("Frame", frameFace);imwrite("out.jpg", frameFace);}}python版本:
# Import required modulesimport cv2 as cvimport timeimport argparsedef getFaceBox(net, frame, conf_threshold=0.7):frameOpencvDnn = frame.copy()frameHeight = frameOpencvDnn.shape[0]frameWidth = frameOpencvDnn.shape[1]blob = cv.dnn.blobFromImage(frameOpencvDnn, 1.0, (300, 300), [104, 117, 123], True, False)net.setInput(blob)detections = net.forward()bboxes = []for i in range(detections.shape[2]):confidence = detections[0, 0, i, 2]if confidence > conf_threshold:x1 = int(detections[0, 0, i, 3] * frameWidth)y1 = int(detections[0, 0, i, 4] * frameHeight)x2 = int(detections[0, 0, i, 5] * frameWidth)y2 = int(detections[0, 0, i, 6] * frameHeight)bboxes.append([x1, y1, x2, y2])cv.rectangle(frameOpencvDnn, (x1, y1), (x2, y2), (0, 255, 0), int(round(frameHeight/150)), 8)return frameOpencvDnn, bboxesparser = argparse.ArgumentParser(description='Use this script to run age and gender recognition using OpenCV.')parser.add_argument('--input', help='Path to input image or video file. Skip this argument to capture frames from a camera.')args = parser.parse_args()faceProto = "age_gender/model/opencv_face_detector.pbtxt"faceModel = "age_gender/model/opencv_face_detector_uint8.pb"ageProto = "age_gender/model/age_deploy.prototxt"ageModel = "age_gender/model/age_net.caffemodel"genderProto = "age_gender/model/gender_deploy.prototxt"genderModel = "age_gender/model/gender_net.caffemodel"MODEL_MEAN_VALUES = (78.4263377603, 87.7689143744, 114.895847746)ageList = ['(0-2)', '(4-6)', '(8-12)', '(15-20)', '(25-32)', '(38-43)', '(48-53)', '(60-100)']genderList = ['Male', 'Female']# Load networkageNet = cv.dnn.readNet(ageModel, ageProto)genderNet = cv.dnn.readNet(genderModel, genderProto)faceNet = cv.dnn.readNet(faceModel, faceProto)# Open a video file or an image file or a camera streamcap = cv.VideoCapture(args.input if args.input else 0)padding = 20while cv.waitKey(1) < 0:# Read framet = time.time()hasFrame, frame = cap.read()if not hasFrame:cv.waitKey()breakframeFace, bboxes = getFaceBox(faceNet, frame)if not bboxes:print("No face Detected, Checking next frame")continuefor bbox in bboxes:# print(bbox)face = frame[max(0,bbox[1]-padding):min(bbox[3]+padding,frame.shape[0]-1),max(0,bbox[0]-padding):min(bbox[2]+padding, frame.shape[1]-1)]blob = cv.dnn.blobFromImage(face, 1.0, (227, 227), MODEL_MEAN_VALUES, swapRB=False)genderNet.setInput(blob)genderPreds = genderNet.forward()gender = genderList[genderPreds[0].argmax()]# print("Gender Output : {}".format(genderPreds))print("Gender : {}, conf = {:.3f}".format(gender, genderPreds[0].max()))ageNet.setInput(blob)agePreds = ageNet.forward()age = ageList[agePreds[0].argmax()]print("Age Output : {}".format(agePreds))print("Age : {}, conf = {:.3f}".format(age, agePreds[0].max()))label = "{},{}".format(gender, age)cv.putText(frameFace, label, (bbox[0], bbox[1]-10), cv.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2, cv.LINE_AA)cv.imshow("Age Gender Demo", frameFace)# cv.imwrite("age-gender-out-{}".format(args.input),frameFace)print("time : {:.3f}".format(time.time() - t))參考
https://www.learnopencv.com/age-gender-classification-using-opencv-deep-learning-c-python/
總結
以上是生活随笔為你收集整理的Opencv 深度学习识别性别和检测年龄的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最小c编译器
- 下一篇: 在Windows10上安装WSL使用bi