android 两个人脸对比 mlkit

一、先厘清核心概念

1.ML Kit 人脸比对的本质 :不是直接对比两张人脸照片,而是先提取每张人脸的人脸特征向量(128 维浮点数组),再通过计算两个特征向量的欧氏距离来判断是否为同一人(距离越小,相似度越高,通常阈值≤0.8 可判定为同一人)。
2.所需依赖 :ML Kit 提供了「人脸检测」和「人脸特征提取」两个相关 API,我们需要用到「人脸特征提取(Face Recognition)」,它支持在线(依赖 Google 服务,精度更高)和离线(本地模型,无网络依赖)两种模式,优先推荐离线模式(适配更多设备)。
3.前置条件:

最低 Android 版本:API 21(Android 5.0)

项目集成 AndroidX(主流项目已默认支持)

人脸照片要求:正面清晰、光线充足、无大面积遮挡(口罩、墨镜等)

二、实操步骤(分步落地)

步骤 1:集成 ML Kit 依赖

在项目的 build.gradle 中添加依赖(Module 级别的 build.gradle,通常是 app/build.gradle):

java 复制代码
<!-- 读取相册权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 相机权限(若需拍摄人脸) -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 声明应用使用相机功能(可选) -->
<uses-feature android:name="android.hardware.camera" android:required="false" />

同步 Gradle,确保依赖下载完成。
步骤 2:配置权限(访问照片 / 相机,可选)

如果需要从相册选择照片或相机拍摄获取人脸,在 AndroidManifest.xml 中添加权限:

java 复制代码
<!-- 读取相册权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 相机权限(若需拍摄人脸) -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 声明应用使用相机功能(可选) -->
<uses-feature android:name="android.hardware.camera" android:required="false" />

注意:Android 6.0(API 23)及以上需要动态申请权限,这里暂不展开,重点聚焦人脸比对核心逻辑。
步骤 3:核心代码实现(人脸特征提取 + 相似度计算)

完整代码包含 3 个核心方法:「提取人脸特征向量」、「计算欧氏距离」、「判断是否为同一人」,可直接复制到 Activity 或工具类中。

java 复制代码
import android.graphics.Bitmap
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.FaceDetectorOptions
import com.google.mlkit.vision.face.recognition.FaceRecognition
import com.google.mlkit.vision.face.recognition.FaceRecognitionModel
import com.google.mlkit.vision.face.recognition.FaceRecognizer
import kotlin.math.sqrt

class FaceCompareManager {
    // 1. 初始化人脸识别器(离线模式,优先推荐)
    private val faceRecognizer: FaceRecognizer by lazy {
        FaceRecognition.getClient(
            FaceRecognitionModel.FACE_RECOGNITION_MODEL_V1 // 离线模型版本
        )
    }

    // 2. 初始化人脸检测器(筛选有效人脸,避免非人脸图片干扰)
    private val faceDetector by lazy {
        val options = FaceDetectorOptions.Builder()
            .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE) // 高精度模式
            .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_NONE)
            .setContourMode(FaceDetectorOptions.CONTOUR_MODE_NONE)
            .build()
        FaceDetection.getClient(options)
    }

    // 核心方法 1:提取人脸特征向量(返回 128 维浮点数组,提取失败返回 null)
    suspend fun extractFaceFeature(bitmap: Bitmap): FloatArray? {
        return try {
            // 将 Bitmap 转换为 ML Kit 可处理的 InputImage
            val inputImage = InputImage.fromBitmap(bitmap, 0)
            
            // 第一步:先检测图片中是否有人脸
            val faces = faceDetector.process(inputImage).await()
            if (faces.isEmpty() || faces.size > 1) {
                // 无人脸或多个人脸,返回 null
                return null
            }
            val face = faces[0]
            
            // 第二步:提取该人脸的特征向量
            val faceResult = faceRecognizer.process(inputImage, face).await()
            faceResult.faceEmbedding // 返回 128 维特征向量
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    // 核心方法 2:计算两个特征向量的欧氏距离(距离越小,相似度越高)
    fun calculateEuclideanDistance(feature1: FloatArray, feature2: FloatArray): Double {
        require(feature1.size == 128 && feature2.size == 128) { "人脸特征向量必须为 128 维" }
        var sum = 0.0
        for (i in 0 until 128) {
            val diff = feature1[i] - feature2[i]
            sum += diff * diff
        }
        return sqrt(sum)
    }

    // 核心方法 3:判断是否为同一人(阈值 ≤ 0.8 判定为同一人,可根据实际场景调整)
    fun isSamePerson(distance: Double): Boolean {
        return distance <= 0.8
    }

    // 释放资源(在 Activity 销毁时调用)
    fun release() {
        faceRecognizer.close()
        faceDetector.close()
    }
}

步骤 4:调用示例(在 Activity 中使用)

java 复制代码
 import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.graphics.BitmapFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class MainActivity : AppCompatActivity() {
    private lateinit var faceCompareManager: FaceCompareManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        faceCompareManager = FaceCompareManager()
        
        // 模拟:从本地资源读取两张人脸照片进行比对
        GlobalScope.launch(Dispatchers.Main) {
            val bitmap1 = BitmapFactory.decodeResource(resources, R.drawable.face1)
            val bitmap2 = BitmapFactory.decodeResource(resources, R.drawable.face2)
            
            val result = compareTwoFaces(bitmap1, bitmap2)
            if (result.first) {
                // 同一人
                println("人脸比对成功:是同一人,欧氏距离:${result.second}")
            } else {
                // 非同一人
                println("人脸比对失败:非同一人,欧氏距离:${result.second}")
            }
        }
    }

    // 封装比对逻辑
    private suspend fun compareTwoFaces(bitmap1: Bitmap, bitmap2: Bitmap): Pair<Boolean, Double> {
        return withContext(Dispatchers.IO) {
            // 提取两张人脸的特征向量
            val feature1 = faceCompareManager.extractFaceFeature(bitmap1)
            val feature2 = faceCompareManager.extractFaceFeature(bitmap2)
            
            if (feature1 == null || feature2 == null) {
                // 特征提取失败(无人脸、多人脸或异常)
                Pair(false, Double.MAX_VALUE)
            } else {
                // 计算欧氏距离
                val distance = faceCompareManager.calculateEuclideanDistance(feature1, feature2)
                // 判断是否为同一人
                Pair(faceCompareManager.isSamePerson(distance), distance)
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        // 释放资源
        faceCompareManager.release()
    }
}

三、关键说明与注意事项

**协程使用:**上述代码使用了 Kotlin 协程(await())处理 ML Kit 的异步任务,避免主线程阻塞,若你使用 Java,可通过 addOnSuccessListener 和 addOnFailureListener 处理回调。

**阈值调整:**默认阈值 0.8 是通用参考值,实际项目中可根据测试数据调整(如对精度要求高可设为 0.6,对容错率要求高可设为 1.0)。
图片预处理:

建议将图片缩放到合适尺寸(如 640×480),减少计算耗时。

确保人脸正面朝向,光线均匀,避免侧脸、逆光、大面积遮挡,否则会导致特征提取失败或相似度判断偏差。
性能优化:

离线模型首次使用时会下载本地模型(约几十 MB),建议在 Wi-Fi 环境下完成。

人脸特征提取是耗时操作,必须在子线程执行,不可在主线程调用。

错误处理:需捕获 Exception(如模型下载失败、图片格式不支持、人脸检测失败等),提升应用健壮性。

四、总结

Android ML Kit 人脸比对的核心是「提取 128 维特征向量 + 计算欧氏距离」,而非直接比对图片。

落地核心步骤:集成离线依赖 → 初始化识别器 / 检测器 → 提取特征 → 计算距离 → 阈值判断。

关键优化点:图片预处理、子线程执行、合理调整阈值、及时释放资源,同时注意权限申请。

相关推荐
darkb1rd3 小时前
五、PHP类型转换与类型安全
android·安全·php
gjxDaniel4 小时前
Kotlin编程语言入门与常见问题
android·开发语言·kotlin
csj504 小时前
安卓基础之《(22)—高级控件(4)碎片Fragment》
android
峥嵘life4 小时前
Android16 【CTS】CtsMediaCodecTestCases等一些列Media测试存在Failed项
android·linux·学习
stevenzqzq5 小时前
Compose 中的状态可变性体系
android·compose
似霰6 小时前
Linux timerfd 的基本使用
android·linux·c++
darling3317 小时前
mysql 自动备份以及远程传输脚本,异地备份
android·数据库·mysql·adb
你刷碗8 小时前
基于S32K144 CESc生成随机数
android·java·数据库
TheNextByte18 小时前
Android上的蓝牙文件传输:跨设备无缝共享
android