利用Python實現(xiàn)眨眼計數(shù)器的示例代碼
一、前言
這幾天宅在家里網上沖浪,無意間看到了一個比較有趣的項目,就是使用 Python 語言實現(xiàn)對視頻中的人物的眨眼進行計數(shù)并描繪在圖表中。我嘗試了一下,發(fā)現(xiàn)是可以實現(xiàn)的,所以自己碼了一遍代碼并簡單注釋了一下,有興趣的朋友可以淺試一下。
該項目大致效果如下:

Now, let's start!
二、實現(xiàn)步驟
對于創(chuàng)建項目文件夾配置環(huán)境以及如何安裝第三方庫這里就不再詳細的介紹了,有不會的同學可以去翻我之前的文章或者其他博主的文章去了解學習吧,并不是很難。
1.第三方庫
首先我們需要安裝 cvzone(一個比較專業(yè)的計算機視覺包,在面部識別,手勢、姿勢檢測中為我們提供了很多便利)。還有一個包是 mediapipe,我們將會使用它來實現(xiàn)面部檢測網絡,以便于對視頻中的眼睛部位進行觀察。
2.導入視頻文件并播放
實現(xiàn)代碼及效果如下:
import cv2
import cvzone
cap = cv2.VideoCapture('BlinkCounter.mp4')#獲取需要檢測的視頻(添加視頻路徑即可,此處由于視頻和Python文件在同一路徑,直接調用即可)
while True:
success, img = cap.read()
img = cv2.resize(img, (640, 360)) #對圖像尺寸進行調節(jié)
cv2.imshow("Image", img) #顯示圖像
cv2.waitKey(1)
3.讓視頻循環(huán)播放
我們要對視頻中的眨眼次數(shù)進行計數(shù),但通過上面的代碼可以看出視頻很快就播放結束了,所以我們采用檢查視頻幀數(shù)的方式,當達到視頻的最后一幀時對其進行重置,達到循環(huán)播放視頻的目的。代碼如下:
#------------------------------------------------------------
#檢查當前幀數(shù)是否等于視頻的總體幀數(shù),如果相等,將播放幀數(shù)重置為0
#------------------------------------------------------------
if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
4.創(chuàng)建面部檢測器
該步驟需要使用到 cvzone 中的相應模塊來實現(xiàn),具體代碼及注釋如下:
import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector #調用面部檢測模塊
cap = cv2.VideoCapture('BlinkCounter.mp4')#獲取需要檢測的視頻(添加視頻路徑即可,此處由于視頻和Python文件在同一路徑,直接調用即可)
detector = FaceMeshDetector(maxFaces = 1)#創(chuàng)建人臉網絡檢測器,檢測面部數(shù)量為1
while True:
#------------------------------------------------------------
#檢查當前幀數(shù)是否等于視頻的總體幀數(shù),如果相等,將播放幀數(shù)重置為0
#------------------------------------------------------------
if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
#------------------------------------------------------------
success, img = cap.read()
img, faces = detector.findFaceMesh(img)#繪制人臉網絡
img = cv2.resize(img, (640, 360)) #對圖像尺寸進行調節(jié)
cv2.imshow("Image", img) #顯示圖像
cv2.waitKey(1)
得到的結果如下:

5.對眼睛周圍的點進行標記
由于面部檢測器是對面部用點進行標記的,所以我們需要找到那些眼睛周圍的點并將它們使用特殊的點來進行標記,從而達到檢測眼睛閉合與張開的目的,相應的點數(shù)以及代碼如下:
idList = [22, 23, 24, 26, 110, 157, 158, 159, 160, 161, 130, 243]#面部檢測器中眼眶周圍的像素點
color = (0, 0, 255)#將顏色設置為紅色
#------------------------------------------------------------
#檢測到面部時將面部的關于眼眶的點用圓圈表示出來,并填補完整
#------------------------------------------------------------
if faces:
face = faces[0]
for id in idList:
cv2.circle(img, face[id], 5, color, cv2.FILLED)
得到的效果如下,可以看出,已經對眼眶進行了標記:

我們可以對面部檢測網絡進行設置,讓其他的一些點不再顯示出來,只關注我們的目標點,具體操作方式是只需要在函數(shù)中添加一個參數(shù)即可,效果如下:
img, faces = detector.findFaceMesh(img, draw = False)#繪制人臉檢測網絡,將參數(shù) draw 修改為 False 即可抹去其他的不必要的點

6.觀察眼睛寬度和長度變化并進行計數(shù)
如果單純的靠上下眼皮的變化來檢測是否眨眼會造成判斷錯誤,所以我們需要結合眼睛長度和寬度之比進行判斷。將這項數(shù)據的變化趨勢繪制在一個窗口中,就會使得我們的觀察更加明顯,得到的效果也將更加優(yōu)良。具體代碼如下:
#-------------------------------------------------------------
#使用眼眶周圍不同的點之間的距離以及眼睛寬度和長度的對比進行眨眼計數(shù)
#-------------------------------------------------------------
leftUp = face[159]#定義不同部位的像素點
leftDown = face[23]
leftLeft = face[130]
leftRight = face[243]
lenghtVer, _ = detector.findDistance(leftUp, leftDown)#得到眼睛寬度
lenghtHor, _ = detector.findDistance(leftLeft, leftRight)#得到眼睛長度
cv2.line(img, leftUp, leftDown, (0, 200, 0), 3)#繪制與眼睛等寬的線段
cv2.line(img, leftLeft, leftRight, (0, 200, 0), 3)#繪制與眼睛等長的線段
ratio = int((lenghtVer / lenghtHor) * 100)#得到的數(shù)據并進行標準化,得到比率值
ratioList.append(ratio)#使用比率值填補列表
#------------------------------------------------------------------
#從之前的一共三個比率中得到平均值,如果比率數(shù)目大于3將會刪去前面的比率值
#------------------------------------------------------------------
if len(ratioList) > 3:
ratioList.pop(0)
ratioAvg = sum(ratioList) / len(ratioList)#得到比率平均值
#------------------------------------
#通過比率平均值的變化對眨眼次數(shù)進行計數(shù)
#------------------------------------
if ratioAvg < 35 and counter == 0:
blinkCounter += 1#變化一次,計數(shù)器加一
color = (0, 200, 0)
counter = 1
if counter != 0:
counter += 1
if counter > 10:
counter = 0
color = (255, 0, 255)
#-----------------------------
#編寫文本框來記錄眨眼的總體次數(shù)
#------------------------------
cvzone.putTextRect(img, f'Blink Count: {blinkCounter}', (50, 250),
12, colorR = color)
imgPlot = plotY.update(ratioAvg, color)
img = cv2.resize(img, (400, 640)) # 對圖像尺寸進行調節(jié)
imgStack = cvzone.stackImages([img, imgPlot], 2, 1)#將兩幅圖像放到一起,疊放為2列圖像
else:
img = cv2.resize(img, (400, 640)) # 對圖像尺寸進行調節(jié)
imgStack = cvzone.stackImages([img, img], 2, 1)通過以上步驟大致就能實現(xiàn)眨眼計數(shù)了。

三、整體代碼
整體代碼如下,已經添加了注釋,如果有解釋的不清楚的地方可以在評論區(qū)交流。
import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector
from cvzone.PlotModule import LivePlot
cap = cv2.VideoCapture('BlinkCounter.mp4')#獲取需要檢測的視頻(添加視頻路徑即可,此處由于視頻和Python文件在同一路徑,直接調用即可)
detector = FaceMeshDetector(maxFaces = 1)#創(chuàng)建人臉網絡檢測器,檢測面部數(shù)量為1
plotY = LivePlot(640, 640, [20, 50], invert = True)#創(chuàng)建窗口來繪制數(shù)據的變化
idList = [22, 23, 24, 26, 110, 157, 158, 159, 160, 161, 130, 243]#面部檢測器中眼眶周圍的像素點
ratioList = []#創(chuàng)建一個空的比率列表
blinkCounter = 0
counter = 0#避免每一個幀節(jié)進行一次計數(shù)
color = (0, 0, 255)#將顏色設置為紅色
while True:
#------------------------------------------------------------
#檢查當前幀數(shù)是否等于視頻的總體幀數(shù),如果相等,將播放幀數(shù)重置為0
#------------------------------------------------------------
if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
success, img = cap.read()#讀取到的視頻
img, faces = detector.findFaceMesh(img, draw = False)#繪制人臉檢測網絡
#------------------------------------------------------------
#檢測到面部時將面部的關于眼眶的點用圓圈表示出來,并填補完整
#------------------------------------------------------------
if faces:
face = faces[0]
for id in idList:
cv2.circle(img, face[id], 5, color, cv2.FILLED)
#-------------------------------------------------------------
#使用眼眶周圍不同的點之間的距離以及眼睛寬度和長度的對比進行眨眼計數(shù)
#-------------------------------------------------------------
leftUp = face[159]#定義不同部位的像素點
leftDown = face[23]
leftLeft = face[130]
leftRight = face[243]
lenghtVer, _ = detector.findDistance(leftUp, leftDown)#得到眼睛寬度
lenghtHor, _ = detector.findDistance(leftLeft, leftRight)#得到眼睛長度
cv2.line(img, leftUp, leftDown, (0, 200, 0), 3)#繪制與眼睛等寬的線段
cv2.line(img, leftLeft, leftRight, (0, 200, 0), 3)#繪制與眼睛等長的線段
ratio = int((lenghtVer / lenghtHor) * 100)#得到的數(shù)據并進行標準化,得到比率值
ratioList.append(ratio)#使用比率值填補列表
#------------------------------------------------------------------
#從之前的一共三個比率中得到平均值,如果比率數(shù)目大于3將會刪去前面的比率值
#------------------------------------------------------------------
if len(ratioList) > 3:
ratioList.pop(0)
ratioAvg = sum(ratioList) / len(ratioList)#得到比率平均值
#------------------------------------
#通過比率平均值的變化對眨眼次數(shù)進行計數(shù)
#------------------------------------
if ratioAvg < 35 and counter == 0:
blinkCounter += 1#變化一次,計數(shù)器加一
color = (0, 200, 0)
counter = 1
if counter != 0:
counter += 1
if counter > 10:
counter = 0
color = (255, 0, 255)
#-----------------------------
#編寫文本框來記錄眨眼的總體次數(shù)
#------------------------------
cvzone.putTextRect(img, f'Blink Count: {blinkCounter}', (50, 250),
12, colorR = color)
imgPlot = plotY.update(ratioAvg, color)
img = cv2.resize(img, (400, 640)) # 對圖像尺寸進行調節(jié)
imgStack = cvzone.stackImages([img, imgPlot], 2, 1)#將兩幅圖像放到一起,疊放為2列圖像
else:
img = cv2.resize(img, (400, 640)) # 對圖像尺寸進行調節(jié)
imgStack = cvzone.stackImages([img, img], 2, 1)
img = cv2.resize(img, (400, 640)) #對圖像尺寸進行調節(jié)
cv2.imshow("Image", imgStack)
cv2.waitKey(1)
以上就是利用Python實現(xiàn)眨眼計數(shù)器的示例代碼的詳細內容,更多關于Python眨眼計數(shù)器的資料請關注腳本之家其它相關文章!
相關文章
Python實現(xiàn)Wordcloud生成詞云圖的示例
這篇文章主要介紹了Python實現(xiàn)Wordcloud生成詞云圖的示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-03-03
python 統(tǒng)計數(shù)組中元素出現(xiàn)次數(shù)并進行排序的實例
今天小編就為大家分享一篇python 統(tǒng)計數(shù)組中元素出現(xiàn)次數(shù)并進行排序的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07

