今天我想分享一个基于深度学习的人脸检测与识别系统的完整实现方案。这个项目结合了MTCNN人脸检测和FaceNet人脸识别两大核心技术,能够从图片中准确找出人脸位置,并判断不同图片中的人脸是否属于同一个人。
在实际应用中,这类系统可以用于门禁控制、考勤系统、照片分类等多种场景。我选择Python作为开发语言,主要使用了OpenCV、PyTorch和TensorFlow等开源库,整个项目代码量不大但效果相当不错。
在众多人脸检测和识别方案中,我最终选择了MTCNN+FaceNet的组合,主要基于以下几个考虑:
MTCNN的优势:
FaceNet的特点:
组合优势:
MTCNN由三个级联的CNN网络组成:
这种级联结构实现了从粗到细的检测策略,既保证了速度又提高了准确率。
FaceNet的核心思想是将人脸图像映射到一个紧凑的欧式空间,在这个空间中,同一人的不同图像距离很近,不同人的图像距离较远。其关键组件包括:
首先需要搭建Python开发环境,我推荐使用conda创建虚拟环境:
bash复制conda create -n facerec python=3.8
conda activate facerec
然后安装必要的依赖库:
bash复制pip install opencv-python
pip install mtcnn
pip install tensorflow
pip install torch torchvision
注意:MTCNN依赖于TensorFlow 1.x或2.x,如果遇到兼容性问题,可以指定版本安装:
pip install tensorflow==2.6.0
系统需要加载两个核心模型:MTCNN人脸检测器和FaceNet特征提取器。
python复制# 初始化MTCNN检测器
detector = MTCNN()
# 构建FaceNet模型
def create_facenet_model():
model = keras.models.Sequential([
keras.layers.Conv2D(32,(3,3),activation='relu',input_shape=(160,160,3)),
keras.layers.MaxPooling2D((2,2)),
keras.layers.Conv2D(64,(3,3),activation='relu'),
keras.layers.MaxPooling2D((2,2)),
keras.layers.Conv2D(128,(3,3),activation='relu'),
keras.layers.MaxPooling2D((2,2)),
keras.layers.Flatten(),
keras.layers.Dense(128),
keras.layers.Lambda(lambda x: keras.backend.l2_normalize(x, axis=1))
])
return model
facenet = create_facenet_model()
FaceNet要求输入图像为160×160的RGB格式,且像素值归一化到[0,1]范围:
python复制def preprocess_face(face_img):
# 缩放到160x160
face = cv2.resize(face_img, (160,160))
# 归一化像素值
face = face.astype('float32') / 255.0
# 添加batch维度
face = np.expand_dims(face, axis=0)
return face
使用FaceNet模型提取128维特征向量:
python复制def get_embedding(face_img):
face = preprocess_face(face_img)
embedding = facenet.predict(face, verbose=0)
return embedding[0] # 去除batch维度
通过计算欧式距离判断两个人脸是否属于同一个人:
python复制def compare_embeddings(emb1, emb2, threshold=0.3):
distance = np.linalg.norm(emb1 - emb2)
return distance < threshold, distance
经验分享:阈值0.3是一个经验值,实际应用中需要根据具体场景调整。要求严格的应用可以设为0.25,宽松场景可以设为0.35。
主函数实现了从图片读取到结果显示的完整流程:
python复制def face_detect_and_recognize(test_img_path, known_img_path):
# 处理已知人脸
known_img, known_rgb = process_image_path(known_img_path)
if known_img is None:
print(f"错误: {known_rgb}")
return
known_faces = detector.detect_faces(known_rgb)
if not known_faces:
print("错误: 已知图片中未检测到人脸")
return
# 提取已知人脸特征
x1, y1, w1, h1 = known_faces[0]['box']
y1, y2 = max(0, y1), max(0, y1 + h1)
x1, x2 = max(0, x1), max(0, x1 + w1)
known_face = known_rgb[y1:y2, x1:x2]
known_emb = get_embedding(known_face)
# 处理测试图片
test_img, test_rgb = process_image_path(test_img_path)
if test_img is None:
print(f"错误: {test_rgb}")
return
test_faces = detector.detect_faces(test_rgb)
if not test_faces:
print("测试图片中未检测到人脸")
return
# 遍历检测到的人脸并比对
for face in test_faces:
x, y, w, h = face['box']
y_min, y_max = max(0, y), max(0, y + h)
x_min, x_max = max(0, x), max(0, x + w)
current_face = test_rgb[y_min:y_max, x_min:x_max]
current_emb = get_embedding(current_face)
is_same, dist = compare_embeddings(known_emb, current_emb)
# 绘制结果
color = (0, 255, 0) if is_same else (0, 0, 255)
label = f"Match ({dist:.2f})" if is_same else f"Unmatch ({dist:.2f})"
cv2.rectangle(test_img, (x_min, y_min), (x_max, y_max), color, 2)
cv2.putText(test_img, label, (x_min, y_min - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
# 显示和保存结果
cv2.imshow("Face Recognition Result", test_img)
cv2.imwrite("result.jpg", test_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
处理不同格式的输入图像,确保符合模型要求:
python复制def process_image_path(img_path):
img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
if img is None:
return None, f"无法读取图片: {img_path}"
# 处理4通道图片
if img.shape[-1] == 4:
img = img[...,:3]
# 处理灰度图
elif len(img.shape) == 2:
img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
# 转换到RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_rgb = img_rgb.astype(np.uint8)
return img, img_rgb
批量处理:当需要处理多张图片时,可以批量提取特征,减少模型加载和初始化的开销。
模型量化:将浮点模型转换为8位整型,可以显著减少模型大小和推理时间。
多线程处理:对于实时视频流,可以使用多线程分别处理人脸检测和特征提取。
检测不到人脸:
识别准确率低:
运行速度慢:
实时视频分析:结合OpenCV的视频捕获功能,实现实时人脸识别。
人脸数据库检索:建立人脸特征数据库,实现基于内容的图像检索。
年龄性别识别:在现有系统基础上添加额外的分类模型。
表情识别:通过分析人脸特征实现情绪识别。
在我的测试中,系统对正面人脸的识别准确率可以达到90%以上。以下是两个测试案例:
案例1:单人脸比对
案例2:多人脸场景
实际测试中发现,系统对侧脸和大角度旋转的人脸识别效果会下降,这是后续需要优化的方向。一个可行的解决方案是增加多角度的人脸样本进行训练。