实战OpenCV之人脸识别

news/2024/12/4 0:41:51/

基础入门

        随着计算机视觉技术和深度学习的发展,人脸识别已经成为一项广泛应用的技术,涵盖了从安全监控、身份验证、智能家居到大型公共安全项目等多个领域。

        人脸识别技术通常包括以下几个主要步骤。

        图像采集:通过摄像头或其他图像采集设备,捕获包含人脸的图像或视频帧。

        人脸检测:从图像中定位人脸的位置,确定人脸的边界框。常用的方法包括:基于特征的传统方法(比如:Haar特征)、基于深度学习的方法(比如:YOLO、SSD等)。

        特征提取:从检测到的人脸区域中提取有用的特征向量。这些特征可以是基于几何形状的特征(比如:眼睛、鼻子、嘴巴之间的相对位置)、颜色特征、或深度学习模型提取的高维特征向量。

        特征匹配:将提取到的特征向量与数据库中的特征向量进行比较,以识别或验证个人的身份。常见的方法包括:欧氏距离、余弦相似度等。

        在OpenCV 4.X版本中,新引入了FaceDetectorYN和FaceRecognizerSF两个类,以提供更高效且准确的面部检测和识别能力。

FaceDetectorYN

        FaceDetectorYN是一个用于面部检测的面向对象接口,它基于YOLOv3架构,并且专门针对人脸检测进行了优化。FaceDetectorYN提供了高效且准确的面部检测能力,适用于实时应用和大规模人脸数据库等场景。FaceDetectorYN可加载预训练的面部检测模型,并提供了一系列方法来检测图像中的人脸。

        FaceDetectorYN::create静态函数用于创建人脸检测的模型实例,其接口原型如下。

static Ptr<FaceDetectorYN> create(const String& model,const String& config, Size inputSize,double scoreThreshold = 0.9, double nmsThreshold = 0.3,int topK = 5000);

        各个参数的含义如下。

        model:模型文件的路径。

        config:配置文件的路径。如果模型文件支持直接加载(比如:ONNX格式),则此参数可以为空字符串。

        inputSize:模型接收的输入图像尺寸,通常为“(宽度, 高度)”的形式。

        scoreThreshold:检测得分阈值,默认为0.9。只有得分高于此阈值的检测框,才会被认为是有效的。

        nmsThreshold:非极大值抑制(NMS)的阈值,默认为0.3,用于去除重叠的检测框。

        topK:最多保留的检测结果数量,默认为5000。

        detect函数用于人脸检测的推理,以获取检测框和关键点信息,其接口原型如下。

int detect(InputArray image, OutputArray faces);

        各个参数的含义如下。

        image:输入的图像。

        faces:输出的人脸检测结果,通常是一个Mat,其形状为[num_faces, 15]。每个人脸包含15个元素,元素的含义如下。

        (1)元素0-1:人脸框左上角的x、y位置。

        (2)元素2-3:人脸框的宽度和高度。

        (3)元素4-5:右眼的x、y位置。

        (4)元素6-7:左眼的x、y位置。

        (5)元素8-9:鼻子的x、y位置。

        (6)元素10-11:右嘴角的x、y位置。

        (7)元素12-13:左嘴角的x、y位置。

        (8)元素14:人脸检测的得分。

FaceRecognizerSF

        FaceRecognizerSF主要用于从图像中提取人脸特征向量,这些特征向量可以用于后续的人脸识别任务。其主要功能包括下面三点。

        1、特征提取:从输入的人脸图像中提取出一个固定长度的特征向量,这个特征向量能够代表该人脸的主要特征。

        2、特征对比:比较两个人脸特征向量之间的相似度,从而判断两个人脸是否属于同一人。

        3、人脸对齐:对输入的人脸图像进行对齐处理,使得提取出的特征更具有一致性。

        FaceRecognizerSF的主要接口和方法如下。

        FaceRecognizerSF::create静态函数用于创建人脸识别的模型实例,其接口原型如下。

static Ptr<FaceRecognizerSF> create(const String& model, const String& config);

        各个参数的含义如下。

        model:模型文件的路径。

        config:配置文件的路径。如果模型文件支持直接加载(比如:ONNX格式),则此参数可以为空字符串。

        alignCrop函数用于对齐并裁剪输入的人脸图像,使其符合模型要求的标准姿势,其接口原型如下。

void alignCrop(InputArray src_img, InputArray face_box, OutputArray aligned_img) const;

        各个参数的含义如下。

        src_img:输入的图像。

        face_box:人脸框的位置信息,通常是一个cv::Rect或类似的结构,表示人脸的位置。

        aligned_img:输出的对齐并裁剪后的人脸图像。

        feature函数用于从对齐后的人脸图像中提取特征向量,其接口原型如下。

void feature(InputArray aligned_img, OutputArray face_feature) const;

        各个参数的含义如下。

        aligned_img:输入的对齐并裁剪后的人脸图像。

        face_feature:输出的特征向量,可用于后续的比对。

        match函数用于计算两个特征向量之间的相似度,以判断它们是否属于同一个人,其接口原型如下。

double match(InputArray face_feature1, InputArray face_feature2, int dis_type = FaceRecognizerSF::FR_COSINE) const;

        各个参数的含义如下。

        face_feature1:第一个特征向量。

        face_feature2:第二个特征向量。

        dis_type:相似度计算的方式,默认为FR_COSINE(余弦相似度),也可以选择FR_NORM_L2(L2 范数)。

实战解析

        下面的实战代码演示了如何使用FaceDetectorYN和FaceRecognizerSF来进行人脸检测、对齐、特征提取以及相似度匹配。

        首先,我们从两个不同的图像文件中加载图像,并检查是否成功加载。接着,我们创建了两个人脸处理模块的实例:一个用于人脸检测,另一个用于特征识别。

        为了使人脸检测更高效,我们调整了图像的尺寸到320 x 320。然后,使用人脸检测器在调整后的图像上查找人脸,并将检测到的人脸信息存储在faces1和faces2中。如果检测到了人脸,程序会使用人脸识别器来对齐并裁剪出人脸区域。随后,进一步提取每个人脸的特征向量,并将这些特征向量克隆到新的Mat对象中。

        注意:必须将特征向量克隆一份,否则match会一直返回1。这是因为,feature返回的特征向量是内部共享数据的,内部data指向的是同一个指针。

        一旦有了两个人脸的特征向量,我们就会计算它们之间的相似度,并输出这个值。最后,我们使用DrawFaces函数在检测到人脸的图像上绘制人脸框及特征点,并在其中一个图像上叠加显示相似度值。

#include <opencv2/opencv.hpp>
using namespace cv;#include <iostream>
using namespace std;static void DrawFaces(Mat& input, Mat& faces, int thickness = 2)
{for (int i = 0; i < faces.rows; i++){// 打印人脸信息cout << "Face " << i<< ", top-left coordinates: (" << faces.at<float>(i, 0) << ", " << faces.at<float>(i, 1) << "), " << "box width: " << faces.at<float>(i, 2)  << ", box height: " << faces.at<float>(i, 3) << ", " << "score: " << format("%.2f", faces.at<float>(i, 14)) << endl;// 画边框rectangle(input, Rect2i(int(faces.at<float>(i, 0)), int(faces.at<float>(i, 1)), int(faces.at<float>(i, 2)), int(faces.at<float>(i, 3))), Scalar(0, 255, 0), thickness);// 画特征点circle(input, Point2i(int(faces.at<float>(i, 4)), int(faces.at<float>(i, 5))), 2, Scalar(255, 0, 0), thickness);circle(input, Point2i(int(faces.at<float>(i, 6)), int(faces.at<float>(i, 7))), 2, Scalar(0, 0, 255), thickness);circle(input, Point2i(int(faces.at<float>(i, 8)), int(faces.at<float>(i, 9))), 2, Scalar(0, 255, 0), thickness);circle(input, Point2i(int(faces.at<float>(i, 10)), int(faces.at<float>(i, 11))), 2, Scalar(255, 0, 255), thickness);circle(input, Point2i(int(faces.at<float>(i, 12)), int(faces.at<float>(i, 13))), 2, Scalar(0, 255, 255), thickness);}
}int main(int argc, char** argv)
{Mat image1 = imread("person_tong1.jpg");Mat image2 = imread("person_tong2.jpg");if (image1.empty() || image2.empty()){cout << "Can not open or find the image" << endl;return -1;}// 创建FaceDetectorYN实例Ptr<FaceDetectorYN> detector = FaceDetectorYN::create("face_detection_yunet_2023mar_int8.onnx", "",  Size(320, 320), 0.5);// 创建FaceRecognizerSF实例Ptr<FaceRecognizerSF> recognizer = FaceRecognizerSF::create("face_recognition_sface_2021dec_int8.onnx", "");// 调整图像尺寸Mat resized_image1;resize(image1, resized_image1, Size(320, 320));Mat resized_image2;resize(image2, resized_image2, Size(320, 320));// 检测人脸Mat faces1;detector->detect(resized_image1, faces1);Mat faces2;detector->detect(resized_image2, faces2);// 对齐并裁剪人脸Mat aligned_face1, aligned_face2;if (!faces1.empty()){recognizer->alignCrop(resized_image1, faces1.row(0), aligned_face1);}if (!faces2.empty()){recognizer->alignCrop(resized_image2, faces2.row(0), aligned_face2);}// 提取特征向量Mat embedding1;if (!aligned_face1.empty()){recognizer->feature(aligned_face1, embedding1);embedding1 = embedding1.clone();}Mat embedding2;if (!aligned_face2.empty()){recognizer->feature(aligned_face2, embedding2);embedding2 = embedding2.clone();}// 计算两张图像中人脸特征向量的相似度double similarity = 0.0;if (!embedding1.empty() && !embedding2.empty()){similarity = recognizer->match(embedding1, embedding2);cout << "Similarity: " << similarity << endl;}else{cout << "No face detected in one or both images" << endl;return -1;}// 在图像上绘制人脸框if (!faces1.empty()){DrawFaces(resized_image1, faces1);}if (!faces2.empty()){DrawFaces(resized_image2, faces2);char pszText[128] = { 0 };sprintf(pszText, "Similarity: %.2f", similarity);putText(resized_image2, pszText, Point(20, 50), FONT_HERSHEY_SIMPLEX,1.0, Scalar(0, 0, 255), 2, 8);}// 显示图像namedWindow("Face 1");imshow("Face 1", resized_image1);namedWindow("Face 2");imshow("Face 2", resized_image2);waitKey(0);destroyAllWindows();return 0;
}

        执行上面的代码,运行效果可参考下图。可以看到,两张图片中人脸的相似度达到0.61,基本可以判定为同一个人。


http://www.ppmy.cn/news/1548752.html

相关文章

C++设计模式之适配器模式与桥接模式,装饰器模式及代理模式相似点与不同点

适配器模式、桥接模式、装饰器模式和代理模式在形式上有一些相似之处&#xff0c;因为它们都涉及到对类的功能或接口的修改、增强或转换。然而&#xff0c;它们在动机和目的上有着显著的不同。以下是对这些模式相似点和不同点的清晰说明&#xff1a; 相似点&#xff1a; 结构…

uniapp微信小程序接入airkiss插件进行WIFI配网

本文可参考uniapp小程序插件 一.申请插件 微信公众平台设置页链接&#xff1a;微信公众平台 登录您的小程序微信公众平台&#xff0c;进入设置页&#xff0c;在第三方设置->插件管理->添加插件中申请AiThinkerAirkissforWXMini插件&#xff0c;申请的插件appId为【wx6…

如何建立devops?

要建立DevOps系统&#xff0c;可以遵循以下步骤&#xff1a; 一、明确目标与确立原则 明确目标&#xff1a;确定DevOps系统的总体目标&#xff0c;例如提高软件发布频率、缩短反馈时间、提升软件质量等。确立原则&#xff1a;确立DevOps的核心原则&#xff0c;包括持续集成&a…

【机器学习chp3】判别式分类器:线性判别函数、线性分类器、广义线性分类器、分段线性分类器

前言&#xff1a; 本文遗留问题&#xff1a;&#xff08;1&#xff09;对最小平方误差分类器的理解不清晰.&#xff08;2&#xff09;分段线性判别函数的局部训练法理解不清晰。 推荐文章1&#xff0c;其中有关于感知机的分析 【王木头从感知机到神经网络】-CSDN博客 推荐文…

SpringBoot项目升级到3.*,并由JDK8升级到JDK21

文章目录 技术选型说明JDK21的Demo项目下载升级过程出现的问题及解决1、程序包javax.servlet.http不存在1.1、java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter1.2、javax.validation包替换为jakarta.validation1.3、jakarta的名字由来 2、mybatis-plus升级3…

根据条件 控制layui的table的toolbar的按钮 显示和不显示

部分代码&#xff1a; <!-----查询条件-----> <input type"date" id"StartDate" onchange"PageList()" /> <input type"date" id"EndDate" onchange"PageList()" /><!-----表格Table-----&…

Python实现随机分布式延迟PSO优化算法(RODDPSO)优化CNN回归模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后关注获取。 1.项目背景 近年来&#xff0c;深度学习技术在计算机视觉、语音识别、自然语言处理等领域取得了显著的成功。卷…

C# 数据结构之【栈】C#栈

1. 描述 栈 &#xff1a;栈遵循后进先出&#xff08;LIFO&#xff09;原则&#xff0c;只能在一端进行插入和删除操作。 2. 应用示例 using System;namespace DataStructure {class Program{static async Task Main(string[] args){// 创建一个栈Stack<int> stack ne…