### 使用 OpenCV 進行臉部識別 :::success 1. 要進行特定圖像辨識最重要的是要有『識別對象特徵檔』。 2. OpenCV 已內建臉部識別特徵檔,只要使用 OpenCV 的CascadeClassifier 類別即可識別臉部。 ::: <font color='red'>記得安裝相關套件: </font> pip install opencv-contrib-python --- ### 建立CascadeClassifier 物件 :::success 識別物件變數 = cv2.CascadeClassifier(識別檔路徑) ::: <font color='red'>可將套件cv2下data目錄複製到您的專案中,比較不會出錯</font> --- 加入識別檔路徑 ```python=1 import cv2 # 識別檔路徑: 當未在專案中加入識別檔路徑要在各自電腦中找出其位置 xmlFile = ''' C:\\Users\\電腦名稱\\anaconda3\\Lib\\site-packages\\cv2\\data\\haarcascade_frontalface_default.xml ''' # 當已在專案中加入識別檔路徑 xmlFile = 'data/haarcascade_frontalface_default.xml' # 建立識別物件 faceCascade = cv2.CascadeClassifier(xmlFile) ``` --- ### 偵測識別結果物件 :::success 識別結果變數 = 識別物件變數.detectMultiScale(圖片, 參數1, ....) ::: 1. 使用識別物件的 detectMultiScale()就能取得識別結果,如臉部識別 2. detectMultiScale()傳回串列,包含識別圖片中多張臉部資訊 3. 串列元素是由臉部圖形左上角(x座標, y座標, 臉部寬度, 臉部高度)所組成 for (x,y,w,h) in faces: --- ## 標識人臉及眼睛位置(一) :::success 1. 標識出圖片中臉部位置 2. 在左下角顯示辨識出臉部的數量 ::: ---- 設定辨識檔路徑與要識別的檔案 ```python=1 import cv2 # 設定人臉識別檔路徑 facePath = "data/haarcascade_frontalface_default.xml" # 設定眼睛識別檔路徑 eyePath = "data/haarcascade_eye.xml" # 建立人臉識別CascadeClassifier 物件 face_cascade = cv2.CascadeClassifier(facePath) # 建立眼睛識別CascadeClassifier 物件 eye_cascade = cv2.CascadeClassifier(eyePath) # 讀取要識別的圖片 #frame = cv2.imread("images/students.jpg") frame = cv2.imread("images/obamafamily.jpg") #frame = cv2.imread("images/face.jpg") ``` ---- ##### 標識人臉及眼睛位置(二) ```python=1 # 取得人臉識別結果變數 faces = face_cascade.detectMultiScale( frame, # 要識別的圖檔 scaleFactor=1.1, # 區塊的改變倍數為1.1倍 minNeighbors=5, # 成功取得特徵須達到5次 minSize=(10,10), # 最小辨識區為10x10 flags=cv2.CASCADE_SCALE_IMAGE # 按比例正常檢測 ) ``` ---- ##### 標識人臉及眼睛位置(三) ```python=1 # 在圖片中顯示相關文字 # frame.shape[0]為圖片高度、frame.shape[1]為圖片寬度 cv2.putText( frame, # 要顯示文字的圖片 "Find " + str(len(faces)) + " face!", # 要顯示的文字 (10, frame.shape[0] - 5), # 要顯示文字的位置 cv2.FONT_HERSHEY_SIMPLEX, # 要使用的字型 0.5, # 字體尺寸 (255,255,255), # 文字顏色 2 # 文字外框粗細 ) ``` ---- ##### 標識人臉及眼睛位置(四) ```python=1 # 依序取得人臉識別結果變數內容 # (x, y): 左上角座標、(w, h): 寬度與高度 for (x, y, w, h) in faces: # 計算中心點座標 center = (x + w//2, y + h//2) # 以圖片中心點為圓心在圖片中繪製橢圓形 #cv2.ellipse(frame, center, (w//2, h//2), 0, 0, 360, (255, 0, 255), 4) cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2) # 取得圖片中Region Of Interest(有興趣的區域: 人臉)後儲存為圖片faceROI faceROI = frame[y : y+h, x : x+w] # 取得眼睛識別結果變數 eyes = eye_cascade.detectMultiScale(faceROI) # 依序取得眼睛識別結果變數內容 # (x, y): 左上角座標、(w, h): 寬度與高度 for (x2, y2, w2, h2) in eyes: # 計算眼睛中心點座標 eye_center = (x + x2 + w2//2, y + y2 + h2//2) # 計算半徑 radius = int(round((w2 + h2)*0.25)) # 以眼睛中心點繪製圓形 frame = cv2.circle(frame, eye_center, radius, (255, 0, 0 ), 4) ``` ---- ##### 標識人臉及眼睛位置(五) ```python=1 # 在視窗中顯示frame圖片 cv2.imshow("FaceDetect", frame) # 等待使用者按下任意鍵後繼續 cv2.waitKey(0) # 關閉圖形顯示視窗 cv2.destroyWindow("FaceDetect") ``` <!-- ## Tello Face Tracking(一) ```python=1 import cv2 import numpy as np import TelloActions as action import threading import time ##### Video Stream UDP Address ##### VS_UDP_IP = '0.0.0.0' VS_UDP_PORT = 11111 tello_cap_address = f'udp://{VS_UDP_IP}:{VS_UDP_PORT}' #print(tello_cap_address) ``` ## Tello Face Tracking(二) ```python=1 ##### Other Parameters ####### # 圖片大小 w, h = 360, 240 # 圖片 大小 範圍(最小為6200, 最大6800) fbRange = [6200, 6800] # PID 控制 pid = [0.4, 0.4, 0] # PID 的 Error pError = 0 ``` ## Tello Face Tracking(三) ```python=1 #### 建立讀取影像的類別,採用多執行緒的方式 class TelloCapture: def __init__(self, address): self.frame = [] self.status = False self.stop = False self.cap = cv2.VideoCapture(address) def start(self): print('Tello Capture Started!') threading.Thread(target=self.queryFrame, daemon=True, args=()).start() def stop(self): self.stop=True print('Tello Capture Stopped!') def queryFrame(self): while not self.stop: self.status, self.frame = self.cap.read() self.cap.release() def getFrame(self): return self.frame.copy() ``` ## Tello Face Tracking(四) ```python=1 def findFace(img): faceCascade = cv2.CascadeClassifier('data/haarcascade_frontalface_alt2.xml') imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = faceCascade.detectMultiScale(imgGray, 1.1, 5) # 紀錄 圖片中心點位置 faceListCenter = [] # 紀錄 圖片 大小 faceListSize = [] for (x, y, w, h) in faces: cv2.rectangle(img, (x, y), (x+w, y+h), (0, 0, 255), 2) cx = x+w//2; cy = y+h//2; area = w*h faceListCenter.append([cx, cy]) faceListSize.append(area) cv2.circle(img, (cx, cy), 5, (0, 255, 0), cv2.FILLED) if len(faceListSize)!=0: # 取出最大圖片的索引 idx = faceListSize.index(max(faceListSize)) # 回傳 繪製的圖, 最大圖的中心點座標, 最大圖的大小 return img, [faceListCenter[idx], faceListSize[idx]] else: return img, [[0, 0], 0] ``` ## Tello Face Tracking(五) ```python=1 def trackFace(info, w, pid, pError): # 圖片大小 area = info[1] # 中心點 x, y = info[0] # 前進後退的飛行值 fb = 0 # 中心點與目前位置的差距 error = x- w//2 # PID 控制 yaw 角度 speed = pid[0]*error + pid[1]*(error-pError) # 將 speed 控制在 -100 到 100 之間的整數 speed = int(np.clip(speed, -100, 100)) # 當 圖片大小在範圍內不調整 if area > fbRange[0] and area < fbRange[1]: fb = 0 # 距離太近,往後 elif area > fbRange[1]: fb = -20 # 距離太遠,往前 elif area < fbRange[0] and area!=0: fb = 20 # 當x在中心時,維持原狀態 if x==0: speed = 0; error=0 # 送出控制信號 action.send_rc_control(0, fb, 0, speed) # 目前的error,作為下次PID運算的pError return error ``` ## Tello Face Tracking(六) ```python=1 def main(): global pError action.connect(1) action.streamon() cap = TelloCapture(tello_cap_address) cap.start() time.sleep(1) action.takeoff(5) while True: frame = cap.getFrame() frame = cv2.resize(frame, (w, h)) frame, info = findFace(frame) pError = trackFace(info, w, pid, pError) cv2.imshow('Output', frame) if cv2.waitKey(1) & 0xff == ord('q'): action.land() break cap.stop() cv2.destroyAllWindows() action.land() action.end() if __name__ == '__main__': main() ``` -->
{"metaMigratedAt":"2023-06-16T06:29:39.068Z","metaMigratedFrom":"YAML","title":"OpenCV 人臉識別","breaks":true,"contributors":"[{\"id\":\"240c1e7c-1eda-461f-8d55-5a4f00e12992\",\"add\":8974,\"del\":2325}]"}
    1193 views