【机器视觉案例】(13) 脸部和摄像机间的距离测量,自适应文本大小,附python完整代码
各位同學(xué)好,今天和大家分享一下如何使用 opencv+Mediapipe 測量人臉和攝像機鏡頭之間的距離,并創(chuàng)建一塊根據(jù)人臉距離變化的文本框。先放張圖看效果。
左圖是視頻圖像,顯示人臉和攝像機之間的距離distance;右圖是文本框,人臉和相機之間距離越近,則字體和行距越小,距離越遠(yuǎn),字體和行距越大。
1. 安裝工具包
pip install opencv_python==4.2.0.34 # 安裝opencv
pip install mediapipe # 安裝mediapipe
# pip install mediapipe --user #有user報錯的話試試這個
pip install cvzone # 安裝cvzone# 導(dǎo)入工具包
import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector # 臉部關(guān)鍵點檢測方法
import numpy as np # 用來創(chuàng)建文本框
2. 臉部關(guān)鍵點檢測
(1)cvzone.FaceMeshModule.FaceMeshDetector() ?人臉關(guān)鍵點檢測方法
參數(shù):
staticMode: 默認(rèn)為 False,將輸入圖像視為視頻流。它將嘗試在第一個輸入圖像中檢測人臉,并在成功檢測后進一步定位468個關(guān)鍵點的坐標(biāo)。在隨后的圖像中,一旦檢測到所有 maxFaces 張臉并定位了相應(yīng)的關(guān)鍵點的坐標(biāo),它就會跟蹤這些坐標(biāo),而不會調(diào)用另一個檢測,直到它失去對任何一張臉的跟蹤。這減少了延遲,非常適合處理視頻幀。如果設(shè)置為 True,則在每個輸入圖像上運行臉部檢測,用于處理一批靜態(tài)的、可能不相關(guān)的圖像。
maxFaces: 最多檢測幾張臉,默認(rèn)為 2
minDetectionCon=0.5: 臉部關(guān)鍵點檢測模型的最小置信值(0-1之間),超過閾值則檢測成功。默認(rèn)為 0.5
minTrackCon=0.5: 關(guān)鍵點坐標(biāo)跟蹤模型的最小置信值 (0-1之間),用于將手部坐標(biāo)視為成功跟蹤,不成功則在下一個輸入圖像上自動調(diào)用手部檢測。將其設(shè)置為更高的值可以提高解決方案的穩(wěn)健性,但代價是更高的延遲。如果 mode 為 True,則忽略這個參數(shù),手部檢測將在每個圖像上運行。默認(rèn)為 0.5
(2)cvzone.FaceMeshModule.FaceMeshDetector.findFaceMesh() ?找到人臉關(guān)鍵點
參數(shù):
img: 需要檢測關(guān)鍵點的幀圖像,格式為BGR
draw: 是否需要在原圖像上繪制關(guān)鍵點及連線
返回值:
img: 返回繪制了關(guān)鍵點及連線后的圖像
faces: 檢測到的臉部信息,三維列表,包含每張臉的468個關(guān)鍵點。
(3)距離測量方法
由下圖距離測量公式可知,現(xiàn)在要求實際距離 d,可通過相似三角形,利用人臉兩眼之間的距離來推算人臉距離攝像機的實際距離。
人兩眼之間的實際距離為W=63mm,相機視角下圖像上人眼的兩個關(guān)鍵點之間的距離w。
在求實時距離 d 之前我們需要知道相機焦距 f,又因為相機焦距 f 是固定不變的,那么我們先以固定的人臉和相機距離計算出 f ,取各個幀 f 的平均值,得到相機焦距
焦距計算公式:,這里的d是一個固定值
實際距離計算公式:,使用估算出的焦距的平均值用來計算實時的距離
代碼如下:
import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector # 臉部關(guān)鍵點檢測方法#(1)讀取視頻圖像
filepath = 'D:/deeplearning/video/eyes.mp4' # 視頻文件位置
cap = cv2.VideoCapture(filepath) # 參數(shù)填0代表電腦自帶攝像頭#(2)臉部關(guān)鍵點檢測方法
detector = FaceMeshDetector(maxFaces=1) # 最多檢測一張臉#(3)處理視頻圖像
while True:# 圖像是否讀取成功success,讀入的幀圖像imgsuccess, img = cap.read() # 每次讀取一幀# 檢測臉部關(guān)鍵點,返回繪制關(guān)鍵點后的圖像img和臉部關(guān)鍵點坐標(biāo)facesimg, faces = detector.findFaceMesh(img, draw=False) # 不繪制關(guān)鍵點print(faces)#(4)處理關(guān)鍵點if faces: # 如果檢測到了,那就接下去執(zhí)行face = faces[0] # faces是三維列表,我們只需要第一張臉的所有關(guān)鍵點pointLeft = tuple(face[145]) # 左眼關(guān)鍵點坐標(biāo)pointRight = tuple(face[374]) # 右眼坐標(biāo)# 繪制兩個關(guān)鍵點之間的連線cv2.line(img, pointLeft, pointRight, (0,255,0), 3)# 在關(guān)鍵點坐標(biāo)上繪制圓。注意圓心坐標(biāo)是元組類型tuplecv2.circle(img, pointLeft, 5, (0,255,255), cv2.FILLED)cv2.circle(img, pointRight, 5, (0,255,255), cv2.FILLED)# 計算兩點之間的線段距離w,相當(dāng)于勾股定理求距離w, _ = detector.findDistance(pointRight, pointLeft) # 返回線段距離和線段信息(兩端點和中點的坐標(biāo))#print(w)# 計算焦距W = 6.3 # 人臉兩眼之間的平均距離是6.3cmd = 40 # 當(dāng)前人臉距屏幕的距離f = (w*d)/W # 根據(jù)公式計算焦距print(f'foucus:{f}') # 打印所有焦距,取平均值,作為模型的焦距#(5)圖像展示cv2.imshow('img', img)k = cv2.waitKey(10) # 每幀延遲1毫秒后消失if k & 0xFF == 27: # 鍵盤上的ESC鍵退出循環(huán)break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()
效果圖如下:左圖是detector.findFaceMesh(img, draw=True)時檢測出的人臉關(guān)鍵點和連線,我們只需要用到兩眼之間的距離。如右圖,設(shè)置參數(shù)draw=True,不繪制人臉網(wǎng),只繪制兩眼之間的連線。
3. 距離測量,制作自適應(yīng)文本框
在上一節(jié)中我們以實際距離d=40cm,計算出了每一幀圖像的相機焦距,取其平均值 f=700 作為相機焦距計算實時的人臉距離?。使用 cvzone.putTextRect() 函數(shù)將距離值顯示在人臉額頭部位。
接下來創(chuàng)建一個和幀圖像相同size的,像素值全為0(黑色)的圖像 np.zeros_like(img),作為顯示文本的底板。
如下面代碼中的第(4)步,singleHeight = 50 + int(d/2) 每行文本初始距離為50,根據(jù)人臉距離實時變化。scale = 1 + int(d/20)? 文本字體的大小初始是1,根據(jù)人臉距離動態(tài)調(diào)整
在上述代碼中補充:
import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector # 臉部關(guān)鍵點檢測方法
import numpy as np # 用來創(chuàng)建文本框#(1)讀取視頻圖像
filepath = 'D:/deeplearning/video/eyes.mp4' # 視頻文件位置
cap = cv2.VideoCapture(filepath) # 參數(shù)填0代表電腦自帶攝像頭#(2)配置
# 臉部檢測方法
detector = FaceMeshDetector(maxFaces=1) # 最多檢測一張臉
# 文本框中的內(nèi)容
textList = ['anukbcxasxxa4525', 'xnsailcnau22222', 'xbuikuysalbxsalb','cinaxsabkcnaskmc','4861581816158151']#(3)處理視頻圖像
while True:# 圖像是否讀取成功success,讀入的幀圖像imgsuccess, img = cap.read() # 每次讀取一幀# 創(chuàng)建文本圖像,一張黑板imgText = np.zeros_like(img) # 創(chuàng)建一個size和img相同的黑色圖像# 檢測臉部關(guān)鍵點,返回繪制關(guān)鍵點后的圖像img和臉部關(guān)鍵點坐標(biāo)facesimg, faces = detector.findFaceMesh(img, draw=False) # 不繪制關(guān)鍵點#(4)處理關(guān)鍵點if faces: # 如果檢測到了,那就接下去執(zhí)行face = faces[0] # faces是三維列表,我們只需要第一張臉的所有關(guān)鍵點pointLeft = tuple(face[145]) # 左眼關(guān)鍵點坐標(biāo)pointRight = tuple(face[374]) # 右眼坐標(biāo)# 計算兩點之間的線段距離w,相當(dāng)于勾股定理求距離w, _ = detector.findDistance(pointRight, pointLeft) # 返回線段距離和線段信息(兩端點和中點的坐標(biāo))W = 6.3 # 人臉兩眼之間的實際平均距離是6.3cmf = 700 # 上一節(jié)的代碼求焦距,估計一個平均值,作為當(dāng)前的焦距# 計算人臉距離屏幕的距離d = (W*f)/wprint('distance face to screen:', d)# 將距離顯示在屏幕上,face[10]代表額頭的坐標(biāo)點,scale矩形框大小,thickness文字大小cvzone.putTextRect(img, f'distace:{int(d)}cm', (face[10][0]-100,face[10][1]),scale=2, thickness=3, colorR=(255,255,0), colorT=(0,0,0))#(4)編寫文本for i, text in enumerate(textList):singleHeight = 50 + int(d/2) # 動態(tài)調(diào)整文本每行之間的距離scale = 1 + int(d/20) # 根據(jù)臉和攝像機之間的距離調(diào)整字體大小# 控制每條文本之間的行間距i*singleHeight,scale動態(tài)改變字體大小cv2.putText(imgText, text, (50,100+i*singleHeight), cv2.FONT_ITALIC, scale, (255,255,255), 2)#(5)圖像展示img = cv2.resize(img, (800,450))imgText = cv2.resize(imgText, (800,450))# 將兩張圖像組合在一起,排2列,組合后size不變imgStacked = cvzone.stackImages([img, imgText], cols=2, scale=1)cv2.imshow('imgStacked', imgStacked)k = cv2.waitKey(20) # 每幀延遲1毫秒后消失if k & 0xFF == 27: # 鍵盤上的ESC鍵退出循環(huán)break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()
效果圖如下,人臉距離攝像機越近,則文本越小;人臉距離攝像機越遠(yuǎn),則字體越大。
總結(jié)
以上是生活随笔為你收集整理的【机器视觉案例】(13) 脸部和摄像机间的距离测量,自适应文本大小,附python完整代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【神经网络】(16) MobileNet
- 下一篇: 【深度学习理论】(2) 卷积神经网络