在3D人脸网格上映射图像

23

我正在使用 iPhone X 和 ARFaceKit 来捕捉用户的脸部。目标是用用户的图像贴在脸部网格上。

我只查看来自AR会话的单个帧(一个ARFrame)。 通过ARFaceGeometry,我有一组描述面部的顶点。 我生成当前帧的capturedImage的jpeg表示。

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

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

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

  3. 除以图像尺寸,获取纹理的像素坐标。

    let geometry: ARFaceGeometry = contentUpdater.faceGeometry! let theCamera = session.currentFrame?.camera

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

    for index in 0..<totalVertices { let vertex = geometry.vertices[index]

     // 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
这很可能是真的,@Omni,我已经尝试过了,但我的方法似乎存在更本质的问题。 - coco
你找到解决方案了吗? - George Asda
你找到解决方案了吗? - George Asda
你是否找到了解决这个问题的方法? - George Asda
显示剩余2条评论
3个回答

6
现在,苹果发布了基于面部的示例代码,用户可以使用自己的图像为面网格进行纹理贴图(参见将相机视频映射到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;

嗨,Oliver!如果你知道如何使用这段代码进行三维到二维转换吗? - swiftlearneer

1
为了正确的UV映射,您需要使用ARSCNFaceGeometry类,而不是您在代码中使用的ARFaceGeometry类。 ARSCNFaceGeometry是SceneKit对面部拓扑的表示,可与ARSession提供的面部信息一起使用。它用于使用SceneKit的渲染引擎快速可视化面部几何形状。 ARSCNFaceGeometry类是SCNGeometry的子类,包装由ARFaceGeometry类提供的网格数据。您可以在SceneKit视图中使用ARSCNFaceGeometry快速轻松地可视化ARKit提供的面部拓扑和面部表情。但是,ARSCNFaceGeometry仅在使用Metal的SceneKit视图或渲染器中可用。此类不支持基于OpenGL的SceneKit渲染。

0

起点不同:

Start point is different

请将以下更改应用于您的代码:

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

你可以获得正常的面孔。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接