OpenCV 人臉檢測(二)
- 2019 年 10 月 7 日
- 筆記
本篇介紹在人臉檢測的基礎上對眼睛進行檢測。下面這個分類器用於檢測眼睛。
cv2.CascadeClassifier('./cascades/haarcascade_eye.xml')
除非是外星人,眼睛通常不會跑到臉部以外。所以我們只需在人臉矩形框的範圍內檢測眼睛。
以下圖為例,我們想以紅色矩形標記臉部區域,藍色矩形標記眼睛區域。

import cv2 import numpy as np from matplotlib import pyplot as plt def detect(img): gray =cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) front_face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')#檢測正臉 faces0 = front_face_cascade.detectMultiScale(gray, 1.1, 6) print("共檢測到%d張人的正臉" %len(faces0)) eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye.xml')#檢測眼睛 for (x, y, w, h) in faces0: eye_detected = False print(w,h) face_area = gray[y: y+h, x: x+w] # (疑似)人臉區域 #eyes = eye_cascade.detectMultiScale(face_area, 1.03, 5, 0, (40,40)) #在人臉區域檢測眼睛 eyes = eye_cascade.detectMultiScale(face_area, 1.03, 5, 0)#在人臉區域檢測眼睛 for (ex,ey,ew,eh) in eyes: print(" ",ew,eh) #if ew/w > 0.18: cv2.rectangle(img, (x+ex,y+ey),(x+ex+ew, y+ey+eh), (255,0,0),2) #畫藍色色矩形框標記正臉 eye_detected = True #if eye_detected: #排除掉檢測不到眼睛的 疑似人臉區域 cv2.rectangle(img, (x,y), (x+w,y+h), (0,0,255), 2) #畫紅色矩形框標記正臉 return img img0= cv2.imread("face.png") img = detect(img0) plt.subplot(1,1,1) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.title("OpenCV 人臉檢測",fontSize =16, color="b") plt.show()
檢測結果如下:

我們發現對於上圖,人臉和眼睛的檢測都產生了假陽性。花朵被檢測成了人臉,鼻子和嘴巴被誤認為是眼睛。
我們可以做簡單合理的假設,只有檢測出眼睛的疑似人臉區域才能被檢測為人臉,只有尺寸適中、位置偏人臉上部的疑似眼睛區域才能被識別成眼睛。按照上述原則我們對程式碼進行優化:
def detect(img): gray =cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) front_face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')#檢測正臉 faces0 = front_face_cascade.detectMultiScale(gray, 1.025, 5) eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye.xml')#檢測眼睛 n =0 for (x, y, w, h) in faces0: eye_detected = False face_area = gray[y: y+h, x: x+w] # (疑似)人臉區域 #eyes = eye_cascade.detectMultiScale(face_area, 1.03, 5, 0, (40,40)) #在人臉區域檢測眼睛 quasi_eyes = eye_cascade.detectMultiScale(face_area, 1.03, 5, 0)#在人臉區域檢測眼睛 if len(quasi_eyes) ==0: continue quasi_eyes = tuple(filter(lambda x : x[2]/w>0.18, quasi_eyes)) # ex,ey,ew,eh; ew/w>0.18 #尺寸過濾 if len(quasi_eyes) <2 : continue eyes = sorted(quasi_eyes, key=operator.itemgetter(1), reverse = False) # 排序,為了取ey最小的(頂部的)兩隻疑似眼睛 ex,ey,ew,eh = eyes[0] cv2.rectangle(img, (x+ex,y+ey),(x+ex+ew, y+ey+eh), (255,0,0),2) #畫藍色色矩形框標記第1隻眼睛 ex,ey,ew,eh = eyes[1] cv2.rectangle(img, (x+ex,y+ey),(x+ex+ew, y+ey+eh), (255,0,0),2) #畫藍色色矩形框標記第2隻眼睛 eye_detected = True if eye_detected: #排除掉檢測不到眼睛的 疑似人臉區域 cv2.rectangle(img, (x,y), (x+w,y+h), (0,0,255), 2) #畫紅色矩形框標記正臉 n += 1 print("共檢測到%d張人的正臉" % n) return img

兩隻眼睛一張臉,嗯,效果還不錯。
我們可以做更多的測試:



紅姑是側臉,沒檢測出來也符合程式碼的邏輯。

有人說人是從猴子變的,看來也不是沒有道理。。。

但是戴上眼鏡,程式就認不出了。很好解決,我們換個眼睛檢測的分類器即可:
eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye_tree_eyeglasses.xml')#檢測眼睛(可戴眼鏡)

下面兩個分類器可以單獨檢測影像的右眼和左眼,用法相同,不再贅述。
eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_righteye_2splits.xml')#檢測右邊的眼睛(人物左眼) eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_lefteye_2splits.xml')#檢測左邊的眼睛(人物右眼)