Android Java基于Google ML Kit人脸检测实现2D人脸滤镜的对齐旋转问题
ML Kit人脸滤镜绘制问题修复方案
问题原因说明
- 位置不对齐:当前取的是左右眉弓顶部的第一个点,该点位不匹配太阳镜需要覆盖的双眼区域,且固定加150的高度没有适配不同人脸的尺寸
- 不跟随旋转:没有使用Face对象返回的Z轴旋转角(face.getHeadEulerAngleZ()) 对画布做对应角度的旋转,歪头时滤镜角度不会同步变化
修复代码
你可以直接替换原有draw方法,适配com.google.mlkit:face-detection:16.1.2版本:
@Override public void draw(Canvas canvas) { Face face = this.face; if (face == null || bitmap == null) { return; } // 保存画布当前状态,后续旋转后可恢复 int saveCount = canvas.save(); // 取左右眼轮廓点计算边界,点位比眉弓更贴合双眼位置 List<PointF> rightEyePoints = face.getContour(FaceContour.RIGHT_EYE).getPoints(); List<PointF> leftEyePoints = face.getContour(FaceContour.LEFT_EYE).getPoints(); float rightEyeX = translateX(rightEyePoints.get(0).x); float rightEyeY = translateY(rightEyePoints.get(0).y); float leftEyeX = translateX(leftEyePoints.get(leftEyePoints.size()-1).x); float leftEyeY = translateY(leftEyePoints.get(leftEyePoints.size()-1).y); // 动态计算太阳镜尺寸,适配不同大小的人脸 float centerX = (rightEyeX + leftEyeX) / 2f; float centerY = (rightEyeY + leftEyeY) / 2f; float eyeDistance = Math.abs(leftEyeX - rightEyeX); // 太阳镜宽度设为眼距的1.2倍,高度按PNG素材的比例自动换算 float glassWidth = eyeDistance * 1.2f; float glassHeight = glassWidth * bitmap.getHeight() / bitmap.getWidth(); // 按人脸旋转角度旋转画布,实现滤镜跟随旋转 float rotateZ = face.getHeadEulerAngleZ(); canvas.rotate(-rotateZ, centerX, centerY); // 计算最终绘制区域 RectF drawRect = new RectF( centerX - glassWidth/2, centerY - glassHeight/2, centerX + glassWidth/2, centerY + glassHeight/2 ); // 绘制带抗锯齿的太阳镜素材 canvas.drawBitmap(bitmap, null, drawRect, new Paint(Paint.ANTI_ALIAS_FLAG)); // 恢复画布状态,不影响其他内容的绘制 canvas.restoreToCount(saveCount); }
可选优化点
- 如果需要适配人脸左右转向的近大远小效果,可以读取
face.getHeadEulerAngleY()的返回值对太阳镜做横向缩放 - 可以根据实际素材的设计,调整centerY的偏移量,让太阳镜佩戴位置更自然
内容的提问来源于stack exchange,提问作者ISHAN KALANSOORIYA
相关产品推荐
相关产品推荐

