深入解析基于OpenCV年齡與性別識別系統
在這篇博客中,我們將詳細解析一個使用OpenCV進行年齡和性別識別的Python腳本。這個腳本展示了如何利用深度學習模型,從視頻或圖像中檢測人臉并預測每個人臉的年齡和性別。
1. 導入必要的模塊
import cv2 as cv
import math
import time
import argparse
首先,腳本開始于導入必需的Python模塊。這里cv2
是OpenCV庫的Python接口,主要用于圖像處理和計算機視覺任務。argparse
用于處理命令行參數,time
用于測量執行時間。
2. 人臉檢測功能
def 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, bboxes
getFaceBox`是腳本的核心,用于從給定的幀中檢測人臉。它首先創建一個圖像的blob(一個經過預處理的圖像數組),然后通過預訓練的神經網絡進行前向傳播,檢測出圖像中的人臉。對于每個檢測到的人臉,如果其置信度高于閾值,它計算出人臉的邊界框,并在圖像上繪制矩形。
3. 解析命令行參數和模型加載
if __name__ == '__main__':parser = 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.')parser.add_argument("--device", default="cpu", help="Device to inference on")args = parser.parse_args()
在腳本的主部分,它首先定義了命令行參數解析器,允許用戶指定輸入源(圖像或視頻文件,或者攝像頭流)和推理設備(CPU或GPU)。
faceNet = cv.dnn.readNet(faceModel, faceProto)ageNet = cv.dnn.readNet(ageModel, ageProto)genderNet = cv.dnn.readNet(genderModel, genderProto)
這里,腳本加載了三個預訓練模型:人臉檢測、年齡預測和性別預測。每個模型都通過OpenCV的深度神經網絡模塊讀取。
4. 主循環
while cv.waitKey(1) < 0:hasFrame, frame = cap.read()if notFrame:cv.waitKey()breakframeFace, bboxes = getFaceBox(faceNet, frame)if not bboxes:print("No face Detected, Checking next frame")continue
在主循環中,腳本從視頻捕獲設備或圖像文件中讀取幀。然后它調用getFaceBox
函數來獲取每幀中的人臉邊界框。
5. 性別和年齡識別
for bbox in bboxes: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()]ageNet.setInput(blob)agePreds = ageNet.forward()age = ageList[agePreds[0].argmax()]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)
對于每個檢測到的人臉,腳本提取人臉圖像并生成一個blob,然后將其輸入到性別和年齡識別模型中。通過模型的輸出,它確定每個人臉的性別和年齡,并在原始圖像上標記出這些信息。
完整代碼
# Import required modules
import cv2 as cv
import math
import time
import 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, bboxesif __name__ == '__main__':parser = 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.')parser.add_argument("--device", default="cpu", help="Device to inference on")args = parser.parse_args()# args = parser.parse_args()faceProto = "opencv_face_detector.pbtxt"faceModel = "opencv_face_detector_uint8.pb"ageProto = "age_deploy.prototxt"ageModel = "age_net.caffemodel"genderProto = "gender_deploy.prototxt"genderModel = "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)if args.device == "cpu":ageNet.setPreferableBackend(cv.dnn.DNN_TARGET_CPU)genderNet.setPreferableBackend(cv.dnn.DNN_TARGET_CPU)faceNet.setPreferableBackend(cv.dnn.DNN_TARGET_CPU)print("Using CPU device")elif args.device == "gpu":ageNet.setPreferableBackend(cv.dnn.DNN_BACKEND_CUDA)ageNet.setPreferableTarget(cv.dnn.DNN_TARGET_CUDA)genderNet.setPreferableBackend(cv.dnn.DNN_BACKEND_CUDA)genderNet.setPreferableTarget(cv.dnn.DNN_TARGET_CUDA)genderNet.setPreferableBackend(cv.dnn.DNN_BACKEND_CUDA)genderNet.setPreferableTarget(cv.dnn.DNN_TARGET_CUDA)print("Using GPU device")# # 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))# cmake -DCMAKE_BUILD_TYPE=RELEASE -DCMAKE_INSTALL_PREFIX=~/opencv_gpu -DINSTALL_PYTHON_EXAMPLES=OFF -DINSTALL_C_EXAMPLES=OFF -DOPENCV_ENABLE_NONFREE=ON -DOPENCV_EXTRA_MODULES_PATH=~/cv2_gpu/opencv_contrib/modules -DPYTHON_EXECUTABLE=~/env/bin/python3 -DBUILD_EXAMPLES=ON -DWITH_CUDA=ON -DWITH_CUDNN=ON -DOPENCV_DNN_CUDA=ON -DENABLE_FAST_MATH=ON -DCUDA_FAST_MATH=ON -DWITH_CUBLAS=ON -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-10.2 -DOpenCL_LIBRARY=/usr/local/cuda-10.2/lib64/libOpenCL.so -DOpenCL_INCLUDE_DIR=/usr/local/cuda-10.2/include/ ..