dlib
安裝方法 之前博文 https://blog.csdn.net/weixin_44634704/article/details/141332644
環境:
python==3.8
opencv-python==4.11.0.86
face_recognition==1.3.0
dlib==19.24.6
人臉檢測
import cv2
import face_recognition# 讀取人臉圖片
img = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
face_List = face_recognition.face_locations(img) # 檢測人臉,返回人臉坐標信息
print(face_List)for x in face_List: # 畫框cv2.rectangle(img, (x[3], x[0]), (x[1], x[2]), (0, 255, 0), 2)
cv2.imshow("a", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 輸出: [(116, 306, 223, 199)]
人臉分割(切割)
import cv2
import face_recognition# 讀取人臉圖片
img = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
face_List = face_recognition.face_locations(img) # 檢測人臉,返回人臉坐標信息
print(face_List)for x in face_List: # 畫框cv2.rectangle(img, (x[3], x[0]), (x[1], x[2]), (0, 255, 0), 2)qie_img = img[x[0]:x[2], x[3]:x[1]]cv2.imshow("a", qie_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
提取人臉特征向量
img = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
# 提取人臉特征向量
face01 = face_recognition.face_encodings(img)[0]
print(face01)
人臉比對(歐式距離)
import cv2
import face_recognition
import numpy as np# 讀取人臉圖片
img = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # face_recognition庫,處理是RGB格式, CV默認為BGR
# 提取人臉特征向量
face01 = face_recognition.face_encodings(img)[0]
# 讀取人臉原圖的圖片
img2 = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
face02 = face_recognition.face_encodings(img2)[0]
#
# 計算歐幾里得距離
v = np.linalg.norm(face01 - face02)
if v < 0.8:print("是一個人")
else:print("不是一個人")
轉為置信度
import cv2
import face_recognition
import numpy as npdef euclidean_distance_to_confidence(distance, max_distance):# 確保距離在合理范圍內distance = min(distance, max_distance)# 計算置信度confidence = 1 - (distance / max_distance)return confidence# 讀取人臉圖片
img = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # face_recognition庫,處理是RGB格式, CV默認為BGR
# 提取人臉特征向量
face01 = face_recognition.face_encodings(img)[0]
# 讀取人臉原圖的圖片
img2 = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
face02 = face_recognition.face_encodings(img2)[0]
#
# 計算歐幾里得距離
v = np.linalg.norm(face01 - face02)
w = euclidean_distance_to_confidence(v, 1) # 置信度最大閾值為1
print(w) # 計算置信度,距離越小,置信度越高。
人臉比對(余弦)
import cv2
import face_recognition
import numpy as npdef cosine_similarity_to_confidence(similarity):# 將余弦相似度從 [-1, 1] 映射到 [0, 1]confidence = (similarity + 1) / 2return confidence# 讀取人臉圖片
img = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # face_recognition庫,處理是RGB格式, CV默認為BGR
# 提取人臉特征向量
face01 = face_recognition.face_encodings(img)[0]
# 讀取人臉原圖的圖片
img2 = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
face02 = face_recognition.face_encodings(img2)[0]
#
dot_product = np.dot(face01, face02)
norm_face01 = np.linalg.norm(face01)
norm_face02 = np.linalg.norm(face02)
similarity = dot_product / (norm_face01 * norm_face02)
print("余弦相似度:", similarity)
confidence = cosine_similarity_to_confidence(similarity)
print("置信度:", confidence)
繪制眼睛,嘴巴,鼻子,輪廓線條
import cv2
import face_recognition
import numpy as np# 讀取人臉圖片
img = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # face_recognition庫,處理是RGB格式, CV默認為BGR#img = face_recognition.load_image_file("face.jpg")
face_landmarks = face_recognition.face_landmarks(img)# 把特征點都畫出來
for landmarks in face_landmarks:print(landmarks)# 畫眼睛for eye in ('left_eye', 'right_eye'):pts = np.array(landmarks[eye], np.int32)cv2.polylines(img, (pts,), True, (0, 255, 0), 2)# 畫嘴巴mouth_pts = np.array(landmarks['top_lip'], np.int32)cv2.polylines(img, (mouth_pts,), True, (0, 0, 255), 2)# 畫鼻子nose_pts = np.array(landmarks['nose_bridge'], np.int32)cv2.polylines(img, (nose_pts,), True, (255, 0, 0), 2)# 繪制臉部輪廓chin_pts = np.array(landmarks['chin'], np.int32)cv2.polylines(img, [chin_pts], False, (255, 255, 0), 2)cv2.imwrite("landmarks.jpg", img[:, :, ::-1])
在 face_recognition
庫檢測出的人臉特征點中,默認是不包含耳朵特征點的。這是因為在很多常見的人臉識別應用場景里,耳朵的特征穩定性和獨特性相對較弱,所以庫沒有專門對耳朵的特征點進行檢測。
不過,要是你想要標記耳朵位置,可以考慮使用更高級的人臉關鍵點檢測模型,像 dlib
庫提供的 68 點或者 81 點人臉關鍵點檢測器,其中 81 點模型包含了耳朵相關的關鍵點。
import cv2
import dlib
import numpy as np# 加載 dlib 的人臉檢測器和 81 點關鍵點預測器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_81_face_landmarks.dat")# 讀取圖片
image = cv2.imread(r"C:\Users\123\Desktop\1.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 檢測人臉
faces = detector(gray)for face in faces:# 檢測關鍵點landmarks = predictor(gray, face)# 繪制眼睛left_eye_points = [(landmarks.part(n).x, landmarks.part(n).y) for n in range(36, 42)]right_eye_points = [(landmarks.part(n).x, landmarks.part(n).y) for n in range(42, 48)]for eye_points in [left_eye_points, right_eye_points]:pts = np.array(eye_points, np.int32)cv2.polylines(image, [pts], True, (0, 255, 0), 2)# 繪制嘴巴mouth_points = [(landmarks.part(n).x, landmarks.part(n).y) for n in range(48, 60)]pts = np.array(mouth_points, np.int32)cv2.polylines(image, [pts], True, (0, 0, 255), 2)# 繪制鼻子nose_points = [(landmarks.part(n).x, landmarks.part(n).y) for n in range(27, 36)]pts = np.array(nose_points, np.int32)cv2.polylines(image, [pts], True, (255, 0, 0), 2)# 繪制臉部輪廓chin_points = [(landmarks.part(n).x, landmarks.part(n).y) for n in range(0, 17)]pts = np.array(chin_points, np.int32)cv2.polylines(image, [pts], False, (255, 255, 0), 2)# 繪制耳朵left_ear_points = [(landmarks.part(n).x, landmarks.part(n).y) for n in range(71, 75)]right_ear_points = [(landmarks.part(n).x, landmarks.part(n).y) for n in range(75, 79)]for ear_points in [left_ear_points, right_ear_points]:pts = np.array(ear_points, np.int32)cv2.polylines(image, [pts], False, (0, 255, 255), 2)# 保存圖片
cv2.imwrite("landmarks.jpg", image)
實時取攝像頭繪制
import numpy as np
import cv2
import face_recognition# 打開攝像頭
video_capture = cv2.VideoCapture(0)while True:# 讀取一幀視頻ret, frame = video_capture.read()# 將圖像從BGR顏色空間轉換為RGB顏色空間,因為face_recognition庫使用RGB格式rgb_frame = frame[:, :, ::-1]# 檢測人臉特征點face_landmarks_list = face_recognition.face_landmarks(rgb_frame)# for face_landmarks in face_landmarks_list:# # 打印所有特征點類型及其對應的關鍵點坐標# for facial_feature in face_landmarks.keys():# print(f"{facial_feature}: {face_landmarks[facial_feature]}")for face_landmarks in face_landmarks_list:# 繪制臉部輪廓chin_points = face_landmarks['chin']pts = [tuple(point) for point in chin_points]pts = np.array(pts, np.int32)cv2.polylines(frame, [pts], False, (255, 255, 0), 2)# 繪制眼睛for eye in ('left_eye', 'right_eye'):eye_points = face_landmarks[eye]pts = [tuple(point) for point in eye_points]pts = np.array(pts, np.int32)cv2.polylines(frame, [pts], True, (0, 255, 0), 2)# 繪制左右眉毛for eyebrow in ('left_eyebrow', 'right_eyebrow'):eyebrow_points = face_landmarks[eyebrow]eyebrow_pts = np.array(eyebrow_points, np.int32)cv2.polylines(frame, [eyebrow_pts], False, (255, 0, 255), 2)# 上嘴唇mouth_pts = np.array(face_landmarks['top_lip'], np.int32)cv2.polylines(frame, (mouth_pts,), True, (0, 0, 255), 2)# 下嘴唇bottom_lip_points = face_landmarks['bottom_lip']bottom_lip_pts = np.array(bottom_lip_points, np.int32)cv2.polylines(frame, [bottom_lip_pts], True, (0, 0, 255), 2)# 繪制鼻子代表鼻梁部分的關鍵點nose_bridge_points = face_landmarks['nose_bridge']pts = [tuple(point) for point in nose_bridge_points]pts = np.array(pts, np.int32)cv2.polylines(frame, [pts], True, (255, 0, 0), 2)# 繪制鼻尖nose_tip_points = face_landmarks['nose_tip']nose_tip_pts = np.array(nose_tip_points, np.int32)cv2.polylines(frame, [nose_tip_pts], True, (0, 255, 255), 2)# 顯示結果圖像cv2.imshow('Video', frame)# 按 'q' 鍵退出循環if cv2.waitKey(1) & 0xFF == ord('q'):break# 釋放攝像頭并關閉所有窗口
video_capture.release()
cv2.destroyAllWindows()
活體檢測
import cv2
import face_recognition
import numpy as np# 計算眼睛的縱橫比
def eye_aspect_ratio(eye):A = np.linalg.norm(np.array(eye[1]) - np.array(eye[5]))B = np.linalg.norm(np.array(eye[2]) - np.array(eye[4]))C = np.linalg.norm(np.array(eye[0]) - np.array(eye[3]))ear = (A + B) / (2.0 * C)return ear# 計算嘴巴的縱橫比
def mouth_aspect_ratio(mouth):# 重新選擇特征點top_mid = (np.array(mouth[2]) + np.array(mouth[3])) // 2bottom_mid = (np.array(mouth[10]) + np.array(mouth[11])) // 2left = np.array(mouth[0])right = np.array(mouth[6])A = np.linalg.norm(top_mid - bottom_mid)C = np.linalg.norm(left - right)mar = A / Creturn mar# 初始化變量
EYE_AR_THRESH = 0.2 # 眼睛縱橫比閾值
EYE_AR_CONSEC_FRAMES = 3 # 連續閉眼幀數閾值
COUNTER_EYE = 0 # 連續閉眼幀數計數器
TOTAL_EYE = 0 # 眨眼次數計數器MOUTH_AR_CONSEC_FRAMES = 3 # 連續張嘴幀數閾值
COUNTER_MOUTH = 0 # 連續張嘴幀數計數器
TOTAL_MOUTH = 0 # 張嘴次數計數器PREVIOUS_LANDMARKS = None # 上一幀的人臉特征點
HEAD_MOTION_THRESH = 10 # 頭部運動閾值
HEAD_MOTION = False # 頭部是否移動標志# 動態閾值相關變量
INITIAL_FRAMES = 10 # 用于確定初始閾值的幀數
initial_mar_values = []
MOUTH_AR_THRESH = None# 打開攝像頭
video_capture = cv2.VideoCapture(0)frame_count = 0
while True:# 讀取一幀視頻ret, frame = video_capture.read()# 將圖像從 BGR 顏色空間轉換為 RGB 顏色空間rgb_frame = frame[:, :, ::-1]# 檢測人臉特征點face_landmarks_list = face_recognition.face_landmarks(rgb_frame)for face_landmarks in face_landmarks_list:# 提取左右眼睛的特征點left_eye = face_landmarks['left_eye']right_eye = face_landmarks['right_eye']# 計算左右眼睛的縱橫比left_ear = eye_aspect_ratio(left_eye)right_ear = eye_aspect_ratio(right_eye)# 計算平均縱橫比ear = (left_ear + right_ear) / 2.0# 檢測眨眼if ear < EYE_AR_THRESH:COUNTER_EYE += 1else:if COUNTER_EYE >= EYE_AR_CONSEC_FRAMES:TOTAL_EYE += 1COUNTER_EYE = 0# 提取嘴巴的特征點mouth = face_landmarks['top_lip'] + face_landmarks['bottom_lip']# 計算嘴巴的縱橫比mar = mouth_aspect_ratio(mouth)print(f"嘴巴縱橫比: {mar}") # 打印嘴巴縱橫比,用于調試# 動態確定嘴巴縱橫比閾值if frame_count < INITIAL_FRAMES:initial_mar_values.append(mar)if frame_count == INITIAL_FRAMES - 1:MOUTH_AR_THRESH = np.mean(initial_mar_values) * 1.2 # 閾值設為初始平均值的 1.2 倍else:# 檢測張嘴if mar > MOUTH_AR_THRESH:COUNTER_MOUTH += 1else:if COUNTER_MOUTH >= MOUTH_AR_CONSEC_FRAMES:TOTAL_MOUTH += 1COUNTER_MOUTH = 0# 檢測頭部運動if PREVIOUS_LANDMARKS is not None:current_landmarks = []for feature in face_landmarks.values():current_landmarks.extend(feature)current_landmarks = np.array(current_landmarks)previous_landmarks = []for feature in PREVIOUS_LANDMARKS.values():previous_landmarks.extend(feature)previous_landmarks = np.array(previous_landmarks)displacement = np.linalg.norm(current_landmarks - previous_landmarks)if displacement > HEAD_MOTION_THRESH:HEAD_MOTION = Trueelse:HEAD_MOTION = FalsePREVIOUS_LANDMARKS = face_landmarks# 在圖像上顯示眨眼次數、張嘴次數和頭部是否移動cv2.putText(frame, f"Blinks: {TOTAL_EYE}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)cv2.putText(frame, f"Opens: {TOTAL_MOUTH}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)cv2.putText(frame, f"Head Motion: {'Yes' if HEAD_MOTION else 'No'}", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)# 顯示結果圖像cv2.imshow('Video', frame)frame_count += 1# 按 'q' 鍵退出循環if cv2.waitKey(1) & 0xFF == ord('q'):break# 釋放攝像頭并關閉所有窗口
video_capture.release()
cv2.destroyAllWindows()