iOS11 ARKit:ARKit 也可以捕捉用户面部的纹理吗?

iOS11 ARKit: Can ARKit also capture the Texture of the user's face?

我阅读了所有 ARKit 类 的完整文档。我没有看到任何描述实际获取用户面部纹理的能力的地方。

ARFaceAnchor 包含 ARFaceGeometry(由顶点组成的拓扑和几何)和 BlendShapeLocation 数组(坐标允许通过在用户面部顶点上操纵几何数学来操纵单个面部特征)。

但是我在哪里可以得到用户面部的实际纹理。例如:实际肤色/颜色/质地、面部毛发、其他独特特征,如疤痕或胎记?或者这根本不可能?

没有。该信息目前在 ARKit.

中不可用

要检测其他面部特征,您需要 运行 您自己的自定义计算机视觉代码。您可以使用 AVFoundation.

从前置摄像头捕获图像

你想要面部纹理贴图风格的图像吗?没有 API 可以准确地为您提供,但您需要的所有信息都在那里:

  • ARFrame.capturedImage 获取相机图像。
  • ARFaceGeometry 获取脸部的 3D 网格。
  • ARAnchorARCamera 一起告诉您面部相对于相机的位置,以及相机与图像像素的关系。

因此完全可以使用当前视频帧图像对面部模型进行纹理处理。对于网格中的每个顶点...

  1. 将顶点位置从模型 space 转换为相机 space(使用锚点变换)
  2. 将相机投影与该向量相乘以获得归一化图像坐标
  3. 除以图像width/height得到像素坐标

这将为您获取每个顶点的纹理坐标,然后您可以使用它来使用相机图像对网格进行纹理处理。您可以一次全部执行此数学运算以替换 ARFaceGeometry 提供的纹理坐标缓冲区,或者在渲染期间在 GPU 上的着色器代码中执行此运算。 (如果您使用 SceneKit / ARSCNView 进行渲染,您可能可以在 geometry 入口点的着色器修改器中执行此操作。)

相反,如果您想知道相机图像中的每个像素对应于面部几何形状的哪一部分,那就有点难了。你不能仅仅反转上面的数学,因为你缺少每个像素的深度值......但是如果你不需要映射每个像素,SceneKit 命中测试是获取单个像素几何的简单方法。


如果您真正要求的是地标识别——例如相机图像中眼睛、鼻子、胡须等的位置——在 ARKit 中没有 API。 Vision 框架可能会有所帮助。

您可以按如下方式计算纹理坐标:

let geometry = faceAnchor.geometry
let vertices = geometry.vertices
let size = arFrame.camera.imageResolution
let camera = arFrame.camera

modelMatrix = faceAnchor.transform

let textureCoordinates = vertices.map { vertex -> vector_float2 in
    let vertex4 = vector_float4(vertex.x, vertex.y, vertex.z, 1)
    let world_vertex4 = simd_mul(modelMatrix!, vertex4)
    let world_vector3 = simd_float3(x: world_vertex4.x, y: world_vertex4.y, z: world_vertex4.z)
    let pt = camera.projectPoint(world_vector3,
        orientation: .portrait,
        viewportSize: CGSize(
            width: CGFloat(size.height),
            height: CGFloat(size.width)))
    let v = 1.0 - Float(pt.x) / Float(size.height)
    let u = Float(pt.y) / Float(size.width)
    return vector_float2(u, v)
}

我整理了一个 demo iOS app 来说明如何完成此操作。该演示实时捕获面部纹理贴图,将其应用回 ARSCNFaceGeometry 以创建用户面部的纹理 3D 模型。

您可以在下方看到左上角的实时纹理 3D 人脸模型,覆盖在 AR 前置摄像头视图之上:

该演示通过渲染 ARSCNFaceGeometry 来工作,但是您不是正常渲染它,而是在纹理 space 中渲染它,同时继续使用原始顶点位置来确定从哪里采样捕获的像素数据。

以下是相关实施部分的链接:

几乎所有的工作都是在金属渲染通道中完成的,因此它很容易实时运行。

我还put together some notes介绍了演示的局限性


如果您想要用户面部的二维图像,您可以尝试执行以下操作:

  • 将转换后的 ARSCNFaceGeometry 渲染到 1 位缓冲区以创建 image mask。基本上你只想要面部模型看起来是白色的地方,而其他一切都应该是黑色的。

  • 将蒙版应用于捕获的帧图像。

这应该会给你一张只有脸的图像(尽管你可能需要裁剪结果)