一、引言
在計算機視覺領域,人臉分析是一個熱門且應用廣泛的研究方向。其中,人臉性別年齡檢測能夠自動識別圖像或視頻流中人臉的性別和年齡信息,具有諸多實際應用場景,如市場調研、安防監控、用戶個性化體驗等。OpenCV 作為一個強大的計算機視覺庫,提供了豐富的工具和預訓練模型來實現這一功能。
二、原理概述
人臉檢測:首先需要在輸入的圖像或視頻幀中檢測出人臉。OpenCV 常用的人臉檢測方法基于 Haar 級聯檢測器或基于深度學習的目標檢測算法(如 SSD、YOLO 等)。Haar 級聯檢測器通過構建一系列簡單的 Haar 特征,并利用 AdaBoost 算法訓練出一個強分類器來識別圖像中的人臉區域。基于深度學習的方法則通過在大規模人臉數據集上訓練卷積神經網絡(CNN),學習人臉的特征模式,從而實現更準確的人臉檢測。?
性別年齡預測:一旦檢測到人臉,將人臉區域進行預處理(如裁剪、歸一化等)后輸入到預訓練的性別年齡預測模型中。這些模型通常也是基于深度學習的 CNN 架構。在訓練過程中,模型學習到不同年齡和性別人臉的特征表示,通過對輸入人臉圖像的特征提取和分析,預測出該人臉對應的性別(通常為男性或女性)和年齡范圍(如兒童、青少年、成年人、老年人等)。
pip install opencv - python
下載預訓練模型:?
人臉檢測模型:對于 Haar 級聯人臉檢測,可以從 OpenCV 官方的 GitHub 倉庫下載haarcascade_frontalface_default.xml文件。該文件包含了訓練好的 Haar 級聯分類器參數。
性別年齡預測模型:性別年齡預測模型通常基于深度學習,如 Caffe 模型。可以從相關開源項目中下載預訓練的deploy_gender.prototxt和gender_net.caffemodel文件用于性別預測,以及deploy_age.prototxt和age_net.caffemodel文件用于年齡預測。這些模型在大規模人臉數據集上進行了訓練,具有一定的準確性。
準備輸入數據:準備用于檢測的圖像或視頻文件。確保圖像或視頻中的人臉清晰可見,光線條件良好,以提高檢測的準確性。
三、代碼實現
1.導入必要的庫
import cv2
from PIL import Image, ImageDraw, ImageFont
import numpy as np
導入cv2庫用于計算機視覺處理,PIL庫中的Image、ImageDraw、ImageFont用于在圖像上繪制中文字符,numpy庫用于數值計算。
2.加載模型文件路徑
獲取路徑:通過網盤分享的文件:model2
鏈接: https://pan.baidu.com/s/1gS-5xqOexYyMQ_wUQJTR0w 提取碼: ued3
faceProto = "model2/opencv_face_detector.pbtxt"
faceModel = "model2/opencv_face_detector_uint8.pb"
ageProto = "model2/deploy_age.prototxt"
ageModel = "model2/age_net.caffemodel"
genderProto = "model2/deploy_gender.prototxt"
genderModel = "model2/gender_net.caffemodel"
定義人臉檢測、年齡預測和性別預測模型的配置文件(.pbtxt或.prototxt)和權重文件(.pb或.caffemodel)的路徑。
3.讀取模型
ageNet = cv2.dnn.readNet(ageModel, ageProto)
genderNet = cv2.dnn.readNet(genderModel, genderProto)
faceNet = cv2.dnn.readNet(faceModel, faceProto)
使用cv2.dnn.readNet函數讀取年齡、性別和人臉檢測模型,以便后續用于推理
4.定義年齡和性別標簽列表及均值
ageList = ['0-2歲', '4-6歲', '8-12歲', '15-20歲', '25-32歲', '38-43歲', '48-53歲', '60-100歲']
genderList = ['男性', '女性']
mean = (78.4263377603, 87.7689143744, 114.895847746)
創建年齡和性別標簽列表,用于將模型預測的類別索引轉換為實際的年齡范圍和性別描述。同時定義了圖像歸一化所需的均值。
5.人臉檢測函數
def getBoxes(net, frame):frameHeight, frameWidth = frame.shape[:2]blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300),[104, 117, 123], True, False)net.setInput(blob)detections = net.forward()faceBoxes = []for i in range(detections.shape[2]):confidence = detections[0, 0, i, 2]if confidence > 0.7: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)faceBoxes.append([x1, y1, x2, y2])cv2.rectangle(frame, (x1, y1), (x2, y2),(0, 255, 0), int(round(frameHeight / 150)), 6)return frame, faceBoxes
這個函數接受一個模型net和一個視頻幀frame作為輸入。首先獲取幀的高度和寬度,然后使用cv2.dnn.blobFromImage將幀轉換為適合模型輸入的 blob 格式,設置模型輸入并進行前向推理得到檢測結果。遍歷檢測結果,篩選出置信度大于 0.7 的檢測框,將其坐標轉換為實際圖像中的坐標并添加到faceBoxes列表中,同時在原幀上繪制檢測框。最后返回繪制了檢測框的幀和檢測框坐標列表。
6.在圖像上繪制中文字符的函數
def cv2AddchineseText(img, text, position, textColor=(0, 255, 0), textSize=30):if isinstance(img, np.ndarray):img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(img)fontStyle = ImageFont.truetype("simhei.ttf", textSize, encoding="utf-8")draw.text(position, text, textColor, font=fontStyle)return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
該函數用于在圖像上繪制中文字符。首先判斷輸入的圖像是否為 OpenCV 的numpy.ndarray格式,如果是則將其轉換為PIL的Image格式。然后使用ImageDraw和ImageFont設置字體樣式并在圖像上指定位置繪制文本,最后再將圖像轉換回 OpenCV 的BGR格式并返回
7.主循環
cap = cv2.VideoCapture(0)
while True:_, frame = cap.read()frame = cv2.flip(frame, 1)frame, faceBoxes = getBoxes(faceNet, frame)if not faceBoxes:print("當前鏡頭中沒有人")continuefor faceBox in faceBoxes:x1, y1, x2, y2 = faceBoxface = frame[y1:y2, x1: x2]blob = cv2.dnn.blobFromImage(face, 1.0, (227, 227), mean)genderNet.setInput(blob)genderOuts = genderNet.forward()gender = genderList[genderOuts[0].argmax()]ageNet.setInput(blob)ageOuts = ageNet.forward()age = ageList[ageOuts[0].argmax()]result = "{},{}".format(gender, age)frame = cv2AddchineseText(frame, result, (x1, y1 - 30))cv2.imshow("result", frame)if cv2.waitKey(1) == 27:break
cv2.destroyAllWindows()
cap.release()
初始化攝像頭設備,通過cv2.VideoCapture(0)打開默認攝像頭。進入無限循環,不斷讀取攝像頭的幀,使用cv2.flip對幀進行水平翻轉(以實現鏡像效果)。調用getBoxes函數進行人臉檢測,獲取繪制了檢測框的幀和檢測到的人臉框列表。如果沒有檢測到人臉,則打印提示信息并繼續下一次循環。對于檢測到的每一張人臉,提取人臉區域,將其轉換為適合性別和年齡模型輸入的 blob 格式,分別輸入到性別和年齡預測模型中進行推理,獲取預測結果并從標簽列表中找到對應的性別和年齡描述,將兩者組合成結果字符串,使用cv2AddchineseText函數在圖像上繪制結果。最后使用cv2.imshow顯示處理后的幀,當用戶按下Esc鍵(鍵值為 27)時,退出循環。循環結束后,釋放攝像頭資源并關閉所有 OpenCV 窗口。
完整代碼:
import cv2
from PIL import Image, ImageDraw, ImageFont
import numpy as npfaceProto = "model2/opencv_face_detector.pbtxt"
faceModel = "model2/opencv_face_detector_uint8.pb"
ageProto = "model2/deploy_age.prototxt"
ageModel = "model2/age_net.caffemodel"
genderProto = "model2/deploy_gender.prototxt"
genderModel = "model2/gender_net.caffemodel"ageNet = cv2.dnn.readNet(ageModel, ageProto)
genderNet = cv2.dnn.readNet(genderModel, genderProto)
faceNet = cv2.dnn.readNet(faceModel, faceProto)ageList = ['0-2歲', '4-6歲', '8-12歲', '15-20歲', '25-32歲', '38-43歲', '48-53歲', '60-100歲']
genderList = ['男性', '女性']
mean = (78.4263377603, 87.7689143744, 114.895847746)def getBoxes(net, frame):frameHeight, frameWidth = frame.shape[:2]blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300),[104, 117, 123], True, False)net.setInput(blob)detections = net.forward()faceBoxes = []for i in range(detections.shape[2]):confidence = detections[0, 0, i, 2]if confidence > 0.7: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)faceBoxes.append([x1, y1, x2, y2])cv2.rectangle(frame, (x1, y1), (x2, y2),(0, 255, 0), int(round(frameHeight / 150)), 6)return frame, faceBoxesdef cv2AddchineseText(img, text, position, textColor=(0, 255, 0), textSize=30):if isinstance(img, np.ndarray): # 判斷是否為OpenCV圖片類型img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(img)fontStyle = ImageFont.truetype("simhei.ttf", textSize, encoding="utf-8")draw.text(position, text, textColor, font=fontStyle)return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)cap = cv2.VideoCapture(0) # 裝載攝像頭
while True:_, frame = cap.read()frame = cv2.flip(frame, 1)frame, faceBoxes = getBoxes(faceNet, frame)if not faceBoxes:print("當前鏡頭中沒有人")continuefor faceBox in faceBoxes:x1, y1, x2, y2 = faceBoxface = frame[y1:y2, x1: x2]blob = cv2.dnn.blobFromImage(face, 1.0, (227, 227), mean)genderNet.setInput(blob)genderOuts = genderNet.forward()gender = genderList[genderOuts[0].argmax()]ageNet.setInput(blob)ageOuts = ageNet.forward()age = ageList[ageOuts[0].argmax()]result = "{},{}".format(gender, age)frame = cv2AddchineseText(frame, result, (x1, y1 - 30))cv2.imshow("result", frame)if cv2.waitKey(1) == 27:break
cv2.destroyAllWindows()
cap.release()
最后實現對人臉性別年齡的檢測
四、總結
通過 OpenCV,我們可以方便地實現人臉性別年齡檢測。利用其提供的預訓練模型和豐富的函數接口,結合簡單的代碼編寫,就能夠搭建起一個實用的人臉分析系統。希望本文能幫助你快速上手并在實際項目中應用這一技術