将图像映射到 3D 面部网格

Posted

技术标签:

【中文标题】将图像映射到 3D 面部网格【英文标题】:Mapping image onto 3D face mesh 【发布时间】:2018-05-19 16:08:41 【问题描述】:

我正在使用 iPhone X 和ARFaceKit 来捕捉用户的面部。目标是使用用户图像对面部网格进行纹理处理。

我只查看来自AR 会话的单个帧(ARFrame)。 从ARFaceGeometry,我有一组描述人脸的顶点。 我制作了当前帧的capturedImage 的 jpeg 表示。

然后我想找到将创建的 jpeg 映射到网格顶点的纹理坐标。我想:

    将顶点从模型空间映射到世界空间;

    将顶点从世界空间映射到相机空间;

    除以图像尺寸以获得纹理的像素坐标。

    让几何:ARFaceGeometry = contentUpdater.faceGeometry! 让 theCamera = session.currentFrame?.camera

    让FaceAnchor:SCNNode = contentUpdater.faceNode 让 anchorTransform = float4x4((theFaceAnchor?.transform)!)

    对于 0..

     // Step 1: Model space to world space, using the anchor's transform
     let vertex4 = float4(vertex.x, vertex.y, vertex.z, 1.0)
     let worldSpace = anchorTransform * vertex4
    
     // Step 2: World space to camera space
     let world3 = float3(worldSpace.x, worldSpace.y, worldSpace.z)
     let projectedPt = theCamera?.projectPoint(world3, orientation: .landscapeRight, viewportSize: (theCamera?.imageResolution)!)
    
     // Step 3: Divide by image width/height to get pixel coordinates
     if (projectedPt != nil) 
         let vtx = projectedPt!.x / (theCamera?.imageResolution.width)!
         let vty = projectedPt!.y / (theCamera?.imageResolution.height)!
         textureVs += "vt \(vtx) \(vty)\n"
     
    

这不起作用,反而让我看起来很时髦!我哪里错了?

【问题讨论】:

我假设相机空间从 -x 到 x。纹理空间通常从 0 变为 1。因此您可能需要添加一半的图像分辨率才能将左上角像素移动到 0,0 这很可能是真的,@Omni,我已经对此进行了试验,但我的方法似乎存在一些更本质上的错误。 您找到解决方案了吗? 你找到解决办法了吗?? 你找到解决这个问题的方法了吗? 【参考方案1】:

现在可以在 Apple 发布的Face-Based sample code 中使用用户图像对面部网格进行纹理处理(将相机视频映射到 3D 面部几何体部分)。

可以使用以下着色器修改器将相机视频映射到 3D 面部几何体。

// 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;

【讨论】:

嗨奥利弗!如果您知道如何使用此代码进行 3D 到 2D 的转换?【参考方案2】:

对于正确的 UV 映射,您需要使用 ARSCNFaceGeometry 类而不是您在代码中使用的 ARFaceGeometry 类

ARSCNFaceGeometry 是 SceneKit 的面部拓扑表示,用于与 ARSession 提供的面部信息一起使用。它用于使用 SceneKit 的渲染引擎快速可视化面部几何。

ARSCNFaceGeometry 类是SCNGeometry 的子类,它包装了ARFaceGeometry 类提供的网格数据。您可以使用ARSCNFaceGeometry 在 SceneKit 视图中快速轻松地可视化 ARKit 提供的面部拓扑和面部表情。

ARSCNFaceGeometry 仅在使用 Metal 的 SceneKit 视图或渲染器中可用。 基于 OpenGL 的 SceneKit 渲染不支持此类

【讨论】:

【参考方案3】:

起点不同:

对您的代码应用以下更改:

//let vty = projectedPt!.y / (theCamera?.imageResolution.height)!
let vty = ((theCamera?.imageResolution.height)! - projectedPt!.y) / (theCamera?.imageResolution.height)!

你可以获得普通脸。

【讨论】:

以上是关于将图像映射到 3D 面部网格的主要内容,如果未能解决你的问题,请参考以下文章

使用 python 将 3D 网格渲染到图像中

我的渲染技术进阶之旅关于ARCore的标准人脸3D模型canonical_face_mesh.fbx和2D面部网格参考纹理canonical_face_mesh.psd文件

我的渲染技术进阶之旅关于ARCore的标准人脸3D模型canonical_face_mesh.fbx和2D面部网格参考纹理canonical_face_mesh.psd文件

MediaPipe基础人脸网格

如何使用引导网格映射图像数组?

Mediapipe facemesh 顶点映射