日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

如何用OpenCV在Python中实现人脸检测

發布時間:2024/9/15 python 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何用OpenCV在Python中实现人脸检测 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

選自towardsdatascience

作者:Ma?l Fabien

機器之心編譯

參與:高璇、張倩、淑婷

本教程將介紹如何使用 OpenCV 和 Dlib 在 Python 中創建和運行人臉檢測算法。同時還將添加一些功能,以同時檢測多個面部的眼睛和嘴巴。本文介紹了人臉檢測的最基本實現,包括級聯分類器、HOG 窗口和深度學習 CNN。

我們將通過以下方法實現人臉檢測:


  • 使用 OpenCV 的 Haar 級聯分類器

  • 使用 Dlib 的方向梯度直方圖

  • 使用 Dlib 的卷積神經網絡


本文代碼的 Github 庫(以及作者其他博客的代碼)鏈接:

https://github.com/maelfabien/Machine_Learning_Tutorials?


我們將使用用于計算機視覺的開源庫 OpenCV,它用 C/C++編寫,有 C++、Python 和 Java 接口。同時支持 Windows、Linux、MacOS、iOS 和 Android 系統。同時我們還需要工具包 Dlib,它是一個包含機器學習算法和創建復雜軟件的 C++工具包。


步驟


第一步是安裝 OpenCV 和 Dlib。運行以下命令:


pip?install?opencv-python
pip?install?dlib


文件生成的路徑如下(版本不同,路徑會稍有差別):


/usr/local/lib/python3.7/site-packages/cv2


如果在使用 Dlib 時出現問題,請參見文章:https://www.pyimagesearch.com/2018/01/22/install-dlib-easy-complete-guide/


導入工具包和模型路徑


創建一個新的 Jupyter notebook/Python 文件,從以下代碼開始:


import?cv2
import?matplotlib.pyplot?as?plt
import?dlib
from?imutils?import?face_utils
font?=?cv2.FONT_HERSHEY_SIMPLEX


級聯分類器


首先研究級聯分類器。


理論


級聯分類器,即使用類 Haar 特征工作的級聯增強分類器,是集成學習的一種特殊情況,稱為 boost。它通常依賴于 Adaboost 分類器(以及其他模型,如 Real Adaboost、Gentle Adaboost 或 Logitboost)。


級聯分類器在包含檢測目標的幾百個樣本圖像以及不包含檢測目標的其他圖像上進行訓練。


我們如何檢測圖上是否有人臉呢?有一種名為 Viola-Jones 的框架的算法,包括了實時人臉檢測所需的所有步驟:


  • 提取 Haar 特征,特征來自 Haar 小波

  • 創建圖像

  • Adaboost 訓練

  • 級聯分類器


Haar 特征選擇


人臉上最常見的一些共同特征如下:


  • 與臉頰相比,眼部顏色較深

  • 與眼睛相比,鼻梁區域較為明亮

  • 眼睛、嘴巴、鼻子的位置較為固定......


這些特征稱為 Haar 特征。過程如下所示:


Haar 特征


在上圖中,第一個特征測量眼部和上臉頰之間的強度差異。特征值計算的方法很簡單,對黑色區域中的像素求和再減去白色區域中的像素即可。


然后,將這個矩形作為卷積核作用到整個圖像。為了不產生遺漏,我們需要用到每個卷積核的所有的維度和位置。簡單的 24 * 24 的圖像可能會產生超過 160000 個特征,每個特征由像素值的和/差組成。這樣在計算上無法實現實時人臉檢測。那么,該如何加快這個過程呢?


一旦通過矩形框識別到有用區域,則在與之完全不同的區域上就無需再做計算了。這一點可以通過 Adaboost 實現。


使用積分圖像原理計算矩形框特征的方法更快。我們將在下一節介紹這一點。



原始論文中提到幾種可用于 Haar 特征提取的矩形框:


  • 雙矩形特征計算的是兩個矩形區域內像素和的差,主要用于檢測邊緣 (a,b)

  • 三矩形特征計算的是中心矩形和減去兩個外部矩形和的差,主要用于檢測線 (c,d)

  • 四矩形特征計算的是矩形對角線對之間的差 (e)


Haar 矩形


特征提取完成后,使用 Adaboost 分類器將它們應用于訓練集,該分類器結合了一組弱分類器來創建準確的集成模型。只需 200 個特征(最初是 16 萬個),實現了 95%的準確率。該論文的作者提取了 6000 個特征。


積分圖像


以卷積核的形式計算特征需要花費很長時間。出于這個原因,作者 Viola 和 Jones 提出了圖像的中間表示:積分圖像。積分圖像的作用是僅使用四個值簡單地計算矩形和。我們來看看它是如何工作的!


假設我們想要確定一個坐標為 (x,y) 的給定像素的矩形特征。然后,像素的積分圖像是給定像素的上方和左側的像素之和。

其中 ii(x,y) 是積分圖像,i(x,y) 是原始圖像。


當計算整個積分圖像時,有一種只需要遍歷一次原始圖像的遞歸方法。實際上,我們可以定義以下一對遞歸形式:

其中 s(x,y) 是累積行和,而 s(x?1)=0, ii(?1,y)=0。


這是怎么實現的呢?假設我們想要估算區域 D 的像素總和。我們已經定義了 3 個其他區域:A,B 和 C。


  • 點 1 處的積分圖像的值是矩形 A 中的像素的總和。

  • 點 2 處的值為 A + B。

  • 點 3 處的值為 A + C。

  • 點 4 處的值是 A + B + C + D。


因此,區域 D 中的像素之和可以簡單地計算為: 4+1?(2+3)。


這樣我們僅使用 4 個數組值就計算出了矩形 D 的值。



人們應該知道矩形在實際中是非常簡單的特征,但對于人臉檢測已經足夠了。當涉及復雜問題時,可調濾波器往往更靈活多變。


可調濾波器


使用 Adaboost 學習分類函數


給定一組帶標簽的訓練圖像(正負樣本均有),Adaboost 用于:


  • 提取一小部分特征

  • 訓練分類器


由于 16 萬個特征中的大多數特征與之極不相關,因此我們設計一個增強模型的弱學習算法,用來提取單個矩形特征,將最好的正負樣本區分開。

級聯分類器


雖然上述過程非常有效,但仍存在一個重大問題。在圖像中,大部分圖像為非面部區域。對圖像的每個區域給予等同的注意力是沒有意義的,因為我們應該主要關注最有可能包含人臉的區域。Viola 和 Jone 使用級聯分類器在減少了計算時間的同時,實現了更高的檢測率。


關鍵思想是在識別人臉區域時排除不含人臉的子窗口。由于任務是正確識別人臉,我們希望假陰率最小,即包含人臉卻未被識別的子窗口最少。


每個子窗口都使用一系列分類器。這些分類器是簡單的決策樹:


  • 如果第一個分類器檢測為正樣本,繼續用第二個

  • 如果第二個分類器檢測是正樣本,繼續用第三個

  • 以此類推


雖然有時可能包含人臉的圖被認成負樣本被子窗口漏檢。但初級分類器以較低的計算成本篩除了大多數負樣本,下圖的分類器可額外消除更多的負樣本,但需要更多的計算量。

使用 Adaboost 訓練分類器,并調整閾值使錯誤率降到最低。在訓練該模型時,變量如下:


  • 每個階段分類器數量

  • 每個階段的特征數量

  • 每個階段的閾值


幸運的是,在 OpenCV 中,整個模型已經經過預訓練,可直接用于人臉檢測。


如果想了解有關 Boosting 技術的更多信息,歡迎查看作者關于 Adaboost 的文章:

https://maelfabien.github.io/machinelearning/adaboost


輸入


下一步是找到預訓練的權重。我們將使用默認的預訓練模型來檢測人臉、眼睛和嘴巴。文件應位于此路徑(python 版本不同,路徑略有不同):


/usr/local/lib/python3.7/site-packages/cv2/data


確定路徑后,以此方式聲明級聯分類器:


cascPath?=?"/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_default.xml"
eyePath?=?"/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_eye.xml"
smilePath?=?"/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_smile.xml"
faceCascade?=?cv2.CascadeClassifier(cascPath)
eyeCascade?=?cv2.CascadeClassifier(eyePath)
smileCascade?=?cv2.CascadeClassifier(smilePath)


檢測圖像中的人臉


在實現實時人臉檢測算法之前,讓我們先嘗試在圖像上簡單檢測一下。從加載測試圖像開始:


#?Load?the?image
gray?=?cv2.imread('face_detect_test.jpeg',?0)
plt.figure(figsize=(12,8))
plt.imshow(gray,?cmap='gray')
plt.show()

測試圖像


然后開始檢測人臉,并將檢測到的人臉框起來。


#?Detect?faces
faces?=?faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
flags=cv2.CASCADE_SCALE_IMAGE
)
#?For?each?face
for?(x,?y,?w,?h)?in?faces:?
????#?Draw?rectangle?around?the?face
????cv2.rectangle(gray,?(x,?y),?(x+w,?y+h),?(255,?255,?255),?3)


以下是 detectMultiScale 函數常見的參數列表:


  • scaleFactor:確定每個圖像縮放比例大小。

  • minNeighbors:確定每個候選矩形應保留多少個相鄰框。

  • minSize:最小目標的大小。小于該值的目標將被忽略。

  • maxSize:最大目標的大小。大于該值的目標將被忽略。


最后,顯示結果:


plt.figure(figsize=(12,8))
plt.imshow(gray,?cmap='gray')
plt.show()


在測試圖像上成功檢測到人臉。現在開始實時檢測!


實時人臉檢測


下面繼續進行實時人臉檢測的 Python 實現。第一步是啟動攝像頭,并拍攝視頻。然后,將圖像轉換為灰度圖。這用于減小輸入圖像的維數。實際上,我們應用了一個簡單的線性變換,而不是每個像素用三個點來描述紅、綠、藍。


這在 OpenCV 中是默認實現的。


video_capture?=?cv2.VideoCapture(0)
while?True:
????#?Capture?frame-by-frame
????ret,?frame?=?video_capture.read()
????gray?=?cv2.cvtColor(frame,?cv2.COLOR_BGR2GRAY)


現在我們使用上述定義的 faceCascade 變量,它包含一個預訓練算法,現在將其用于灰度圖。


faces?=?faceCascade.detectMultiScale(
????????gray,
????????scaleFactor=1.1,
????????minNeighbors=5,
????????minSize=(30,?30),
????????flags=cv2.CASCADE_SCALE_IMAGE
????????)


對于檢測到的每個人臉,都加上一個矩形框:


for?(x,?y,?w,?h)?in?faces:
????????if?w?>?250?:
????????????cv2.rectangle(frame,?(x,?y),?(x+w,?y+h),?(255,?0,?0),?3)
????????????roi_gray?=?gray[y:y+h,?x:x+w]
????????????roi_color?=?frame[y:y+h,?x:x+w]


對于檢測到的每張嘴,都加上一個矩形框:


smile?=?smileCascade.detectMultiScale(
????????roi_gray,
????????scaleFactor=?1.16,
????????minNeighbors=35,
????????minSize=(25,?25),
????????flags=cv2.CASCADE_SCALE_IMAGE
????)
????for?(sx,?sy,?sw,?sh)?in?smile:
????????cv2.rectangle(roi_color,?(sh,?sy),?(sx+sw,?sy+sh),?(255,?0,?0),?2)
????????cv2.putText(frame,'Smile',(x?+?sx,y?+?sy),?1,?1,?(0,?255,?0),?1)


對于檢測到的每雙眼睛,都加上一個矩形框:


eyes?=?eyeCascade.detectMultiScale(roi_gray)
????for?(ex,ey,ew,eh)?in?eyes:
????????cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
????????cv2.putText(frame,'Eye',(x?+?ex,y?+?ey),?1,?1,?(0,?255,?0),?1)


然后計算人臉總數,顯示整體圖像:


cv2.putText(frame,'Number?of?Faces?:?'?+?str(len(faces)),(40,?40),?font,?1,(255,0,0),2)??????
????#?Display?the?resulting?frame
????cv2.imshow('Video',?frame)


當按下 q 鍵時,執行退出選項。


if?cv2.waitKey(1)?&?0xFF?==?ord('q'):
????????break


最后當所有操作完成后,關閉所有窗口。在 Mac 上關閉窗口存在一些問題,可能需要通過活動管理器退出 Python。


video_capture.release()
cv2.destroyAllWindows()


封裝


import?cv2

cascPath?=?"/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_default.xml"
eyePath?=?"/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_eye.xml"
smilePath?=?"/usr/local/lib/python3.7/site-packages/cv2/data/haarcascade_smile.xml"

faceCascade?=?cv2.CascadeClassifier(cascPath)
eyeCascade?=?cv2.CascadeClassifier(eyePath)
smileCascade?=?cv2.CascadeClassifier(smilePath)

font?=?cv2.FONT_HERSHEY_SIMPLEX
video_capture?=?cv2.VideoCapture(0)

while?True:
????#?Capture?frame-by-frame
????ret,?frame?=?video_capture.read()

????gray?=?cv2.cvtColor(frame,?cv2.COLOR_BGR2GRAY)

????faces?=?faceCascade.detectMultiScale(
????????gray,
????????scaleFactor=1.1,
????????minNeighbors=5,
????????minSize=(200,?200),
????????flags=cv2.CASCADE_SCALE_IMAGE
????)

????#?Draw?a?rectangle?around?the?faces
????for?(x,?y,?w,?h)?in?faces:
????????cv2.rectangle(frame,?(x,?y),?(x+w,?y+h),?(255,?0,?0),?3)
????????????roi_gray?=?gray[y:y+h,?x:x+w]
????????????roi_color?=?frame[y:y+h,?x:x+w]
????????????cv2.putText(frame,'Face',(x,?y),?font,?2,(255,0,0),5)

????smile?=?smileCascade.detectMultiScale(
????????roi_gray,
????????scaleFactor=?1.16,
????????minNeighbors=35,
????????minSize=(25,?25),
????????flags=cv2.CASCADE_SCALE_IMAGE
????)

????for?(sx,?sy,?sw,?sh)?in?smile:
????????cv2.rectangle(roi_color,?(sh,?sy),?(sx+sw,?sy+sh),?(255,?0,?0),?2)
????????cv2.putText(frame,'Smile',(x?+?sx,y?+?sy),?1,?1,?(0,?255,?0),?1)

????eyes?=?eyeCascade.detectMultiScale(roi_gray)
????for?(ex,ey,ew,eh)?in?eyes:
????????cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
????????cv2.putText(frame,'Eye',(x?+?ex,y?+?ey),?1,?1,?(0,?255,?0),?1)

????cv2.putText(frame,'Number?of?Faces?:?'?+?str(len(faces)),(40,?40),?font,?1,(255,0,0),2)??????
????#?Display?the?resulting?frame
????cv2.imshow('Video',?frame)

????if?cv2.waitKey(1)?&?0xFF?==?ord('q'):
??????break

#?When?everything?is?done,?release?the?capture
video_capture.release()
cv2.destroyAllWindows()


結果


我已經制作了人臉檢測算法的 YouTube 視頻演示:



Dlib 的方向梯度直方圖(HOG)


第二種常用的人臉檢測工具由 Dlib 提供,它使用了方向梯度直方圖(HOG)的概念。論文《Histograms of Oriented Gradients for Human Detection》實現這一方案。


理論


HOG 背后的想法是將特征提取到一個向量中,并將其輸入到分類算法中,例如支持向量機,它將評估人臉(或實際想識別的任何對象)是否存在于某個區域中。


提取的特征是圖像梯度(方向梯度)方向的分布(直方圖)。梯度通常在邊緣和角落周圍較大,并允許我們檢測這些區域。


在原始論文中,該算法用于人體檢測,檢測過程如下:



預處理


首先,輸入圖像必須尺寸相同(可通過裁剪和縮放)。圖像長寬比要求為 1:2,因此輸入圖像的尺寸可能為 64x128 或 100x200。


計算梯度圖像


第一步是通過以下卷積核計算圖像的水平梯度和垂直梯度:


計算梯度的卷積核


圖像的梯度通常會消除非必要信息。


上面圖像的梯度可以通過下面的 python 語句找到:


gray?=?cv2.imread('images/face_detect_test.jpeg',?0)
im?=?np.float32(gray)?/?255.0
#?Calculate?gradient?
gx?=?cv2.Sobel(im,?cv2.CV_32F,?1,?0,?ksize=1)
gy?=?cv2.Sobel(im,?cv2.CV_32F,?0,?1,?ksize=1)
mag,?angle?=?cv2.cartToPolar(gx,?gy,?angleInDegrees=True)


繪制圖片:


plt.figure(figsize=(12,8))
plt.imshow(mag)
plt.show()


我們之前沒有預處理圖像。


計算 HOG


首先將圖像分成 8x8 個單元來提供緊湊表示,使 HOG 對噪聲更魯棒。然后,計算每個單元的 HOG。


為了估計區域內的梯度方向,我們只需在每個區域內的 64 個梯度方向值(8x8)及其大小(另外 64 個值)之間構建直方圖。直方圖的類別對應梯度的角度,從 0 到 180°。總共 9 類:0°,20°,40°...... 160°。


上面的代碼給了我們 2 個信息:


  • 梯度方向

  • 梯度大小


當我們構建 HOG 時,有 3 種情況:


  • 角度小于 160°,且不介于兩類之間。在這種情況下,角度將添加到 HOG 的正確類中。

  • 角度小于 160°,恰好在兩類之間。在這種情況下,像素被均分到左右兩側類中。

  • 角度大于 160°。在這種情況下,我們認為像素與 160°和 0°成比例。



每個 8x8 單元的 HOG 如下所示:


HOG


模塊歸一化


最后,可以用 16×16 的模塊對圖像進行歸一化,并使其對光照不變。這可以通過將大小為 8x8 的 HOG 的每個值除以包含它的 16x16 模塊的 HOG 的 L2 范數來實現,這個模塊實際上是長度為 9*4 = 36 的簡單向量。


模塊歸一化


最后,將所有 36x1 向量連接成一個大向量。OK!現在有了特征向量,我們可以在上面訓練一個軟 SVM 分類器(C=0.01)。


檢測圖像上的人臉


實現非常簡單:


face_detect?=?dlib.get_frontal_face_detector()
rects?=?face_detect(gray,?1)
for?(i,?rect)?in?enumerate(rects):
(x,?y,?w,?h)?=?face_utils.rect_to_bb(rect)
????cv2.rectangle(gray,?(x,?y),?(x?+?w,?y?+?h),?(255,?255,?255),?3)

plt.figure(figsize=(12,8))
plt.imshow(gray,?cmap='gray')
plt.show()



實時人臉檢測


如前所述,該算法非常容易實現。我們還實現了一個更輕量的版本,只用來識別人臉。Dlib 讓人臉關鍵點的檢測更加容易,但這是另一個話題。


video_capture?=?cv2.VideoCapture(0)
flag?=?0

while?True:

????ret,?frame?=?video_capture.read()

????gray?=?cv2.cvtColor(frame,?cv2.COLOR_BGR2GRAY)
????rects?=?face_detect(gray,?1)

????for?(i,?rect)?in?enumerate(rects):

????????(x,?y,?w,?h)?=?face_utils.rect_to_bb(rect)

????????cv2.rectangle(frame,?(x,?y),?(x?+?w,?y?+?h),?(0,?255,?0),?2)

????????cv2.imshow('Video',?frame)

????if?cv2.waitKey(1)?&?0xFF?==?ord('q'):
????????break

video_capture.release()
cv2.destroyAllWindows()


Dlib 中的卷積神經網絡


最后一種方法基于卷積神經網絡。為了增強結果,它還實現了最大邊緣目標檢測(MMOD)。


理論


卷積神經網絡是主要用于計算機視覺的前饋神經網絡。它們提供自動圖像預處理以及密集的神經網絡部分。CNN 還是用來處理帶有網格狀拓撲的數據的特殊神經網絡。它的架構靈感來自動物視覺皮層。


以前的方法中,很大一部分工作是選擇濾波器來創建特征,以便盡從圖像中可能多地提取信息。隨著深度學習和計算能力的提高,這項工作現在可以實現自動化。CNN 的名稱就來自我們用一組濾波器卷積初始圖像輸入的事實。需要選擇的參數仍是需要應用的濾波器數量以及尺寸。濾波器的尺寸稱為步幅。一般步幅設置在 2 到 5 之間。


在這種特定情況下,CNN 的輸出是二分類,如果有人臉,則取值 1,否則取 0。


檢測圖像上的人臉


一些元素在實現中會發生變化。


第一步是下載預訓練模型:https://github.com/davisking/dlib-models/blob/master/mmod_human_face_detector.dat.bz2


?將下載后的權重放到文件夾中,并定義 dnnDaceDetector:


dnnFaceDetector?=?dlib.cnn_face_detection_model_v1("mmod_human_face_detector.dat"


然后,與之前做的相同:


rects?=?dnnFaceDetector(gray,?1)
for?(i,?rect)?in?enumerate(rects):
????x1?=?rect.rect.left()
????y1?=?rect.rect.top()
????x2?=?rect.rect.right()
????y2?=?rect.rect.bottom()
????#?Rectangle?around?the?face
????cv2.rectangle(gray,?(x1,?y1),?(x2,?y2),?(255,?255,?255),?3)
plt.figure(figsize=(12,8))
plt.imshow(gray,?cmap='gray')
plt.show()

實時人臉檢測


最后,實現實時 CNN 人臉檢測:


video_capture?=?cv2.VideoCapture(0)
flag?=?0

while?True:
????#?Capture?frame-by-frame
????ret,?frame?=?video_capture.read()

????gray?=?cv2.cvtColor(frame,?cv2.COLOR_BGR2GRAY)
????rects?=?dnnFaceDetector(gray,?1)

????for?(i,?rect)?in?enumerate(rects):

????????x1?=?rect.rect.left()
????????y1?=?rect.rect.top()
????????x2?=?rect.rect.right()
????????y2?=?rect.rect.bottom()

????????#?Rectangle?around?the?face
????????cv2.rectangle(frame,?(x1,?y1),?(x2,?y2),?(0,?255,?0),?2)

????#?Display?the?video?output
????cv2.imshow('Video',?frame)

????#?Quit?video?by?typing?Q
????if?cv2.waitKey(1)?&?0xFF?==?ord('q'):
????????break

video_capture.release()
cv2.destroyAllWindows()


如何選擇模型


這是一個很難回答的問題,但我們只討論兩個重要指標:


  • 計算時間

  • 準確率


在速度方面,HOG 是最快的算法,其次是 Haar 級聯分類器和 CNN。


但是,Dlib 中的 CNN 是準確率最高的算法。HOG 表現也很好,但在識別較小的人臉時會有一些問題。Haar 級聯分類器的整體表現與 HOG 相似。


考慮到實時人臉檢測的速度,我在個人項目中使用了 HOG。


希望這個關于 OpenCV 和 Dlib 的人臉檢測的快速教程能對你有所幫助。


原文鏈接:https://towardsdatascience.com/a-guide-to-face-detection-in-python-3eab0f6b9fc1

總結

以上是生活随笔為你收集整理的如何用OpenCV在Python中实现人脸检测的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。