各位同學好,今天和大家分享一下如何使用MediaPipe完成人臉實時跟蹤檢測,先放張圖看效果,FPS值為14,右側的輸出為:每幀圖像是人臉的概率,檢測框的左上角坐標及框的寬高。
有需要的可以使用 cv2.VideoCapture(0) 捕獲電腦攝像頭。本節就用視頻進行人臉識別。

1. 導入工具包
# 安裝opencv
pip install opencv-contrib-python
# 安裝mediapipe
pip install mediapipe
# pip install mediapipe --user #有user報錯的話試試這個
# 安裝之後導入各個包
import cv2 #opencv
import mediapipe as mp
import time人臉檢測的相關說明見官方文檔:Face Detection – mediapipe
MediaPipe 人臉檢測是一種識別速度超快的方法,具有 6 個特徵點和多面支持。它基於BlazeFcae一個輕量級且性能良好的面部檢測器,專為移動GPU推理量身定製。該探測器的超實時性能使其能夠應用於任何需要精確感興趣面部區域作為其他任務特定模型輸入的實時取景器體驗,例如3D面部關鍵點或幾何估計(例如 MediaPipe Face Mesh)面部特徵或表情分類以及面部區域分割。
2. 相關函數說明
從mediapipe中導入檢測方法,今天我們使用人臉檢測
mediapipe.solutions.face_detection。
mediapipe.solutions.hands # 手部關鍵點檢測
mediapipe.solutions.pose # 人體姿態檢測
mediapipe.solutions.face_mesh # 人臉網狀檢測
mediapipe.solutions.face_detection # 人臉識別
....................(1)
mediapipe.solutions.face_detection.FaceDetection() 人臉檢測函數
參數:
min_detection_confidence: 默認為 0.5。人臉檢測模型的最小置信值 (0-1之間),高於該置信度則將檢測視為成功。
返回值:
detections:檢測到的人臉的集合,其中每個人臉都表示為一個檢測原始消息,其中包含 人臉的概率、1 個邊界框、6 個關鍵點(右眼、左眼、鼻尖、嘴巴中心、右耳、左耳)。邊界框由 xmin 和 width (由圖像寬度歸一化為 [0, 1])以及 ymin 和 height (由圖像高度歸一化為 [0, 1])組成。每個關鍵點由 x 和 y 組成,分別通過圖像寬度和高度歸一化為 [0, 1]。
返回值.score: 獲取圖像是人臉的概率
返回值.location_data: 獲取識別框的 x, y, w, h 和 6個關鍵點的 x, y
返回值
.location_data.relative_bounding_box: 獲取識別框的 x, y, w, h
返回值
.location_data.relative_keypoints: 6個關鍵點的 x, y 組成的列表
(2)
mediapipe.solutions.drawing_utils.draw_landmarks() 繪製手部關鍵點的連線
參數:
image: 需要畫圖的原始圖片
landmark_list: 檢測到的手部關鍵點坐標
connections: 連接線,需要把那些坐標連接起來
landmark_drawing_spec: 坐標的顏色,粗細
connection_drawing_spec: 連接線的粗細,顏色等
3. 只繪製識別框和關鍵點
使用 cv2.VideoCapture() 讀取視頻文件時,文件路徑最好不要出現中文,防止報錯。
變量.read() 每次執行就從視頻中提取一幀圖片,需要循環來不斷提取。用success來接收是否能打開,返回True表示可以打開。img保存返回的的每一幀圖像。
由於讀入視頻圖像通道一般為RGB,而opencv中圖像通道的格式為BGR,因此需要 cv2.cvtColor() 函數將opencv讀入的視頻圖像轉為RGB格式 cv2.COLOR_BGR2RGB。
import cv2
import mediapipe as mp
import time
# 導入人臉識別模塊
mpFace = mp.solutions.face_detection
# 導入繪圖模塊
mpDraw = mp.solutions.drawing_utils
# 自定義人臉識別方法,最小的人臉檢測置信度0.5
faceDetection = mpFace.FaceDetection(min_detection_confidence=0.5)
#(1)導入視頻
filepath = 'C:\GameDownload\Deep Learning\face.mp4'
cap = cv2.VideoCapture(filepath)
pTime = 0 # 記錄每幀圖像處理的起始時間
#(2)處理每一幀圖像
while True:
# 每次取出一幀圖像,返回是否讀取成功(True/False),以及讀取的圖像數據
success, img = cap.read()
# 將opencv導入的BGR圖像轉為RGB圖像
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 將每一幀圖像傳給人臉識別模塊
results = faceDetection.process(imgRGB)
# 如果檢測不到人臉那就返回None
if results.detections:
# 返回人臉關鍵點索引index,和關鍵點的坐標信息
for index, detection in enumerate(results.detections):
# 遍歷每一幀圖像並打印結果
print(index, detection)
# 每幀圖像返回一次是人臉的幾率,以及識別框的xywh,後續返回關鍵點的xy坐標
# print(detection.score) # 是人臉的的可能性
# print(detection.location_data.relative_bounding_box) # 識別框的xywh
# 繪製關鍵點信息及邊界框
mpDraw.draw_detection(img, detection)
# 記錄每幀圖像處理所花的時間
cTime = time.time()
fps = 1/(cTime-pTime) #計算fps值
pTime = cTime # 更新每張圖像處理的初始時間
# 把fps值顯示在圖像上,img畫板;fps變成字符串;顯示的位置;設置字體;字體大小;字體顏色;線條粗細
cv2.putText(img, f'FPS: {str(int(fps))}', (10,50), cv2.FONT_HERSHEY_PLAIN, 3, (0,255,0), 3)
# 顯示圖像,輸入窗口名及圖像數據
cv2.imshow('image', img)
if cv2.waitKey(50) & 0xFF==27: #每幀滯留50毫秒後消失,ESC鍵退出
break
# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()結果如下圖所示,準確找到了人臉位置,並繪製識別框。右側打印識別框和關鍵點信息。

4. 編輯識別框,保存人臉位置信息
在這裡我更加關注識別框的位置位置,不太關心關鍵點的坐標信息,因此接下來我們單獨繪製識別框,並把每一幀圖像的人臉概率顯示出來。如果有同學更關注人臉關鍵點,可以使用mediapipe的人臉網狀檢測,能得到的關鍵點非常多,這個我在後續章節也會寫。
因此,接下來我們在上面代碼的基礎上繼續補充。
detection.location_data.relative_bounding_box 獲取檢測框的左上角坐標和檢測框的寬高,保保存在bbox中。如下我們可以看到識別框的信息都是歸一化之後的,需要將其轉換為像素坐標。
IN[21]: detection.location_data.relative_bounding_box
Out[21]:
xmin: 0.6636191606521606
ymin: 0.16451001167297363
width: 0.1620280146598816
height: 0.28804928064346313轉換方法也很簡單,只需要將比例長度x和w乘以實際圖像寬度即可得到像素長度下的x和w,同理y和h。注意,像素長度一定是整數,如[200,200],比例長度是小數,如[0.5, 0.5]
使用自定義矩形繪製函數cv2.rectangle(),現在有了像素坐標下的左上坐標xy,框的寬w和高h。就可以在原圖像img上把框繪製出來。
detection.score 獲取檢測框的人臉概率值,返回只有一個元素的列表。detection.score[0] 提取這個元素,返回浮點型數值。
# 導入人臉識別模塊
mpFace = mp.solutions.face_detection
# 導入繪圖模塊
mpDraw = mp.solutions.drawing_utils
# 自定義人臉識別方法,最小的人臉檢測置信度0.5
faceDetection = mpFace.FaceDetection(min_detection_confidence=0.5)
#(1)導入視頻
filepath = 'C:\GameDownload\Deep Learning\face.mp4'
cap = cv2.VideoCapture(filepath)
pTime = 0 # 記錄每幀圖像處理的起始時間
boxlist = [] # 保存每幀圖像每個框的信息
#(2)處理每一幀圖像
while True:
# 每次取出一幀圖像,返回是否讀取成功(True/False),以及讀取的圖像數據
success, img = cap.read()
# 將opencv導入的BGR圖像轉為RGB圖像
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 將每一幀圖像傳給人臉識別模塊
results = faceDetection.process(imgRGB)
# 如果檢測不到人臉那就返回None
if results.detections:
# 返回人臉索引index(第幾張臉),和關鍵點的坐標信息
for index, detection in enumerate(results.detections):
# 遍歷每一幀圖像並打印結果
# print(index, detection)
# 每幀圖像返回一次是人臉的幾率,以及識別框的xywh,後續返回關鍵點的xy坐標
print(detection.score) # 是人臉的的可能性
print(detection.location_data.relative_bounding_box) # 識別框的xywh
# 設置一個邊界框,接收所有的框的xywh及關鍵點信息
bboxC = detection.location_data.relative_bounding_box
# 接收每一幀圖像的寬、高、通道數
ih, iw, ic = img.shape
# 將邊界框的坐標點從比例坐標轉換成像素坐標
# 將邊界框的寬和高從比例長度轉換為像素長度
bbox = (int(bboxC.xmin * iw), int(bboxC.ymin * ih),
int(bboxC.width * iw), int(bboxC.height * ih))
# 有了識別框的xywh就可以在每一幀圖像上把框畫出來
cv2.rectangle(img, bbox, (255,0,0), 5) # 自定義繪製函數,不適用官方的mpDraw.draw_detection
# 把人臉的概率顯示在檢測框上,img畫板,概率值*100保留兩位小數變成百分數,再變成字符串
cv2.putText(img, f'{str(round(detection.score[0] * 100, 2))}%',
(bbox[0], bbox[1]-20), # 文本顯示的位置,-20是為了不和框重合
cv2.FONT_HERSHEY_PLAIN, # 文本字體類型
2, (0,0,255), 2) # 字體大小; 字體顏色; 線條粗細
# 保存索引,人臉概率,識別框的x/y/w/h
boxlist.append([index, detection.score, bbox])
# 記錄每幀圖像處理所花的時間
cTime = time.time()
fps = 1/(cTime-pTime) #計算fps值
pTime = cTime # 更新每張圖像處理的初始時間
# 把fps值顯示在圖像上,img畫板;fps變成字符串;顯示的位置;設置字體;字體大小;字體顏色;線條粗細
cv2.putText(img, f'FPS: {str(int(fps))}', (10,50), cv2.FONT_HERSHEY_PLAIN, 3, (0,255,0), 3)
# 顯示圖像,輸入窗口名及圖像數據
cv2.imshow('image', img)
if cv2.waitKey(50) & 0xFF==27: #每幀滯留50毫秒後消失,ESC鍵退出
break
# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()結果如下圖所示,右側輸出每幀圖像的每個識別框的概率和框坐標

5. 優化識別框
接下來把識別框做的好看一些,只需要修改矩形框樣式即可,我們接着上面的代碼編輯。把識別框寬度調細一些,在四個角上添加粗線段。
# 導入人臉識別模塊
mpFace = mp.solutions.face_detection
# 導入繪圖模塊
mpDraw = mp.solutions.drawing_utils
# 自定義人臉識別方法,最小的人臉檢測置信度0.5
faceDetection = mpFace.FaceDetection(min_detection_confidence=0.5)
#(1)導入視頻
filepath = 'C:\GameDownload\Deep Learning\face.mp4'
cap = cv2.VideoCapture(filepath)
pTime = 0 # 記錄每幀圖像處理的起始時間
boxlist = [] # 保存每幀圖像每個框的信息
#(2)處理每一幀圖像
while True:
# 每次取出一幀圖像,返回是否讀取成功(True/False),以及讀取的圖像數據
success, img = cap.read()
# 將opencv導入的BGR圖像轉為RGB圖像
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 將每一幀圖像傳給人臉識別模塊
results = faceDetection.process(imgRGB)
# 如果檢測不到人臉那就返回None
if results.detections:
# 返回人臉索引index(第幾張臉),和關鍵點的坐標信息
for index, detection in enumerate(results.detections):
# 遍歷每一幀圖像並打印結果
# print(index, detection)
# 每幀圖像返回一次是人臉的幾率,以及識別框的xywh,後續返回關鍵點的xy坐標
print(detection.score) # 是人臉的的可能性
print(detection.location_data.relative_bounding_box) # 識別框的xywh
# 設置一個邊界框,接收所有的框的xywh及關鍵點信息
bboxC = detection.location_data.relative_bounding_box
# 接收每一幀圖像的寬、高、通道數
ih, iw, ic = img.shape
# 將邊界框的坐標點從比例坐標轉換成像素坐標
# 將邊界框的寬和高從比例長度轉換為像素長度
bbox = (int(bboxC.xmin * iw), int(bboxC.ymin * ih),
int(bboxC.width * iw), int(bboxC.height * ih))
# 有了識別框的xywh就可以在每一幀圖像上把框畫出來
# cv2.rectangle(img, bbox, (255,0,0), 5) # 自定義繪製函數,不適用官方的mpDraw.draw_detection
# 把人臉的概率顯示在檢測框上,img畫板,概率值*100保留兩位小數變成百分數,再變成字符串
cv2.putText(img, f'{str(round(detection.score[0] * 100, 2))}%',
(bbox[0], bbox[1]-20), # 文本顯示的位置,-20是為了不和框重合
cv2.FONT_HERSHEY_PLAIN, # 文本字體類型
2, (0,0,255), 2) # 字體大小; 字體顏色; 線條粗細
# 保存索引,人臉概率,識別框的x/y/w/h
boxlist.append([index, detection.score, bbox])
#(3)修改識別框樣式
x, y, w, h = bbox # 獲取識別框的信息,xy為左上角坐標點
x1, y1 = x+w, y+h # 右下角坐標點
# 繪製比矩形框粗的線段,img畫板,線段起始點坐標,線段顏色,線寬為8
cv2.line(img, (x,y), (x+20,y), (255,0,255), 4)
cv2.line(img, (x,y), (x,y+20), (255,0,255), 4)
cv2.line(img, (x1,y1), (x1-20,y1), (255,0,255), 4)
cv2.line(img, (x1,y1), (x1,y1-20), (255,0,255), 4)
cv2.line(img, (x1,y), (x1-20,y), (255,0,255), 4)
cv2.line(img, (x1, y), (x1, y+20), (255, 0, 255), 4)
cv2.line(img, (x,y1), (x+20,y1), (255,0,255), 4)
cv2.line(img, (x,y1), (x,y1-20), (255,0,255), 4)
# 在每一幀圖像上繪製矩形框
cv2.rectangle(img, bbox, (255,0,255), 1) # 自定義繪製函數
# 記錄每幀圖像處理所花的時間
cTime = time.time()
fps = 1/(cTime-pTime) #計算fps值
pTime = cTime # 更新每張圖像處理的初始時間
# 把fps值顯示在圖像上,img畫板;fps變成字符串;顯示的位置;設置字體;字體大小;字體顏色;線條粗細
cv2.putText(img, f'FPS: {str(int(fps))}', (10,50), cv2.FONT_HERSHEY_PLAIN, 3, (0,255,0), 3)
# 顯示圖像,輸入窗口名及圖像數據
cv2.imshow('image', img)
if cv2.waitKey(50) & 0xFF==27: #每幀滯留50毫秒後消失,ESC鍵退出
break
# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()修改後的檢測框效果如下

我們將坐標信息存放在了boxlist中,boxlist.append([index, detection.score, bbox]) 存放人臉索引、評分、檢測框信息,把它打印出來看一下,比如某幀圖像所在的視頻有3張臉,每一幀都會輸出0、1、2三個識別框的概率,左上角坐標xy,框的寬高wh
。。。。。。。。。。。。。。。。。。。。。。。。。
[0, [0.9619430303573608], (98, 100, 96, 96)],
[1, [0.9173532128334045], (457, 65, 118, 118)],
[2, [0.8985080122947693], (268, 52, 123, 123)],
[0, [0.9615015983581543], (98, 100, 97, 97)],
[1, [0.9164762496948242], (457, 65, 118, 118)],
[2, [0.9118367433547974], (269, 53, 123, 123)],
[0, [0.9616674780845642], (97, 100, 97, 97)],
[1, [0.9218802452087402], (272, 53, 122, 122)],
[2, [0.9176990389823914], (456, 65, 118, 118)],
[0, [0.9638006091117859], (97, 101, 97, 97)],
[1, [0.9180505275726318], (276, 56, 119, 119)],
[2, [0.9177079796791077], (456, 64, 118, 118)],
。。。。。。。。。。。。。。。。。。。。。。。。。。原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/223272.html
微信掃一掃
支付寶掃一掃