如何通过Apple Vision“ NO AR”在检测到的面部上应用3D模型

时间:2019-05-23 09:58:53

标签: swift xcode 3d face-detection apple-vision

使用iPhoneX True-Depth相机可以获取任何物体的3D坐标,并使用该信息来定位和缩放物体,但是对于较旧的iPhone,我们无法使用正面相机上的AR,到目前为止,要做的就是使用Apple Vison框架检测面部,并在面部或地标周围绘制一些2D路径。 我制作了一个 SceneView 并将其应用为背景清晰的我的视图的顶层,在它的下方是 AVCaptureVideoPreviewLayer ,在检测到人脸后,我的3D对象出现在屏幕上但是根据面部boundingBox正确定位和缩放它需要未投影的东西和其他卡在其中的东西,我也尝试使用 CATransform3D 将2D BoundingBox转换为3D,但是我失败了!我想知道我是否想要实现?我记得如果我没记错的话,SnapChat就是在ARKit在iPhone上可用之前就已经这样做了!

Imgur

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(self.sceneView)

        self.sceneView.frame = self.view.bounds
        self.sceneView.backgroundColor = .clear
        self.node = self.scene.rootNode.childNode(withName: "face", 
        recursively: true)!

    }

    fileprivate func updateFaceView(for result: 
    VNFaceObservation, twoDFace: Face2D) {
        let box = convert(rect: result.boundingBox)
        defer {
            DispatchQueue.main.async {
                self.faceView.setNeedsDisplay()
            }
        }

        faceView.boundingBox = box
        self.sceneView.scene?.rootNode.addChildNode(self.node)

        let unprojectedBox = SCNVector3(box.origin.x, box.origin.y, 
        0.8)

        let worldPoint = sceneView.unprojectPoint(unprojectedBox)

         self.node.position = worldPoint 
        /* Here i have to to unprojecting 
         to convert the value from a 2D point to 3D point also 
         issue here. */
    }

2 个答案:

答案 0 :(得分:0)

我建议您看一下使用后置或前置摄像头支持Apple AR场景的Google AR Core产品...但是,对于非面部深度摄像头设备,它会增加Apple之外的一些其他功能。

Apple的Core Vision与Google的Core Vision框架几乎相同,该框架返回代表眼睛/嘴巴/鼻子等的2D点以及面部倾斜组件。

但是,如果您想要一种简单的方法将2D纹理应用于响应式3D脸部,或者将3D模型附加到脸部上的点,请查看Google的Core Augmented Faces框架。它在iOS和Android上具有出色的示例代码。

答案 1 :(得分:0)

实现此目的的唯一方法是使用带有地形相机的SceneKit,并使用SCNGeometrySource将Vision的界标与网格的顶点相匹配。 首先,您需要网格具有相同数量的Vision顶点(66-77,具体取决于您所在的Vision Revision)。您可以使用Blender之类的工具来创建一个。

The mesh on Blender

然后,在代码上,每次处理地标时,请执行以下步骤: 1-获取网格顶点:

func getVertices() -> [SCNVector3]{
        var result = [SCNVector3]()
        let planeSources = shape!.geometry?.sources(for: SCNGeometrySource.Semantic.vertex)
        if let planeSource = planeSources?.first {
            let stride = planeSource.dataStride
            let offset = planeSource.dataOffset
            let componentsPerVector = planeSource.componentsPerVector
            let bytesPerVector = componentsPerVector * planeSource.bytesPerComponent
            let vectors = [SCNVector3](repeating: SCNVector3Zero, count: planeSource.vectorCount)
            //   [SCNVector3](count: planeSource.vectorCount, repeatedValue: SCNVector3Zero)
            let vertices = vectors.enumerated().map({
                (index: Int, element: SCNVector3) -> SCNVector3 in
                var vectorData = [Float](repeating: 0, count: componentsPerVector)
                let byteRange = NSMakeRange(index * stride + offset, bytesPerVector)

                let data = planeSource.data
                (data as NSData).getBytes(&vectorData, range: byteRange)
                return SCNVector3( x: vectorData[0], y: vectorData[1], z: vectorData[2])
            })

            result = vertices

        }

        return result
    }

2-取消投影Vision捕获的每个地标,并将它们保存在SCNVector3数组中:

let unprojectedLandmark = sceneView.unprojectPoint( SCNVector3(landmarks[i].x + (landmarks[i].x,landmarks[i].y,0))

3-使用新的顶点修改几何:

func reshapeGeometry(_顶点:[SCNVector3]){

let source = SCNGeometrySource(vertices: vertices)

var newSources = [SCNGeometrySource]()
newSources.append(source)

for source in shape!.geometry!.sources {
    if (source.semantic != SCNGeometrySource.Semantic.vertex) {
        newSources.append(source)
    }
}

let geometry = SCNGeometry(sources: newSources, elements: shape!.geometry?.elements)

let material = shape!.geometry?.firstMaterial
shape!.geometry = geometry
shape!.geometry?.firstMaterial = material

}

我能够做到这一点,这就是我的方法。 希望这会有所帮助!