首页 > 解决方案 > 来自 ARKit 的面部纹理

问题描述

我正在使用 SceneKit 在 ARKit 中运行人脸跟踪配置,在每一帧中,我都可以通过snapshot属性或capturedImage作为缓冲区访问相机源,我还能够将每个人脸顶点映射到图像坐标空间并添加一些UIView助手( 1 点正方形)在屏幕上实时显示所有面部顶点,如下所示:

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    guard let faceGeometry = node.geometry as? ARSCNFaceGeometry,
        let anchorFace = anchor as? ARFaceAnchor,
        anchorFace.isTracked
        else { return }

    let vertices = anchorFace.geometry.vertices

    for (index, vertex) in vertices.enumerated() {
        let vertex = sceneView.projectPoint(node.convertPosition(SCNVector3(vertex), to: nil))
        let xVertex = CGFloat(vertex.x)
        let yVertex = CGFloat(vertex.y)

        let newPosition = CGPoint(x: xVertex, y: yVertex) 
    // Here i update the position of each UIView in the screen with the calculated vertex new position, i have an array of views that matches the vertex count that is consistent across sessions.

    }
}

由于 UV 坐标在会话中也是恒定的,因此我尝试为面部网格上的每个像素绘制其在 UV 纹理中的相应位置,以便在经过一些迭代后,我可以将人的面部纹理绘制到文件中。

我已经得出了一些理论解决方案,例如CGPaths为每个三角形创建,并询问每个像素是否包含在该三角形中,如果是,则创建一个三角形图像,裁剪一个矩形,然后应用从投影点获得的三角形蒙版通过图像坐标中的三角形顶点,所以以这种方式,我可以获得一个三角形图像,该图像必须被转换为底层三角形变换(比如将其倾斜到位),然后在UIView(1024x1024) 中将每个三角形图像添加为UIImageView作为子视图,最后将该 UIView 编码为 PNG,这听起来需要做很多工作,特别是将裁剪后的三角形与 UV 纹理对应的三角形进行匹配的部分。

Apple 演示项目中,有一张图像显示了 UV 纹理的外观,如果您编辑此图像并添加一些颜色,它将显示在脸上,但我需要相反的方式,从我所看到的相机提要,创建脸部纹理,在同一个演示项目中,有一个示例可以完全满足我的需要,但使用着色器,并且没有关于如何将纹理提取到文件的线索,着色器代码看起来像这个:

/*
 <samplecode>
 <abstract>
 SceneKit shader (geometry) modifier for texture mapping ARKit camera video onto the face.
 </abstract>
 </samplecode>
 */

#pragma arguments
float4x4 displayTransform // from ARFrame.displayTransform(for:viewportSize:)

#pragma body

// Transform the vertex to the camera coordinate system.
float4 vertexCamera = scn_node.modelViewTransform * _geometry.position;

// Camera projection and perspective divide to get normalized viewport coordinates (clip space).
float4 vertexClipSpace = scn_frame.projectionTransform * vertexCamera;
vertexClipSpace /= vertexClipSpace.w;

// XY in clip space is [-1,1]x[-1,1], so adjust to UV texture coordinates: [0,1]x[0,1].
// Image coordinates are Y-flipped (upper-left origin).
float4 vertexImageSpace = float4(vertexClipSpace.xy * 0.5 + 0.5, 0.0, 1.0);
vertexImageSpace.y = 1.0 - vertexImageSpace.y;

// Apply ARKit's display transform (device orientation * front-facing camera flip).
float4 transformedVertex = displayTransform * vertexImageSpace;

// Output as texture coordinates for use in later rendering stages.
_geometry.texcoords[0] = transformedVertex.xy;

/**
 * MARK: Post-process special effects
 */

老实说,我对着色器没有太多经验,因此在翻译有关如何转换为更多 Cocoa Touch Swift 代码的着色器信息方面的任何帮助将不胜感激,现在我还没有考虑性能,所以如果必须这样做在 CPU 中,如在后台线程中或离线是可以的,无论如何我将不得不选择正确的帧以避免歪斜的样本,或者具有非常好的信息的三角形和其他一些几乎没有拉伸几个像素的三角形(比如检查是否正常三角形指向相机,对其进行采样)或其他 UI 助手,以使用户转动面部以正确采样所有面部。

我已经检查了这篇文章这篇文章,但无法让它工作。

这个应用程序完全符合我的需要,但它们似乎不像使用 ARKit。

谢谢。

标签: iosswiftscenekitarkit

解决方案


推荐阅读