Android实现活体人脸识别检测(附带源码)
Android 实现活体人脸识别检测
一、项目背景详细介绍
随着人脸识别在金融、政务、安防、教育、互联网应用等场景中的广泛应用,安全性问题逐渐被重视。传统的人脸识别仅仅检测用户的面部特征向量,无法有效区分真实人脸与照片、视频或3D模型,这带来了严重的风险。
为了解决这一问题,业界普遍引入了 活体检测 技术,即在识别人脸的同时验证被检测对象是否为“真实活体”。
常见的活体检测方式:
-
动作活体检测:要求用户完成随机动作(如眨眼、张嘴、点头)。
-
纹理活体检测:基于图像深度、反射光特征判断。
-
3D 深度活体检测:通过红外摄像头采集深度信息。
本文将实现一个 基于动作活体检测(眨眼、张嘴、点头)的 Android Demo,用户启动 App 后摄像头捕捉人脸,检测其动作,从而验证其为真实用户。
二、项目需求详细介绍
-
打开 App 时启动前置摄像头,实时预览用户人脸。
-
检测到人脸后,随机给出活体检测指令(如“请眨眼”、“请张嘴”)。
-
通过人脸关键点检测(眼睛、嘴巴位置)来判断用户是否完成动作。
-
若完成动作,判定通过活体检测;否则提示失败。
-
代码实现需保证可扩展,方便接入第三方人脸识别 SDK(如百度、旷视、商汤等)。
三、相关技术详细介绍
-
CameraX/Camera2 API
-
用于调用 Android 摄像头并获取实时预览帧。
-
-
人脸关键点检测技术
-
Google ML Kit 提供人脸检测 API,可获取眼睛、嘴巴等位置。
-
也可接入 OpenCV 或第三方 SDK。
-
-
活体检测算法
-
眨眼检测:眼睛开合状态变化。
-
张嘴检测:嘴巴高度与人脸比例。
-
点头检测:人脸关键点上下移动轨迹。
-
-
随机动作挑战
-
为了防止“视频伪造攻击”,指令需随机生成,避免用户提前准备。
-
四、实现思路详细介绍
-
摄像头初始化
-
使用 CameraX 预览前置摄像头画面。
-
-
人脸检测
-
使用 ML Kit Face Detection 获取眼睛、嘴巴关键点坐标。
-
-
动作识别逻辑
-
眨眼:眼睛长宽比(EAR)< 阈值,且两次变化。
-
张嘴:嘴巴高度/宽度 > 阈值。
-
点头:鼻子纵向坐标大幅波动。
-
-
检测流程
-
随机生成任务(眨眼/张嘴/点头)。
-
实时监测关键点,判断是否完成任务。
-
输出活体检测结果。
-
五、完整实现代码
// =====================================================
// 文件: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)];
}
}
六、代码详细解读
-
activity_main.xml
-
使用
PreviewView显示摄像头画面。 -
TextView用于实时提示当前活体检测任务。
-
-
MainActivity.java
-
初始化 CameraX,获取实时帧。
-
使用 Google ML Kit 检测人脸与关键点。
-
随机分配活体检测任务(眨眼/张嘴/点头)。
-
根据检测结果更新 UI。
-
七、项目详细总结
本文实现了一个简易的 活体人脸检测 Demo,利用 Google ML Kit 的人脸检测功能,结合摄像头实时预览,完成了“眨眼、张嘴、点头”动作的活体检测。
虽然该方案能满足基本演示需求,但在实际商用场景中,往往需要:
-
更加复杂的随机动作组合。
-
更精确的面部特征点检测。
-
防御视频、3D 假体攻击。
因此,最终落地应用中通常需要接入专业的第三方 SDK(如百度智能云、商汤 SenseTime、旷视 Face++)。
八、项目常见问题及解答
-
为什么 ML Kit 检测不到眼睛开合?
-
确认 FaceDetectorOptions 开启了
LANDMARK_MODE_ALL。 -
保证光线充足,避免强逆光。
-
-
检测延迟怎么办?
-
可降低
ImageAnalysis分辨率,减少处理开销。
-
-
如何防止视频攻击?
-
单一动作检测无法完全防御,需要结合多模态检测(红外、深度摄像头、动作组合)。
-
九、扩展方向与性能优化
-
多动作组合验证
-
一次检测需要依次完成多个动作,例如“眨眼 + 张嘴 + 点头”,安全性更高。
-
-
接入深度摄像头
-
使用 ToF/红外摄像头检测深度信息,防御平面攻击。
-
-
AI 活体检测模型
-
使用 CNN/RNN 训练模型,基于光流、纹理特征区分真实人脸与照片视频。
-
-
与人脸识别结合
-
先通过活体检测,再进行身份比对,提高整体安全性。
-
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)