当前位置:首页 > Software > Python > 正文内容

(原创)ClassImgsByFace 根据人脸对大量照片进行分类 利用 MTCNN 和 OpenCV 实现人脸识别和分类的 Python 程序

chanra1n2年前 (2024-01-03)Python3598

需求分析

这个Python程序旨在从输入文件夹中读取照片,使用 MTCNN 和 OpenCV 进行人脸检测,比对已有的人脸库,并根据相似度阈值将照片分类到不同的输出文件夹中。同时,程序还会将检测到的人脸保存到人脸库中。

方法和思路

  1. 读取配置文件,设置路径和参数。

  2. 使用 MTCNN 和 OpenCV 进行人脸检测和特征提取。

  3. 比对检测到的人脸与已有人脸库中的人脸相似度。

  4. 根据相似度阈值分类照片到不同的输出文件夹,同时将人脸保存到人脸库。

  5. 记录日志以便追踪处理过程。

方法评价

  • MTCNN 和 OpenCV 是常用的人脸检测和特征提取工具,能够有效地进行人脸识别。

  • 结合结构相似性指数(SSIM)进行人脸比对,提高了准确性。

  • 多线程实现全局计数器,确保人脸保存到人脸库时的唯一性。

  • 通过日志记录,方便追踪处理过程中的错误和信息。

选择最适合的方法

综合考虑了 MTCNN 和 OpenCV 的人脸检测特性、SSIM 的准确性以及多线程的性能,认为当前的实现方法是较为合理和全面的。

代码实现

# -*- coding: utf-8 -*-
# 版本唯一标识 V1_1
import os
import cv2
from mtcnn.mtcnn import MTCNN
from shutil import copyfile
from skimage.metrics import structural_similarity as ssim
import logging
import threading
import configparser

# 读取配置文件
config = configparser.ConfigParser()
config.read('ClassImgsByFace.cfg')

# 设置路径
input_folder = config.get('Paths', 'input_folder')
output_folder = config.get('Paths', 'output_folder')
face_library_folder = config.get('Paths', 'face_library_folder')
similarity_threshold = float(config.get('Settings', 'similarity_threshold'))

# 初始化 MTCNN
mtcnn = MTCNN()

# 初始化 logging
logging.basicConfig(filename='ClassImgsByFace.log', level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')

# 日志记录函数
def log_info(message):
    logging.info(message)

# 全局计数器和锁
global_face_counter = 0
counter_lock = threading.Lock()

# 人脸检测和特征提取(MTCNN)
def detect_faces_mtcnn(image_path):
    try:
        image = cv2.imread(image_path)
        result = mtcnn.detect_faces(image)
        faces = [(image[y:y+h, x:x+w], f"face{idx}") for idx, (x, y, w, h) in enumerate([face['box'] for face in result])]
        return faces
    except Exception as e:
        log_info(f"Error processing image {image_path} with MTCNN: {e}")
        return []

# 人脸检测和特征提取(OpenCV)
def detect_faces_opencv(image_path):
    try:
        image = cv2.imread(image_path)
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        faces = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml').detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)
        faces = [(image[y:y+h, x:x+w], f"face{idx}") for idx, (x, y, w, h) in enumerate(faces)]
        return faces
    except Exception as e:
        log_info(f"Error processing image {image_path} with OpenCV: {e}")
        return []

# 人脸比对
def compare_faces(face1, face2):
    face1 = cv2.resize(face1, (face2.shape[1], face2.shape[0]))
    gray1 = cv2.cvtColor(face1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(face2, cv2.COLOR_BGR2GRAY)
    _, diff = cv2.threshold(cv2.absdiff(gray1, gray2), 30, 255, cv2.THRESH_BINARY)
    score = ssim(gray1, gray2)
    return score

# 保存人脸到人脸库
def save_to_face_library(face, face_library_folder):
    global global_face_counter
    with counter_lock:
        face_id = f"face{global_face_counter}"
        global_face_counter += 1
    cv2.imwrite(os.path.join(face_library_folder, f"{face_id}.jpg"), face)
    return face_id

# 保存完整照片到输出文件夹
def save_full_photo(image_path, output_folder, name, face_id):
    output_path = os.path.join(output_folder, face_id)
    if not os.path.exists(output_path):
        os.makedirs(output_path)
    copyfile(image_path, os.path.join(output_path, name + ".jpg"))

# 人脸匹配和处理
def process_image(image_path):
    try:
        faces_mtcnn = detect_faces_mtcnn(image_path)
        faces_opencv = detect_faces_opencv(image_path)

        if not faces_mtcnn and not faces_opencv:
            log_info(f"No faces detected in image: {image_path}")
            return

        for face_mtcnn, face_id in faces_mtcnn:
            for face_opencv, _ in faces_opencv:
                similarity_scores = [compare_faces(face_mtcnn, face_opencv), compare_faces(face_opencv, face_mtcnn)]
                min_similarity_score = min(similarity_scores)
                log_info(f"Similarity Scores - {similarity_scores}")

                if min_similarity_score > similarity_threshold:
                    log_info("Similar face found!")
                    saved_face_id = save_to_face_library(face_mtcnn, face_library_folder)
                    save_full_photo(image_path, output_folder, os.path.basename(image_path).split('.')[0], saved_face_id)
                    return

        log_info("No similar face found. Adding to face library.")
        saved_face_id = save_to_face_library(faces_mtcnn[0][0], face_library_folder)
        save_full_photo(image_path, output_folder, os.path.basename(image_path).split('.')[0], saved_face_id)
    except Exception as e:
        log_info(f"Error processing image {image_path}: {e}")

# 主流程
def main():
    for root, dirs, files in os.walk(input_folder):
        for file in files:
            image_path = os.path.join(root, file)
            log_info(f"\nProcessing image: {file}")
            process_image(image_path)

if __name__ == "__main__":
    main()

分析结果

  • 功能完成情况:程序能够正确地检测人脸,进行比对,并根据相似度阈值分类照片到不同的输出文件夹。同时,人脸也被保存到人脸库中。

  • 安全性:程序在人脸保存时使用了全局计数器和锁,确保人脸库中的人脸 ID 唯一性。

  • 异常处理:程序通过日志记录了处理过程中的错误,方便追踪问题。

综上所述,该程序能够有效地完成人脸识别和分类的任务,同时具备较好的安全性和异常处理能力。


cfg文件示例

[Paths]
input_folder = C:/Users/ChanRa1n/Desktop
output_folder = C:/Users/ChanRa1n/Desktop/OutPut
face_library_folder = C:/Users/ChanRa1n/Desktop/DataSet/FaceLibrary

[Settings]
similarity_threshold = 0.5
Debug_Mode = True


扫描二维码推送至手机访问。

版权声明:本文由我的FPGA发布,如需转载请注明出处。

本文链接:https://www.myfpga.cn/index.php/post/344.html

分享给朋友:

“(原创)ClassImgsByFace 根据人脸对大量照片进行分类 利用 MTCNN 和 OpenCV 实现人脸识别和分类的 Python 程序” 的相关文章

2.Python中的基本运算

2.Python中的基本运算

我们打开Python,请你尝试输入如下算式并尝试理解有什么为什么是这样的?1+1 1+1.0 1-2 2-3.5 1*1 1*1.1 1/2 2/1 2/3 3/2 3//2 3/1.0 5/2.5我们不难得到如下结果2 2.0 -1 -1.5 1 1.1 0.5...

Python关于turtle的函数名

Python关于turtle的函数名

turtle.forward(distance)                   向当前画笔方向移动distance像素长度turtle.backward(distance)              向当前画笔相反方向移动distance像素长度turtle.right(degree)    ...

math库的使用

math库的使用

math库包括4个数学常数math.pi      圆周率math.e       自然对数math.inf     正无穷大,负无穷大为-math.infmath.nan     非浮点数标记math库常用函数math.cell(x)      向上取整,返回不小于x的最小整数math.facto...

random库

random库

random()            生成一个[0.0,1.0)之间的随机小数randint(a,b)     生成一个[a,b]之间的整数uniform(a,b)     生成一个[a,b]之间的随机小数对random库的引用方法与math库一样,采用下面两种方式实现:import random...

(原创)使用Python对任意网站图片进行爬取,仅用于学习

(原创)使用Python对任意网站图片进行爬取,仅用于学习

import os import time import argparse import requests import re import io from urllib.parse import ...

(原创)使用Python递归获取网页内的所有URL,并进行清洗

(原创)使用Python递归获取网页内的所有URL,并进行清洗

import argparse import time from urllib.parse import urljoin, urlparse from selenium import webdriver...