import cv2
|
import dlib
|
import os
|
import numpy as np
|
|
# 计算眼睛纵横比
|
def eye_aspect_ratio(eye):
|
A = np.linalg.norm(eye[1] - eye[5])
|
B = np.linalg.norm(eye[2] - eye[4])
|
C = np.linalg.norm(eye[0] - eye[3])
|
ear = (A + B) / (2.0 * C)
|
return ear
|
|
# 检测头部运动(简单示例,可根据实际情况优化)
|
def detect_head_movement(prev_face_landmarks, face_landmarks):
|
if prev_face_landmarks is None:
|
return False
|
prev_nose = prev_face_landmarks[30]
|
current_nose = face_landmarks[30]
|
movement_threshold = 10 # 调整阈值
|
return abs(current_nose[0] - prev_nose[0]) > movement_threshold or abs(
|
current_nose[1] - prev_nose[1]
|
) > movement_threshold
|
|
# 直接指定路径和参数
|
input_path = None # 如果需要从文件读取可以指定路径,这里设为None表示使用摄像头
|
# 使用原始字符串来定义路径,避免转义问题
|
output_path = r"H:\python_charm\python_project\database"
|
detector_path = r"H:\python_charm\python_project\face_detector"
|
confidence = 0.5
|
|
# 加载人脸检测模型
|
print("[INFO] loading face detector...")
|
protoPath = os.path.sep.join([detector_path, "deploy.prototxt"])
|
modelPath = os.path.sep.join([detector_path, "res10_300x300_ssd_iter_140000.caffemodel"])
|
net = cv2.dnn.readNetFromCaffe(protoPath, modelPath)
|
|
# 创建输出目录
|
if not os.path.exists(output_path):
|
os.makedirs(output_path)
|
real_output_dir = os.path.join(output_path, "real")
|
fake_output_dir = os.path.join(output_path, "fake")
|
if not os.path.exists(real_output_dir):
|
os.makedirs(real_output_dir)
|
if not os.path.exists(fake_output_dir):
|
os.makedirs(fake_output_dir)
|
|
# 初始化dlib的面部关键点检测器
|
detector = dlib.get_frontal_face_detector()
|
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
|
|
# 初始化参数
|
EYE_AR_THRESH = 0.3
|
EYE_AR_CONSEC_FRAMES = 3
|
COUNTER = 0
|
TOTAL = 0
|
prev_face_landmarks = None
|
has_shaken_head = False
|
has_blinked = False
|
saved_fake = 0
|
saved_real = 0
|
# 各自采集500张
|
target_count = 500
|
# 新增标志变量,用于记录是否正在连续采集
|
is_continuous_capturing = False
|
capture_type = None # 记录当前采集的类型('real' 或 'fake')
|
|
# 打开摄像头
|
cap = cv2.VideoCapture(0)
|
|
print("[INFO] Automatically taking pictures...")
|
|
while True:
|
ret, frame = cap.read()
|
if not ret:
|
break
|
|
(h, w) = frame.shape[:2]
|
blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0,
|
(300, 300), (104.0, 177.0, 123.0))
|
net.setInput(blob)
|
detections = net.forward()
|
|
# 检测到的人脸
|
if len(detections) > 0:
|
i = np.argmax(detections[0, 0, :, 2])
|
detection_confidence = detections[0, 0, i, 2] # 重命名变量,避免混淆
|
|
if detection_confidence > confidence:
|
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
|
(startX, startY, endX, endY) = box.astype("int")
|
|
# 提取面部关键点
|
rect = dlib.rectangle(int(startX), int(startY), int(endX), int(endY))
|
face_landmarks = predictor(frame, rect)
|
face_landmarks = np.array([[part.x, part.y] for part in face_landmarks.parts()])
|
|
# 检测头部运动
|
has_shaken_head = has_shaken_head or detect_head_movement(prev_face_landmarks, face_landmarks)
|
prev_face_landmarks = face_landmarks
|
|
# 检测眨眼动作
|
left_eye = face_landmarks[42:48]
|
right_eye = face_landmarks[36:42]
|
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 += 1
|
else:
|
if COUNTER >= EYE_AR_CONSEC_FRAMES:
|
TOTAL += 1
|
has_blinked = has_blinked or True
|
COUNTER = 0
|
|
# 保存人脸区域
|
face = frame[startY:endY, startX:endX]
|
|
if is_continuous_capturing:
|
if capture_type == "real":
|
label = "real"
|
saved = saved_real
|
output_dir = real_output_dir
|
else:
|
label = "fake"
|
saved = saved_fake
|
output_dir = fake_output_dir
|
|
p = os.path.sep.join([output_dir, f"{label}_{saved}.png"])
|
cv2.imwrite(p, face)
|
print(f"[INFO] saved {p} to disk")
|
|
if label == "fake":
|
saved_fake += 1
|
else:
|
saved_real += 1
|
|
if (capture_type == "real" and saved_real >= target_count) or \
|
(capture_type == "fake" and saved_fake >= target_count):
|
is_continuous_capturing = False
|
print(f"[INFO] Reached the target count for {capture_type} images.")
|
else:
|
print("[INFO] Please enter 'r' for real or 'f' for fake (q to quit): ")
|
key = cv2.waitKey(0) & 0xFF
|
if key == ord("r"):
|
if saved_real < target_count:
|
is_continuous_capturing = True
|
capture_type = "real"
|
else:
|
print("[INFO] Already reached the target count for real images. Skipping.")
|
elif key == ord("f"):
|
if saved_fake < target_count:
|
is_continuous_capturing = True
|
capture_type = "fake"
|
else:
|
print("[INFO] Already reached the target count for fake images. Skipping.")
|
elif key == ord("q"):
|
break
|
|
# 显示画面
|
cv2.imshow("Frame", frame)
|
|
key = cv2.waitKey(1) & 0xFF
|
if key == ord("q"):
|
break
|
|
# 当真实和虚假图片都采集到500张时结束
|
if saved_fake >= target_count and saved_real >= target_count:
|
print("[INFO] Reached the target count for both real and fake images. Exiting...")
|
break
|
|
cap.release()
|
cv2.destroyAllWindows()
|