You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin集成Google ML Kit实现人脸环形录入动作检测卡顿问题

Google ML Kit人脸环形录入检测问题排查

问题背景

  • 开发目标:基于Google ML Kit实现类iOS的人脸环形转动录入效果
  • 参考效果:
    人脸环形录入参考示意图
  • 当前进度:除环形动作检测逻辑外,其余功能均开发完成
  • 现存异常:现有角度判断逻辑存在检测卡顿问题,仅能识别部分左转、右转动作,整体检测流畅度远低于iOS Face ID效果
  • 现有判断代码:
private fun Direction(): Boolean {
    if (angley in 20f..25f && anglez in 2.0f..6.0f) {
        return true
    }
    return false
}
  • 参数来源:angley 取自ML Kit返回的face.headEulerAngleY字段,anglez取自ML Kit返回的face.headEulerAngleZ字段

当前方案核心缺失点

  • 角度区间设置不合理
    写死的20°25°(Y轴)、2°6°(Z轴)区间范围过窄,ML Kit实时返回的欧拉角本身存在±3°左右的检测抖动,加上不同用户握持手机的姿态、转动幅度存在差异,窄区间很容易出现角度短暂超出范围的情况,直接导致检测卡顿、漏识别。
  • 检测维度缺失
    环形转动是头部沿圆周方向的连续动作,需要同时覆盖左转/右转(Y轴)、抬头/低头(X轴)、左右倾斜(Z轴)三个维度的角度变化,现有逻辑仅判断Y、Z轴的单段固定角度,完全没有接入headEulerAngleX的抬头低头角度判断,无法覆盖完整环形路径。
  • 缺少噪声处理
    视频流逐帧返回的原始角度值存在高频跳变噪声,直接用原始值做判断会导致检测状态反复横跳,视觉上表现为卡顿、识别不跟手。
  • 无连续动作校验逻辑
    现有逻辑仅做单帧角度匹配,没有记录动作流转状态,既无法判断用户是否沿环形路径连续转动,也无法避免非预期动作的误触发,本质上只能识别固定角度的单次偏头,完全不满足环形录入的检测需求。

可落地优化方向

  • 放宽角度阈值容差
    取消硬编码的窄区间限制,每个动作节点设置10°以上的容差范围,比如左右转Y轴阈值设为18°32°,Z轴倾斜容差放宽到-10°10°,适配不同用户的使用习惯和检测抖动。
  • 拆分环形检测节点
    将完整环形路径拆分为正视、左转、左下低头、正低头、右下低头、右转、抬头回到正视共7个连续检测节点,每个节点配置X/Y/Z三轴对应的角度阈值,覆盖完整转动路径。
  • 增加角度平滑滤波
    维护一个长度为3~5帧的滑动窗口,对窗口内的三轴角度做加权平均计算,过滤单帧异常跳变的噪声值,保证检测状态稳定。
  • 实现状态机流转逻辑
    维护当前检测进度的状态变量,只有当平滑后的角度匹配当前节点的阈值要求时,才将进度流转到下一个节点,直到走完所有节点判定环形录入完成,从根本上解决漏判、误判问题。最简状态机实现参考:
// 环形检测节点枚举
enum class CircleDetectNode {
    INIT_FRONT, LEFT_TURN, LEFT_LOWER, HEAD_LOWER, RIGHT_LOWER, RIGHT_TURN, FINISH
}
// 当前检测节点,初始为正视校验
private var currentNode = CircleDetectNode.INIT_FRONT

// 角度滑动窗口缓存,用于平滑计算
private val angleWindowX = mutableListOf<Float>()
private val angleWindowY = mutableListOf<Float>()
private val angleWindowZ = mutableListOf<Float>()
private const val WINDOW_SIZE = 4

private fun checkDetectProgress(angleX: Float, angleY: Float, angleZ: Float): Boolean {
    // 维护滑动窗口
    angleWindowX.add(angleX)
    angleWindowY.add(angleY)
    angleWindowZ.add(angleZ)
    if (angleWindowX.size > WINDOW_SIZE) {
        angleWindowX.removeFirst()
        angleWindowY.removeFirst()
        angleWindowZ.removeFirst()
    }
    // 计算平滑后的角度值
    val smoothX = angleWindowX.average().toFloat()
    val smoothY = angleWindowY.average().toFloat()
    val smoothZ = angleWindowZ.average().toFloat()

    // 按当前节点匹配阈值,匹配成功则流转到下一节点
    return when(currentNode) {
        CircleDetectNode.INIT_FRONT -> {
            if (kotlin.math.abs(smoothX) < 6 && kotlin.math.abs(smoothY) < 6) {
                currentNode = CircleDetectNode.LEFT_TURN
                true
            } else false
        }
        CircleDetectNode.LEFT_TURN -> {
            if (smoothY in 18f..32f && kotlin.math.abs(smoothZ) < 10f) {
                currentNode = CircleDetectNode.LEFT_LOWER
                true
            } else false
        }
        // 剩余节点按对应角度阈值依次实现流转逻辑即可
        else -> false
    }
}

内容的提问来源于stack exchange,提问作者EMT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 11:09:28