人脸活体识别3:C/C++实现人脸眨眼 张嘴 点头 摇头识别(可实时检测)

人脸活体识别3:C/C++实现人脸眨眼 张嘴 点头 摇头识别(可实时检测)

目录

[人脸活体识别3:C/C++实现人脸眨眼 张嘴 点头 摇头识别(可实时检测)](#人脸活体识别3:C/C++实现人脸眨眼 张嘴 点头 摇头识别(可实时检测))

[1. 前言](#1. 前言)

2.人脸活体识别方法

(1)基于人脸动作的检测​​

(2)​​基于红外的活体识别​​

(3)基于深度的活体识别​​

3.人脸检测模型

[4. 活体识别模型](#4. 活体识别模型)

[(1) 将Pytorch模型转换ONNX模型](#(1) 将Pytorch模型转换ONNX模型)

[(2) 将Pytorch模型转换为NCNN模型](#(2) 将Pytorch模型转换为NCNN模型)

[5. 活体识别C++端上部署](#5. 活体识别C++端上部署)

[(1) 项目结构](#(1) 项目结构)

[(2) 配置开发环境(OpenCV+vulkan+base-utils+NCNN)](#(2) 配置开发环境(OpenCV+vulkan+base-utils+NCNN))

[(3) 部署NCNN模型](#(3) 部署NCNN模型)

(4)CMake配置

(5)main源码

(6)源码编译和运行

6.活体识别效果(C/C++版本)

7.活体识别效果(Android版本)

[8. 项目源码下载](#8. 项目源码下载)


1. 前言

人脸活体识别技术是确保人脸识别系统安全性的关键,主要用于区分真实人脸与伪造攻击(如照片、视频、3D面具等)。本项目基于深度学习技术,构建了一套高鲁棒性的面部活体检测系统,可精准识别眨眼(闭眼)、张嘴、点头(低头)、摇头(侧脸)等生物特征动作,可有效防范照片、视频、3D面具等伪造攻击等多种场景,​​可应用于金融支付、远程身份核验(如银行开户)等场景。

整套项目分为人脸活体识别数据集说明,模型开发和训练,模型边缘侧部署C++/Android等多个章节,本篇是项目《​​​​人脸活体识别》系列文章之《C/C++实现人脸眨眼 张嘴 点头 摇头识别》;为了方便后续模型工程化和Android平台部署,项目对活体识别模型进行轻量化,并提供Python/C++/Android多个版本;

整套活体识别系统,在普通Android手机上可以达到实时的检测效果,CPU(4线程)约40ms左右,GPU约30ms左右 ,基本满足业务的性能需求。准确率还挺高的,采用轻量级mobilenet_v2模型的人脸活体识别准确率也可以高达99.9661%左右,满足业务性能需求。

|---------------|----------------|-------------|
| 模型 | input size | Test准确率 |
| Mobilenet | 112×112 | 99.9661 |
| Resnet18 | 112×112 | 99.9322 |
| MobileVit | 112×112 | 99.9322 |

【尊重原创,转载请注明出处】https://blog.csdn.net/guyuealian/article/details/148774226


更多人脸识别和活体识别文章,请参考:

  1. 人脸活体识别1:眨眼 张嘴 点头 摇头人脸数据集
  2. 人脸活体识别2:Pytorch实现人脸眨眼 张嘴 点头 摇头识别(含训练代码和数据集)
  3. 人脸活体识别3:C/C++实现人脸眨眼 张嘴 点头 摇头识别(可实时检测)
  4. 人脸活体识别4:Android实现人脸眨眼 张嘴 点头 摇头识别(可实时检测)
  5. 人脸识别2:InsightFace实现人脸识别Face Recognition(含源码下载)
  6. 人脸识别3:C/C++ InsightFace实现人脸识别Face Recognition(含源码)
  7. 人脸识别4:Android InsightFace实现人脸识别Face Recognition(含源码)

2.人脸活体识别方法

人脸活体识别的方法有很多,如基于人脸动作的活体识别​,基于红外的活体识别,基于深度的活体识别等等方法。

(1)基于人脸动作的检测​​

要求用户配合完成随机指令动作(如眨眼、点头、张嘴、摇头等),通过计算机视觉算法(如光流法、关键点跟踪)分析动作的自然性和时序连贯性。

优点​​:实现简单,能有效抵御照片和静态视频攻击。​​

缺点​​:依赖用户配合,体验较差;可能被高仿动态视频(如Deepfake)欺骗。

(2)​​基于红外的活体识别​​

​​ 利用红外摄像头捕捉人脸的红外反射特性或热辐射分布,如采用红外光谱分析​​,活体皮肤对特定波长红外光的吸收/反射模式与非活体不同。​​

优点​​:无需用户配合,可抵御照片、视频及部分3D面具攻击。

缺点​​:设备成本较高;受环境温度影响(如低温可能降低检测精度)。

(3)基于深度的活体识别​​

通过3D深度摄像头(如结构光、ToF)获取人脸的三维几何信息(如鼻梁高度、曲面曲率),非活体(照片、屏幕)缺乏真实的深度结构。​​

优点​​:防御能力最强,可识别高级3D头套攻击。

​​缺点​​:硬件成本高,需专用3D传感器。

本项目实现方案是采用基于人脸动作的活体识别方法,即先采用通用的人脸检测模型,进行人脸检测定位人脸区域,然后按照一定规则裁剪人脸检测区域,再训练一个人脸活体识别 分类器,完成人脸活体识别的任务。人脸动作主要包含:眨眼(闭眼)、张嘴、点头(低头)、摇头(侧脸)。


3.人脸检测模型

本项目人脸检测训练代码请参考:https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB

这是一个基于SSD改进且轻量化后人脸检测模型,很slim,整个模型仅仅1.7M左右,在普通Android手机都可以实时检测。人脸检测方法在网上有一大堆现成的方法可以使用,完全可以不局限我这个方法。

当然可以基于YOLOv5训练一个人脸检测模型:人脸检测和行人检测2:YOLOv5实现人脸检测和行人检测(含数据集和训练代码)


4. 活体识别模型

关于人脸活体识别模型训练,请参考《人脸活体识别2:Pytorch实现人脸眨眼 张嘴 点头 摇头识别(含训练代码和数据集)

整套活体识别系统,在NCNN加速下,可以达到实时的检测效果,基本满足业务的性能需求。下表格给出MobilenetResnet18MobileVit模型识别的准确率:

|---------------|----------------|-------------|
| 模型 | input size | Test准确率 |
| Mobilenet | 112×112 | 99.9661 |
| Resnet18 | 112×112 | 99.9322 |
| MobileVit | 112×112 | 99.9322 |

模型训练完成后,需要将Pytorch模型转换为NCNN格式,转换方法请参考如下

考虑到端上硬件处理性能比较弱鸡,项目C++和Android部署仅使用Mobilenet模型。

(1) 将Pytorch模型转换ONNX模型

项目Python源码提供了转换工具,可实现将Pytorch的模型转换为ONNX模型文件,且文件会默认保存在Pytorch的模型文件同一目录下。

bash 复制代码
python libs/convertor/convert2onnx.py

(2) 将Pytorch模型转换为NCNN模型

你也可以一步到位,使用PNNX工具,直接将Pytorch模型直接转换为NCNN文件

bash 复制代码
python libs/convertor/convert2ncnn.py

NCNN转换工具说明,请参考:


5. 活体识别C++端上部署

(1) 项目结构

(2) 配置开发环境(OpenCV+vulkan+base-utils+NCNN)

项目仅在Ubuntu18.04进行测试,Windows系统下请自行配置和编译

  • 安装OpenCV:图像处理

图像处理(如读取图片,图像裁剪等)都需要使用OpenCV库进行处理

安装教程:Ubuntu18.04安装opencv和opencv_contrib

OpenCV库使用opencv-4.3.0版本,opencv_contrib库暂时未使用,可不安装

  • 安装vulkan:模型加速

安装教程:Ubuntu18.04安装Vulkan SDK教程方法

vulkan 用于模型GPU加速,若不使用****vulkan****进行模型推理加速,纯C++推理模型,速度可能会比较慢

  • base-utils:C++库

GitHub:https://github.com/PanJinquan/base-utils (无需安装,项目已经配置了)

base_utils是个人开发常用的C++库,集成了C/C++ OpenCV等常用的算法

  • NCNN:模型推理

GitHub:https://github.com/Tencent/ncnn (无需安装,项目已经配置了)

ncnn 是一个为手机端极致优化的高性能神经网络前向计算框架。 ncnn 从设计之初深刻考虑手机端的部署和使用。 无第三方依赖,跨平台,手机端 cpu 的速度快于目前所有已知的开源框架。 基于 ncnn,开发者能够将深度学习算法轻松移植到手机端高效执行, 开发出人工智能 APP,将 AI 带到你的指尖。 ncnn 目前已在腾讯多款应用中使用,如:QQ,Qzone,微信,天天 P 图等。

(3) 部署NCNN模型

项目实现了C/C++版本的活体识别,模型推理采用NCNN部署框架(支持多线程CPU和GPU加速推理);图像处理采用OpenCV库,模型加速采用****vulkan****,在普通设备即可达到实时处理。

如果你想在这个 Demo部署你自己训练的活体识别模型,你可将训练好的Pytorch模型转换为NCNN模型,然后把原始的模型替换成你自己的NCNN模型即可。

(4)CMake配置

这是CMakeLists.txt,其中主要配置OpenCV+vulkan+base-utils+NCNN这四个库,Windows系统下请自行配置和编译

bash 复制代码
cmake_minimum_required(VERSION 3.14.0)
project(Detector)

#set(CMAKE_BUILD_TYPE Debug)
add_compile_options(-fPIC) # fix Bug: can not be used when making a shared object
set(CMAKE_CXX_FLAGS "-Wall -std=c++11 -pthread")
#set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
#set(CMAKE_CXX_FLAGS_DEBUG "-g")

if (NOT CMAKE_BUILD_TYPE)
    # -DCMAKE_BUILD_TYPE=Debug
    # -DCMAKE_BUILD_TYPE=Release
    message(STATUS "No build type selected, default to Release")
    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type (default Debug)" FORCE)
endif ()


# NCNN set
set(NCNN_OPENMP ON CACHE BOOL "" FORCE)
set(NCNN_VULKAN ON CACHE BOOL "" FORCE)
set(NCNN_BUILD_TOOLS OFF CACHE BOOL "" FORCE)
set(NCNN_COMPILER_SUPPORT_X86_AVX OFF CACHE BOOL "" FORCE)
set(NCNN_COMPILER_SUPPORT_X86_AVX2 OFF CACHE BOOL "" FORCE)
set(NCNN_AVX OFF CACHE BOOL "" FORCE)
set(NCNN_AVXVNNI OFF CACHE BOOL "" FORCE)
#set(NCNN_SHARED_LIB ON CACHE BOOL "" FORCE)
set(NCNN_THREADS ON CACHE BOOL "" FORCE)
set(NCNN_BF16 ON CACHE BOOL "" FORCE)
set(NCNN_DISABLE_RTTI OFF CACHE BOOL "" FORCE)


if (CMAKE_SYSTEM_NAME MATCHES "Android")
    add_definitions(-DDEBUG_ANDROID_ON)            # for Android Log
    add_definitions(-DPLATFORM_ANDROID)
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
    add_definitions(-DDEBUG_ON)                    # for WIN/Linux Log
    add_definitions(-DDEBUG_LOG_ON)                # for WIN/Linux Log
    add_definitions(-DDEBUG_IMSHOW_OFF)            # for OpenCV show
    add_definitions(-DPLATFORM_LINUX)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
    add_definitions(-DDEBUG_ON)                    # for WIN/Linux Log
    add_definitions(-DDEBUG_LOG_ON)                # for WIN/Linux Log
    add_definitions(-DDEBUG_IMSHOW_OFF)            # for OpenCV show
    add_definitions(-DPLATFORM_WINDOWS)
endif ()
add_subdirectory(3rdparty/ncnn ncnn_build)
include_directories(3rdparty/ncnn/src)


# VULKAN set
set(VULKAN_SDK "3rdparty/vulkansdk/1.3.280.1/x86_64")


# opencv set
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS} ./src/)
#MESSAGE(STATUS "OpenCV_INCLUDE_DIRS = ${OpenCV_INCLUDE_DIRS}")

# base_utils
set(BASE_ROOT 3rdparty/base-utils) # 设置base-utils所在的根目录
add_subdirectory(${BASE_ROOT}/base_utils/ base_build) # 添加子目录到build中
include_directories(${BASE_ROOT}/base_utils/include)
include_directories(${BASE_ROOT}/base_utils/src)
MESSAGE(STATUS "BASE_ROOT = ${BASE_ROOT}")

# Detector
include_directories(src)
set(SRC_LIST
        src/Interpreter.cpp
        src/object_detection.cpp
        src/classifier.cpp)
add_library(dlcv SHARED ${SRC_LIST})
target_link_libraries(dlcv ncnn ${OpenCV_LIBS} base_utils)
MESSAGE(STATUS "DIR_SRCS = ${SRC_LIST}")

add_executable(Detector src/main_classifier.cpp)
target_link_libraries(Detector dlcv -lpthread)

(5)main源码

主程序中实现了**人脸活体识别,**其中test_image_file()实现测试图片,test_video_file()实现测试视频文件,test_camera()实现测试摄像头

cpp 复制代码
//
// Created by Pan on 2018/6/24.
//
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <vector>
#include <string>
#include "classifier.h"
#include "object_detection.h"
#include "Types.h"
#include "file_utils.h"
#include "image_utils.h"

using namespace dl;
using namespace vision;
using namespace std;

int numThread = 8;
DeviceType device = GPU; // 使用GPU运行,需要配置好vulkan
//DeviceType device = CPU; // 使用CPU运行


string det_bin_file = "../data/model/face/rfb_face_416.bin";
string det_pam_file = "../data/model/face/rfb_face_416.param";
// 测试图片数据
string image_dir = "../data/test_image/person";
// 初始化人脸和关键点检测
DetParam model_param = FACE_MODEL;
ObjectDetection *detector = new ObjectDetection(det_bin_file,
                                                det_pam_file,
                                                model_param,
                                                numThread,
                                                device);

string rec_bin_file = "../data/model/class/face_gesture_112_112.bin";
string rec_pam_file = "../data/model/class/face_gesture_112_112.param";
// 设置检测阈值
RecParam param = REC_MODEL;
Classifier *classifier = new Classifier(rec_bin_file,
                                        rec_pam_file,
                                        param,
                                        numThread,
                                        device);


/***
 * 测试图片文件
 * @return
 */
int test_image_file() {
    // 测试图片
    string image_dir = "../data/test_image";
    vector<string> image_list = get_files_list(image_dir);
    for (string image_path: image_list) {
        cv::Mat frame = cv::imread(image_path);
        if (frame.empty()) continue;
        FrameInfo resultInfo;
        // 开始检测
        detector->detect(frame, &resultInfo);
        //
        classifier->detect(frame, &resultInfo);
        // 可视化代码
        classifier->visualizeResult(frame, &resultInfo, 0);
    }
    printf("FINISHED.\n");
    return 0;
}


/***
 * 测试视频文件
 * @return
 */
int test_video_file() {
    string video_file = "../data/video/test-video.mp4"; //视频文件
    cv::VideoCapture cap;
    bool ret = get_video_capture(video_file, cap);
    cv::Mat frame;
    while (ret) {
        cap >> frame;
        if (frame.empty()) break;
        FrameInfo resultInfo;
        // 开始检测
        detector->detect(frame, &resultInfo);
        //
        classifier->detect(frame, &resultInfo);
        // 可视化代码
        classifier->visualizeResult(frame, &resultInfo, 10);
    }
    cap.release();
    delete detector;
    detector = nullptr;
    printf("FINISHED.\n");
    return 0;
}


/***
 * 测试摄像头
 * @return
 */
int test_camera() {
    int camera = 0; //摄像头ID号(请修改成自己摄像头ID号)
    cv::VideoCapture cap;
    bool ret = get_video_capture(camera, cap);
    cv::Mat frame;
    while (ret) {
        cap >> frame;
        if (frame.empty()) break;
        FrameInfo resultInfo;
        // 开始检测
        detector->detect(frame, &resultInfo);
        //
        classifier->detect(frame, &resultInfo);
        // 可视化代码
        classifier->visualizeResult(frame, &resultInfo, 10);
    }
    cap.release();
    delete detector;
    detector = nullptr;
    printf("FINISHED.\n");
    return 0;

}


int main() {
//    test_image_file();
    test_video_file();
    //test_camera();
    return 0;
}

(6)源码编译和运行

编译脚本,或者直接:bash build.sh

bash 复制代码
#!/usr/bin/env bash
if [ ! -d "build/" ];then
  mkdir "build"
else
  echo "exist build"
fi
cd build
cmake ..
make -j4
sleep 1
./demo
  • 如果你要测试GPU运行的性能,请修改src/main_classifier.cpp

DeviceType device = CPU;

  • 如果你要测试GPU运行的性能,请修改src/main_crnn.cpp (需配置好vulkan

DeviceType device = GPU;

下面截图给出开启vulkan 加速的性能对比截图,纯C++推理模式需要耗时几百毫秒的时间,而开启vulkan加速后,GPU模式耗时仅需十几毫秒,性能极大的提高。


6.活体识别效果(C/C++版本)

C++版本的opencv不支持中文显示,暂时未解决这个BUG,不过LOG会打印检测信息,凑合的用吧。

下图GIF这是Python版本的活体识别效果,C++版本与Python版本的结果几乎是一致


7.活体识别效果(Android版本)

项目已经完成Android版本人脸活体识别算法开发,APP在普通Android手机上可以达到实时的检测和识别效果,CPU(4线程)约40ms左右,GPU约30ms左右 ,基本满足业务的性能需求。详细说明请查看:人脸活体识别4:Android实现人脸眨眼 张嘴 点头 摇头识别(可实时检测)

Android Demo体验:https://download.csdn.net/download/guyuealian/91133467


8. 项目源码下载

如需下载项目源码,请WX关注【AI吃大瓜】,回复【活体识别】即可下载

项目资源内容包含:

  1. 提供轻量化人脸检测模型
  2. 提供轻量化人脸活体识别模型(Mobilenet),支持眨眼(闭眼)、张嘴、点头(低头)、摇头(侧脸)动作识别,识别准确率可以高达99.9661%左右。
  3. 提供整套人脸活体识别C++项目源码
  4. C++ Demo源码支持二次开发
  5. C++ Demo支持图片,视频和摄像头测试
  6. C++ Demo支持CPU和GPU,GPU模型加速需要配置好****vulkan**** ,否则速度较慢;CPU模式推理需要耗时40ms左右,而开启vulkan加速后,GPU模式耗时仅需30ms左右