Android 实现活体人脸识别检测


一、项目背景详细介绍

随着人脸识别在金融、政务、安防、教育、互联网应用等场景中的广泛应用,安全性问题逐渐被重视。传统的人脸识别仅仅检测用户的面部特征向量,无法有效区分真实人脸与照片、视频或3D模型,这带来了严重的风险。

为了解决这一问题,业界普遍引入了 活体检测 技术,即在识别人脸的同时验证被检测对象是否为“真实活体”。

常见的活体检测方式:

  1. 动作活体检测:要求用户完成随机动作(如眨眼、张嘴、点头)。

  2. 纹理活体检测:基于图像深度、反射光特征判断。

  3. 3D 深度活体检测:通过红外摄像头采集深度信息。

本文将实现一个 基于动作活体检测(眨眼、张嘴、点头)的 Android Demo,用户启动 App 后摄像头捕捉人脸,检测其动作,从而验证其为真实用户。


二、项目需求详细介绍

  1. 打开 App 时启动前置摄像头,实时预览用户人脸。

  2. 检测到人脸后,随机给出活体检测指令(如“请眨眼”、“请张嘴”)。

  3. 通过人脸关键点检测(眼睛、嘴巴位置)来判断用户是否完成动作。

  4. 若完成动作,判定通过活体检测;否则提示失败。

  5. 代码实现需保证可扩展,方便接入第三方人脸识别 SDK(如百度、旷视、商汤等)。


三、相关技术详细介绍

  1. CameraX/Camera2 API

    • 用于调用 Android 摄像头并获取实时预览帧。

  2. 人脸关键点检测技术

    • Google ML Kit 提供人脸检测 API,可获取眼睛、嘴巴等位置。

    • 也可接入 OpenCV 或第三方 SDK。

  3. 活体检测算法

    • 眨眼检测:眼睛开合状态变化。

    • 张嘴检测:嘴巴高度与人脸比例。

    • 点头检测:人脸关键点上下移动轨迹。

  4. 随机动作挑战

    • 为了防止“视频伪造攻击”,指令需随机生成,避免用户提前准备。


四、实现思路详细介绍

  1. 摄像头初始化

    • 使用 CameraX 预览前置摄像头画面。

  2. 人脸检测

    • 使用 ML Kit Face Detection 获取眼睛、嘴巴关键点坐标。

  3. 动作识别逻辑

    • 眨眼:眼睛长宽比(EAR)< 阈值,且两次变化。

    • 张嘴:嘴巴高度/宽度 > 阈值。

    • 点头:鼻子纵向坐标大幅波动。

  4. 检测流程

    • 随机生成任务(眨眼/张嘴/点头)。

    • 实时监测关键点,判断是否完成任务。

    • 输出活体检测结果。


五、完整实现代码

// =====================================================
// 文件:app/src/main/res/layout/activity_main.xml
// 描述:主界面布局,包含一个预览界面和提示文字
// =====================================================
/*
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- 摄像头预览控件 -->
    <androidx.camera.view.PreviewView
        android:id="@+id/previewView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- 提示活体检测指令 -->
    <TextView
        android:id="@+id/tvInstruction"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="请正对摄像头"
        android:textSize="20sp"
        android:textColor="#FFFFFF"
        android:background="#80000000"
        android:padding="12dp"
        android:layout_gravity="center_horizontal|top"
        android:margin="20dp"/>
</FrameLayout>
*/


// =====================================================
// 文件:MainActivity.java
// 描述:活体检测主逻辑
// =====================================================
package com.example.livenessdemo;

import android.os.Bundle;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;

import com.google.common.util.concurrent.ListenableFuture;
import com.google.mlkit.vision.common.InputImage;
import com.google.mlkit.vision.face.Face;
import com.google.mlkit.vision.face.FaceDetection;
import com.google.mlkit.vision.face.FaceDetector;
import com.google.mlkit.vision.face.FaceDetectorOptions;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainActivity extends AppCompatActivity {

    private PreviewView previewView;
    private TextView tvInstruction;
    private FaceDetector faceDetector;
    private ExecutorService cameraExecutor;
    private String currentTask; // 当前活体任务
    private boolean taskCompleted = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        previewView = findViewById(R.id.previewView);
        tvInstruction = findViewById(R.id.tvInstruction);

        // 初始化摄像头
        startCamera();

        // 初始化人脸检测器(高精度模式)
        FaceDetectorOptions options = new FaceDetectorOptions.Builder()
                .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)
                .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
                .enableTracking()
                .build();
        faceDetector = FaceDetection.getClient(options);

        // 随机生成活体检测任务
        currentTask = getRandomTask();
        tvInstruction.setText("请 " + currentTask);

        cameraExecutor = Executors.newSingleThreadExecutor();
    }

    private void startCamera() {
        ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
                ProcessCameraProvider.getInstance(this);

        cameraProviderFuture.addListener(() -> {
            try {
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

                // 构建预览
                androidx.camera.core.Preview preview = new androidx.camera.core.Preview.Builder().build();
                preview.setSurfaceProvider(previewView.getSurfaceProvider());

                // 图像分析器
                ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                        .build();

                imageAnalysis.setAnalyzer(cameraExecutor, imageProxy -> {
                    analyzeImage(imageProxy);
                });

                // 使用前置摄像头
                CameraSelector cameraSelector = new CameraSelector.Builder()
                        .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
                        .build();

                // 绑定生命周期
                cameraProvider.unbindAll();
                cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }, ContextCompat.getMainExecutor(this));
    }

    private void analyzeImage(@NonNull ImageProxy imageProxy) {
        if (imageProxy.getImage() == null) {
            imageProxy.close();
            return;
        }

        InputImage image = InputImage.fromMediaImage(imageProxy.getImage(), imageProxy.getImageInfo().getRotationDegrees());

        faceDetector.process(image)
                .addOnSuccessListener(faces -> {
                    if (!faces.isEmpty()) {
                        checkLiveness(faces.get(0));
                    }
                    imageProxy.close();
                })
                .addOnFailureListener(e -> {
                    imageProxy.close();
                });
    }

    // 检查用户是否完成任务
    private void checkLiveness(Face face) {
        if (taskCompleted) return;

        switch (currentTask) {
            case "眨眼":
                if (face.getLeftEyeOpenProbability() != null && face.getRightEyeOpenProbability() != null) {
                    float left = face.getLeftEyeOpenProbability();
                    float right = face.getRightEyeOpenProbability();
                    if (left < 0.4 && right < 0.4) {
                        runOnUiThread(() -> tvInstruction.setText("活体检测通过"));
                        taskCompleted = true;
                    }
                }
                break;

            case "张嘴":
                if (face.getSmilingProbability() != null && face.getSmilingProbability() > 0.6) {
                    runOnUiThread(() -> tvInstruction.setText("活体检测通过"));
                    taskCompleted = true;
                }
                break;

            case "点头":
                // 简化:通过 Euler Y 角度(上下点头)
                float headEulerY = face.getHeadEulerAngleY();
                if (Math.abs(headEulerY) > 15) {
                    runOnUiThread(() -> tvInstruction.setText("活体检测通过"));
                    taskCompleted = true;
                }
                break;
        }
    }

    private String getRandomTask() {
        String[] tasks = {"眨眼", "张嘴", "点头"};
        return tasks[new Random().nextInt(tasks.length)];
    }
}

六、代码详细解读

  1. activity_main.xml

    • 使用 PreviewView 显示摄像头画面。

    • TextView 用于实时提示当前活体检测任务。

  2. MainActivity.java

    • 初始化 CameraX,获取实时帧。

    • 使用 Google ML Kit 检测人脸与关键点。

    • 随机分配活体检测任务(眨眼/张嘴/点头)。

    • 根据检测结果更新 UI。


七、项目详细总结

本文实现了一个简易的 活体人脸检测 Demo,利用 Google ML Kit 的人脸检测功能,结合摄像头实时预览,完成了“眨眼、张嘴、点头”动作的活体检测。

虽然该方案能满足基本演示需求,但在实际商用场景中,往往需要:

  • 更加复杂的随机动作组合。

  • 更精确的面部特征点检测。

  • 防御视频、3D 假体攻击。

因此,最终落地应用中通常需要接入专业的第三方 SDK(如百度智能云、商汤 SenseTime、旷视 Face++)。


八、项目常见问题及解答

  1. 为什么 ML Kit 检测不到眼睛开合?

    • 确认 FaceDetectorOptions 开启了 LANDMARK_MODE_ALL

    • 保证光线充足,避免强逆光。

  2. 检测延迟怎么办?

    • 可降低 ImageAnalysis 分辨率,减少处理开销。

  3. 如何防止视频攻击?

    • 单一动作检测无法完全防御,需要结合多模态检测(红外、深度摄像头、动作组合)。


九、扩展方向与性能优化

  1. 多动作组合验证

    • 一次检测需要依次完成多个动作,例如“眨眼 + 张嘴 + 点头”,安全性更高。

  2. 接入深度摄像头

    • 使用 ToF/红外摄像头检测深度信息,防御平面攻击。

  3. AI 活体检测模型

    • 使用 CNN/RNN 训练模型,基于光流、纹理特征区分真实人脸与照片视频。

  4. 与人脸识别结合

    • 先通过活体检测,再进行身份比对,提高整体安全性。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐