基于 face_recognition 的人脸识别的小工具

news2024/11/24 12:52:23

使用 face_recognition 和 pyside2,开发了一个小工具,识别指定的人脸照片,保存到指定的文件夹。

源码如下:

import sys
import os
import shutil
import face_recognition
import logging
from PySide2.QtWidgets import QApplication, QMainWindow, QFileDialog, QPushButton, QLabel, QLineEdit, QVBoxLayout, \
    QWidget, QComboBox, QProgressBar
from PySide2.QtCore import Qt, QThread, Signal

# 配置 logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


# 定义模型路径获取函数
def get_model_path():
    if getattr(sys, 'frozen', False):  # 检测是否为打包后的环境
        base_path = sys._MEIPASS
    else:
        base_path = os.path.dirname(__file__)

    return os.path.join(base_path, 'shape_predictor_68_face_landmarks.dat')


class WorkerThread(QThread):
    progress = Signal(int)
    status = Signal(str)
    finished = Signal(list)

    def __init__(self, directory_path, known_face_encodings, output_directory, model, threshold):
        super().__init__()
        self.directory_path = directory_path
        self.known_face_encodings = known_face_encodings
        self.output_directory = output_directory
        self.model = model
        self.threshold = threshold

    def run(self):
        matched_images = []
        total_images = len([f for f in os.listdir(self.directory_path) if f.endswith(('.png', '.jpg', '.jpeg'))])
        logging.info(f"总共有 {total_images} 张图片需要处理。")

        # 获取模型文件路径
        model_path = get_model_path()

        for idx, filename in enumerate(os.listdir(self.directory_path)):
            if filename.endswith(('.png', '.jpg', '.jpeg')):
                image_path = os.path.join(self.directory_path, filename)
                logging.info(f"正在处理图片: {image_path}")
                image = face_recognition.load_image_file(image_path)

                # 使用模型文件路径
                face_locations = face_recognition.face_locations(image, model=self.model)
                face_encodings = face_recognition.face_encodings(image, face_locations)

                matched = False  # 用于记录是否有匹配
                for face_encoding in face_encodings:
                    face_distances = face_recognition.face_distance(self.known_face_encodings, face_encoding)
                    best_match_index = face_distances.argmin()

                    # 记录匹配度信息
                    logging.info(f"图片 {filename} 的相似度: {(1 - face_distances[best_match_index]) * 100:.2f} %")

                    if face_distances[best_match_index] < self.threshold:
                        matched_images.append(filename)
                        shutil.move(image_path, os.path.join(self.output_directory, filename))
                        logging.info(f"匹配并移动: {filename}")
                        matched = True  # 标记为匹配成功
                        break  # 只要有一个匹配成功就跳出

                if not matched:
                    logging.info(f"图片 {filename} 未找到匹配 (所有匹配度均大于 {self.threshold})")

                # 发射进度信号
                self.progress.emit(int((idx + 1) / total_images * 100))

        # 处理完成后发射信号
        self.finished.emit(matched_images)
        self.status.emit(f"处理完成,共匹配到 {len(matched_images)} 张图片。")



class FaceRecognitionApp(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("人脸识别工具")
        self.setGeometry(100, 100, 100, 400)

        layout = QVBoxLayout()

        # 已知图片文件夹选择
        self.known_images_label = QLabel("已知人脸文件夹:")
        layout.addWidget(self.known_images_label)
        self.known_images_button = QPushButton("选择已知人脸文件夹")
        self.known_images_button.clicked.connect(self.select_known_images_directory)
        layout.addWidget(self.known_images_button)

        # 待处理文件夹选择
        self.directory_label = QLabel("待处理的文件夹:")
        layout.addWidget(self.directory_label)
        self.directory_button = QPushButton("选择待处理的文件夹")
        self.directory_button.clicked.connect(self.select_directory)
        layout.addWidget(self.directory_button)

        # 输出文件夹选择
        self.output_directory_label = QLabel("输出文件夹:")
        layout.addWidget(self.output_directory_label)
        self.output_directory_button = QPushButton("选择输出文件夹")
        self.output_directory_button.clicked.connect(self.select_output_directory)
        layout.addWidget(self.output_directory_button)

        # 阈值输入
        self.threshold_label = QLabel("阈值 (0 到 1): 数值越大通过率越高")
        layout.addWidget(self.threshold_label)
        self.threshold_input = QLineEdit()
        self.threshold_input.setText("0.6")  # 默认值
        layout.addWidget(self.threshold_input)

        # 模型选择下拉框
        self.model_label = QLabel("选择模型 (HOG 或 CNN): hog速度快,cnn精准但速度巨慢")
        layout.addWidget(self.model_label)
        self.model_selector = QComboBox()
        self.model_selector.addItems(["hog", "cnn"])
        layout.addWidget(self.model_selector)

        # 开始处理按钮
        self.process_button = QPushButton("开始处理")
        self.process_button.clicked.connect(self.start_processing)
        layout.addWidget(self.process_button)

        # 进度条
        self.progress_bar = QProgressBar()
        layout.addWidget(self.progress_bar)

        # 状态标签
        self.status_label = QLabel("")
        layout.addWidget(self.status_label)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

    def select_known_images_directory(self):
        self.known_images_directory = QFileDialog.getExistingDirectory(self, "选择已知图片文件夹")
        self.known_images_label.setText(f"已知图片文件夹: {self.known_images_directory}")

    def select_directory(self):
        self.directory_path = QFileDialog.getExistingDirectory(self, "选择待处理的文件夹")
        self.directory_label.setText(f"待处理的文件夹: {self.directory_path}")

    def select_output_directory(self):
        self.output_directory = QFileDialog.getExistingDirectory(self, "选择输出文件夹")
        self.output_directory_label.setText(f"输出文件夹: {self.output_directory}")

    def load_known_faces(self, known_image_paths):
        known_face_encodings = []
        for path in known_image_paths:
            image = face_recognition.load_image_file(path)
            encodings = face_recognition.face_encodings(image)
            if len(encodings) > 0:
                known_face_encodings.append(encodings[0])
                logging.info(f"已加载并编码: {path}")
            else:
                logging.warning(f"在 {path} 中未找到人脸")
        return known_face_encodings

    def start_processing(self):
        try:
            known_image_paths = [os.path.join(self.known_images_directory, f) for f in
                                 os.listdir(self.known_images_directory) if f.endswith(('.png', '.jpg', '.jpeg'))]
            threshold = float(self.threshold_input.text())
            model = self.model_selector.currentText()

            self.status_label.setText("处理中...")
            self.status_label.repaint()

            known_face_encodings = self.load_known_faces(known_image_paths)

            # 创建并启动工作线程
            self.worker = WorkerThread(self.directory_path, known_face_encodings, self.output_directory, model,
                                       threshold)
            self.worker.progress.connect(self.update_progress)
            self.worker.status.connect(self.update_status)
            self.worker.finished.connect(self.processing_finished)
            self.worker.start()

        except Exception as e:
            self.status_label.setText(f"错误: {e}")
            logging.error(f"错误: {e}", exc_info=True)

    def update_progress(self, value):
        self.progress_bar.setValue(value)

    def update_status(self, message):
        self.status_label.setText(message)

    def processing_finished(self, matched_images):
        self.status_label.setText(f"处理完成,共匹配到 {len(matched_images)} 张图片。")


if __name__ == "__main__":
    # 获取模型文件路径
    model_path = get_model_path()

    app = QApplication(sys.argv)
    window = FaceRecognitionApp()
    window.show()
    sys.exit(app.exec_())

打包exe时,遇到的问题,缺少shape_predictor_68_face_landmarks.dat,

解决步骤:
1、先生成demo.spec文件

pyinstaller 你要打包的文件.py

2、找到 face_recognition_models 文件复制到打包py文件的根目录下

3、然后更改demo.spec文件
 

# -*- mode: python -*-

block_cipher = None
# 最重要的是这里,缺少的文件
face_models = [
('.\\face_recognition_models\\models\\dlib_face_recognition_resnet_model_v1.dat', './face_recognition_models/models'),
('.\\face_recognition_models\\models\\mmod_human_face_detector.dat', './face_recognition_models/models'),
('.\\face_recognition_models\\models\\shape_predictor_5_face_landmarks.dat', './face_recognition_models/models'),
('.\\face_recognition_models\\models\\shape_predictor_68_face_landmarks.dat', './face_recognition_models/models'),
]
# demourl.py 改为你自己的打包文件
a = Analysis(['demourl.py'],
             # 打包exe文件路径
             pathex=[r'D:\Google\png\dist'],
             binaries=face_models,
             datas=[],
             hiddenimports=['scipy._lib.messagestream', 'scipy', 'scipy.signal', 'scipy.signal.bsplines', 'scipy.special', 'scipy.special._ufuncs_cxx',
                            'scipy.linalg.cython_blas',
                            'scipy.linalg.cython_lapack',
                            'scipy.integrate',
                            'scipy.integrate.quadrature',
                            'scipy.integrate.odepack',
                            'scipy.integrate._odepack',
                            'scipy.integrate.quadpack',
                            'scipy.integrate._quadpack',
                            'scipy.integrate._ode',
                            'scipy.integrate.vode',
                            'scipy.integrate._dop', 'scipy._lib', 'scipy._build_utils','scipy.__config__',
                            'scipy.integrate.lsoda', 'scipy.cluster', 'scipy.constants','scipy.fftpack','scipy.interpolate','scipy.io','scipy.linalg','scipy.misc','scipy.ndimage','scipy.odr','scipy.optimize','scipy.setup','scipy.sparse','scipy.spatial','scipy.special','scipy.stats','scipy.version'],

             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)


pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='test',
          debug=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True )

4、执行打包命令

pyinstaller demo.spec

打包完了,去dist运行exe文件,就可以运行了。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2045943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PDF文件转换为HTML文件

推荐使用 pdf2htmlEX&#xff08;因为确实做的比较全&#xff09; pdf2htmlEX 是一个开源工具&#xff0c;可以将PDF文件转换为HTML文件。你需要先安装pdf2htmlEX工具&#xff0c;并确保它在你的系统路径中可用。&#xff08;花时间最多就是找包&#xff09; 安装 pdf2htmlEX …

API以及添加学生信息练习

API:应用程序编程接口 简单理解&#xff1a;API就是别人已经写好的东西&#xff0c;我们不需要自己编写&#xff0c;直接使用即可 Java API&#xff1a;指的就是jdk中提供的各种功能的Java类&#xff0c;这些类将底层的实现封装起来&#xff0c;我们不需关心这些类是如何实现的…

什么是神中神公司?发表内卷言论,分分钟要你道歉...

谷歌 海的那边&#xff0c;这几天最乐的新闻&#xff0c;是谷歌前 CEO 批评员工不拼命工作后道歉。 今年 4 月&#xff0c;谷歌前 CEO 埃里克施密特&#xff08;Eric Schmidt&#xff09;在斯坦福大学的一次演讲中&#xff0c;被问及 OpenAI 和 Anthropic 等初创公司目前在人工…

【全面解析】芯片采购渠道策略:原厂直采VS代理VS现货市场

芯片作为现代科技的基石&#xff0c;其重要性不言而喻。无论是智能手机、汽车电子、物联网设备还是高性能计算领域&#xff0c;都离不开芯片的支持。随着5G、AI、大数据等前沿技术的飞速发展&#xff0c;对芯片的需求量持续攀升&#xff0c;如何确保稳定、高效的芯片供应链成为…

A3VLM: Actionable Articulation-Aware Vision Language Model

发表时间&#xff1a;13 Jun 2024 作者单位&#xff1a;SJTU Motivation&#xff1a;以往的机器人VLM如RT-1[4]、RT-2[3]和ManipLLM[21]都专注于直接学习以机器人为中心的动作。这种方法需要收集大量的机器人交互数据&#xff0c;这在现实世界中非常昂贵。 解决方法&#xf…

数据中台之数据开发-离线开发和实时开发

目录 一、离线开发 1.1 概述 1.2 作业调度 1.3 基线控制 1.4 异构存储 1.5 代码校验 1.6 多环境级联 1.7 推荐依赖 1.8 数据权限 二、实时开发 2.1 概述 2.2 实时计算的特点 2.2.1 实时且无界(unbounded)的数据流 2.2.2 持续且高效的计算 2.2.3 流式且实时的数据…

go,gin封装gorm使用,增删改查

1、主 package mainimport ("fmt""wbGo/configs" )type Dades struct {Id intName stringAge int }func main() {//连接数据库configs.BaseName("wbrj_sample")var data []Dades//查询configs.Db.Raw("select * from dade where id>…

机器学习/深度学习——关于分类任务的机器学习、深度学习模型的评估指标详解

机器学习/深度学习——模型的评估详解 搭配以下文章进行学习&#xff1a; 卷积神经网络&#xff1a; 深度学习——卷积神经网络&#xff08;convolutional neural network&#xff09;CNN详解&#xff08;一&#xff09;——概述. 步骤清晰0基础可看 深度学习——卷积神经网…

Ciallo~(∠・ω・ )⌒☆第十七篇 Ubuntu基础使用 其一

Ubuntu是一种基于Linux的操作系统&#xff0c;它是开源的、免费的&#xff0c;并且具有广泛的用户群体。 基本文件操作&#xff1a;Ubuntu使用命令行工具来进行文件操作。以下是一些常用的命令&#xff1a; 切换到用户主目录&#xff1a; cd ~ 切换到上级目录&#xff1a; cd .…

QT 数据导出到Excel

原创&#xff1a;QT 数据导出到Excel 在Qt自带的axcontainer模块中&#xff0c;我们可以使用QAxObject类来将数据保存到Excel中。Qt中将数据保存到Excel通常有两种方式&#xff1a;一种是以Excel格式导出&#xff0c;需要电脑上安装Office软件&#xff1b;另一种是以CSV格式导出…

用户端是小程序,后台管理系统是PC端的CMS系统

1. 数据库表设计 1.1 课程轮播图表 CREATE TABLE course_banners (id int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 轮播图主键,image_url varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 轮播图图片链接,title varchar(255) CHARAC…

高考志愿智能推荐系统-计算机毕设Java|springboot实战项目

&#x1f34a;作者&#xff1a;计算机毕设残哥 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目、 源…

Lesson 64 Don‘t ... You mustn‘t ...

Lesson 64 Don’t … You mustn’t … 词汇 play n. 戏剧&#xff08;真人演的&#xff0c;话剧&#xff09;v. 玩耍 搭配&#xff1a;play with 物体 / 人    玩…… / 和……一起玩 例句&#xff1a;我正在和Leo玩。    I am playing with Leo.演奏&#xff08;乐器…

代码随想录算法训练营第十六天

力扣题部分: 513.找树左下角的值 题目链接:. - 力扣&#xff08;LeetCode&#xff09; 题面: 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 思路(层序遍历): 应该是这道题最简单的方法了&#xff0…

数据结构与算法——DFS(深度优先搜索)

算法介绍&#xff1a; 深度优先搜索&#xff08;Depth-First Search&#xff0c;简称DFS&#xff09;是一种用于遍历或搜索树或图的算法。这种算法会尽可能深地搜索图的分支&#xff0c;直到找到目标节点或达到叶节点&#xff08;没有子节点的节点&#xff09;&#xff0c;然后…

Vue3 reactive 响应式原理源码实现

学习小满的视频&#xff0c;更详细的讲解 Vue3响应式原理 视频 需要了解Proxy、Reflect函数 目录结构&#xff1a; 配置环境&#xff1a; package.json {"name": "vue-reactive","version": "1.0.0","description": &quo…

【Kubernetes】Service 类型

Service 类型 1.NodePort2.ClusterlP3.LoadBalance4.ExternalName 在《Service 概念与实战》一文中&#xff0c;Service 的发布使用的是 NodePort 类型。除此之外&#xff0c;Service 的发布还支持 ClusterlP、LoadBalancer 和 ExternalName 这 3 种类型。 1.NodePort 在把 Se…

基于STM32开发的智能门铃系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化按钮与蜂鸣器控制显示与远程通知Wi-Fi通信应用场景 家庭智能门铃办公室访客通知常见问题及解决方案 常见问题解决方案结论 1. 引言 智能门铃系统通过集成按钮、蜂鸣器、显示屏、W…

HTML补充——表格表单

一、表格 1、在现实生活中&#xff0c;我们经常需要使用表格来表示一些格式化数据&#xff1a;课程表、人名表、成绩单 同样在网页中我们也需要使用表格&#xff0c;我们通过table标签创建表格。 2、在table标签中使用tr表示表格中的一行&#xff0c;有几个tr就有几行&#xff…

prometheus数据如何清理

1. 停止prometheus服务 2. 进到prometheus数据目录 3. 删除数据 3.1 删除持久化的数据块 Prometheus 将数据分块存储&#xff0c;每个块对应一个时间段。你可以通过查看目录中的时间戳来找到需要删除的数据块。 每个块的目录名是一个时间戳范围&#xff0c;例如 16094592000…