OpenCV 人脸识别和比对工具

OpenCV 人脸识别和比对工具

应用场景

在很多张包含人脸的照片中,提取出包含指定人脸相关的照片。适合将图片按人物分类。

功能说明

此Python脚本可以:

  1. 从一张目标人脸图片中提取人脸特征
  2. 在指定目录中搜索包含该人脸的所有图片
  3. 将匹配的图片保存到新目录并在图片上框出人脸位置
  4. 提供阈值参数以调整识别精度

安装依赖

在运行脚本之前,需要安装以下依赖:

bash 复制代码
pip install opencv-python numpy requests dlib-bin

使用方法

配置路径

在运行脚本之前,需要在脚本中配置以下路径:

  • target_image:目标人脸图片路径(默认为:C:\Users\zhangqs\Desktop\TEST\1.jpg
  • search_directory:要搜索的图片目录(默认为:C:\Users\zhangqs\Desktop\TEST\2
  • tolerance:人脸识别阈值(默认为:0.4,值越小越严格)

运行脚本

bash 复制代码
python face_recognition_script.py

脚本执行流程

  1. 检查模型文件:自动检查并下载所需的dlib模型文件(首次运行时)
  2. 初始化模型:加载人脸识别模型
  3. 提取特征:从目标人脸图片中提取特征
  4. 搜索匹配:在指定目录中搜索包含目标人脸的图片
  5. 保存结果 :将匹配的图片保存到 C:\Users\zhangqs\Desktop\TEST\3 目录,并在图片上框出人脸位置

提高识别准确性的方法

  1. 使用清晰的目标图片:确保目标人脸图片清晰、正面,光线充足
  2. 调整tolerance参数:降低阈值(如0.4)可以提高识别精度,但可能会漏掉一些相似的人脸
  3. 确保搜索目录中的图片质量:搜索目录中的图片也应该清晰可见人脸
  4. 使用足够的测试数据:搜索目录中应该包含足够多的图片来测试识别效果

注意事项

  1. 首次运行时间较长:首次运行时需要下载模型文件,可能需要较长时间
  2. 处理大量图片时可能耗时:这是正常现象,因为人脸识别是计算密集型任务
  3. 支持的图片格式:jpg、jpeg、png、bmp
  4. 脚本会遍历子目录:脚本会递归遍历指定目录及其所有子目录中的图片文件

技术原理

  • 使用dlib进行人脸检测和特征提取

  • 使用OpenCV进行图像处理

  • 使用欧氏距离计算人脸特征相似度

  • 通过阈值控制识别的严格程度

  • 使用ResNet模型进行人脸识别,提高识别准确性

    import os
    import cv2
    import dlib
    import numpy as np
    import argparse

    全局变量

    detector = None
    sp = None
    facerec = None

    def extract_face_features(image_path):
    """
    从图片中提取人脸特征
    """
    try:
    # 读取图片
    img = cv2.imread(image_path)
    if img is None:
    print(f"错误: 无法读取 {image_path}")
    return None

    复制代码
          # 转换为灰度图
          gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
          
          # 检测人脸
          faces = detector(gray)
          if len(faces) == 0:
              print(f"错误: 在 {image_path} 中未检测到人脸")
              return None
          
          # 提取第一个人脸的特征
          shape = sp(img, faces[0])
          face_descriptor = facerec.compute_face_descriptor(img, shape)
          return np.array(face_descriptor)
      except Exception as e:
          print(f"错误: 处理 {image_path} 时出错: {e}")
          return None

    def compute_distance(encoding1, encoding2):
    """
    计算两个人脸特征之间的欧氏距离
    """
    return np.linalg.norm(encoding1 - encoding2)

    def find_matching_images(target_encoding, search_directory, tolerance=0.6):
    """
    在指定目录中查找包含目标人脸的图片
    """
    matching_images = []

    复制代码
      # 创建保存目录
      save_directory = "C:\\Users\\zhangqs\\Desktop\\TEST\\3"
      if not os.path.exists(save_directory):
          os.makedirs(save_directory)
          print(f"创建保存目录: {save_directory}")
      
      image_count = 1
      
      for root, dirs, files in os.walk(search_directory):
          for file in files:
              if file.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp')):
                  image_path = os.path.join(root, file)
                  print(f"正在处理: {image_path}")
                  
                  try:
                      # 读取图片
                      img = cv2.imread(image_path)
                      if img is None:
                          print(f"警告: 无法读取 {image_path}")
                          continue
                      
                      # 转换为灰度图
                      gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                      
                      # 检测人脸
                      faces = detector(gray)
                      
                      # 检查每个人脸
                      for face in faces:
                          shape = sp(img, face)
                          face_descriptor = facerec.compute_face_descriptor(img, shape)
                          face_encoding = np.array(face_descriptor)
                          
                          # 计算距离
                          distance = compute_distance(target_encoding, face_encoding)
                          print(f"  距离: {distance:.4f}")
                          
                          # 检查是否匹配
                          if distance < tolerance:
                              matching_images.append(image_path)
                              
                              # 在图片上框出人脸
                              x, y, w, h = face.left(), face.top(), face.width(), face.height()
                              cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
                              
                              # 保存处理后的图片
                              save_filename = f"{image_count}.jpg"
                              save_path = os.path.join(save_directory, save_filename)
                              cv2.imwrite(save_path, img)
                              print(f"  保存到: {save_path}")
                              
                              image_count += 1
                              break
                  except Exception as e:
                      print(f"错误: 处理 {image_path} 时出错: {e}")
      
      return matching_images

    def download_required_files():
    """
    下载所需的模型文件
    """
    import requests
    import zipfile

    复制代码
      files = {
          'shape_predictor_68_face_landmarks.dat': 'http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2',
          'dlib_face_recognition_resnet_model_v1.dat': 'http://dlib.net/files/dlib_face_recognition_resnet_model_v1.dat.bz2'
      }
      
      for filename, url in files.items():
          if not os.path.exists(filename):
              # 检查压缩包是否存在
              if os.path.exists(f"{filename}.bz2"):
                  print(f"发现压缩包 {filename}.bz2,正在解压...")
                  try:
                      # 解压文件
                      import bz2
                      with bz2.BZ2File(f"{filename}.bz2", 'rb') as fr, open(filename, 'wb') as fw:
                          fw.write(fr.read())
                      
                      # 删除压缩文件
                      os.remove(f"{filename}.bz2")
                      print(f"{filename} 解压完成")
                  except Exception as e:
                      print(f"错误: 解压 {filename} 时出错: {e}")
                      return False
              else:
                  print(f"正在下载 {filename}...")
                  try:
                      # 下载文件
                      import bz2
                      response = requests.get(url, stream=True)
                      with open(f"{filename}.bz2", 'wb') as f:
                          for chunk in response.iter_content(chunk_size=8192):
                              f.write(chunk)
                      
                      # 解压文件
                      print(f"正在解压 {filename}...")
                      with bz2.BZ2File(f"{filename}.bz2", 'rb') as fr, open(filename, 'wb') as fw:
                          fw.write(fr.read())
                      
                      # 删除压缩文件
                      os.remove(f"{filename}.bz2")
                      print(f"{filename} 下载完成")
                  except Exception as e:
                      print(f"错误: 下载 {filename} 时出错: {e}")
                      return False
          else:
              print(f"{filename} 已存在")
      
      return True

    def main():
    global detector, sp, facerec

    复制代码
      # 硬编码路径
      target_image = "C:\\Users\\zhangqs\\Desktop\\TEST\\1.jpg"
      search_directory = "C:\\Users\\zhangqs\\Desktop\\TEST\\2"
      tolerance = 0.4  # 降低阈值,提高识别精度
      
      print(f"目标人脸图片: {target_image}")
      print(f"搜索目录: {search_directory}")
      print(f"识别阈值: {tolerance}")
      
      # 检查模型文件是否存在
      print("\n检查所需的模型文件...")
      model_files = [
          'shape_predictor_68_face_landmarks.dat',
          'dlib_face_recognition_resnet_model_v1.dat'
      ]
      
      all_files_exist = True
      for model_file in model_files:
          if os.path.exists(model_file):
              print(f"{model_file} 已存在")
          else:
              print(f"错误: {model_file} 不存在")
              all_files_exist = False
      
      if not all_files_exist:
          print("缺少必要的模型文件,程序退出")
          return
      
      # 初始化dlib的模型
      print("初始化人脸识别模型...")
      detector = dlib.get_frontal_face_detector()
      sp = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
      facerec = dlib.face_recognition_model_v1('dlib_face_recognition_resnet_model_v1.dat')
      
      print(f"\n正在提取目标人脸特征...")
      target_encoding = extract_face_features(target_image)
      
      if target_encoding is None:
          print("无法提取目标人脸特征,程序退出")
          return
      
      print(f"\n正在搜索包含目标人脸的图片...")
      matching_images = find_matching_images(target_encoding, search_directory, tolerance)
      
      print(f"\n搜索完成!")
      print(f"找到 {len(matching_images)} 张包含目标人脸的图片:")
      for image_path in matching_images:
          print(f"- {image_path}")

    if name == "main":
    main()

资源下载

  • 完整人脸检测/识别所需模型及代码,请在文章关联资源下载(文章顶部)。
相关推荐
要加油哦~5 小时前
AI | 实践教程 - ScreenCoder | 多agents前端代码生成
前端·javascript·人工智能
程序员Sunday5 小时前
说点不一样的。GPT-5.3 与 Claude Opus 4.6 同时炸场,前端变天了?
前端·gpt·状态模式
yq1982043011565 小时前
静思书屋:基于Java Web技术栈构建高性能图书信息平台实践
java·开发语言·前端
aPurpleBerry5 小时前
monorepo (Monolithic Repository) pnpm rush
前端
青茶3605 小时前
php怎么实现订单接口状态轮询请求
前端·javascript·php
鹏北海6 小时前
micro-app 微前端项目部署指南
前端·nginx·微服务
发现一只大呆瓜6 小时前
虚拟列表:从定高到动态高度的 Vue 3 & React 满分实现
前端·vue.js·react.js
css趣多多6 小时前
add组件增删改的表单处理
java·服务器·前端
证榜样呀6 小时前
2026 大专计算机专业必考证书推荐什么
大数据·前端