首页 > 解决方案 > 基于在 Swift 中实时跟踪用户面部,为实时视频添加类似 Snap 的效果

问题描述

我希望基于实时跟踪用户的面部,为实时视频添加类似 Snap 的效果。我的设计想要放置来自眉毛、眼睛或嘴唇的粒子流。我已经有一个灵活的效果库,可以将所需的流放置在屏幕上可以实时更新的任何选定点。

Apple 提供了我在此链接下载的 Swift 演示项目: https ://developer.apple.com/documentation/vision/tracking_the_user_s_face_in_real_time

如果您下载并运行该项目而不进行任何更改,它将显示一个包含面部标志的叠加层,例如左右眉毛、眼睛、鼻子、嘴唇等,实时跟踪人脸。

没有太多关于坐标系、图层绘制等的文档,无法让我提取与面部标志相对应的 CGPoint 值,例如左眉上的点。

我在分析 Apple 演示中使用的绘图代码方面取得了一些进展,但在获得所需坐标方面的成功有限。

左眉毛似乎由一条由线连接的路径上的 6 个点组成。我只想得到一个 CGPoint 来指示左眉毛上一个点的当前位置。

Apple 提供了一个名为 addPoints 的例程。

addPoints 为开放和封闭的地标调用。

为每个面部标志调用该例程。由于眉毛不是封闭路径,因此它对应于这种类型:openLandmarkRegions。嘴巴和眼睛对应一个稍微不同的类型,closedLandmarkRegions,因为它们是起点和终点相同的闭合路径。


fileprivate func addPoints(in landmarkRegion: VNFaceLandmarkRegion2D, to path: CGMutablePath, applying affineTransform: CGAffineTransform, closingWhenComplete closePath: Bool) 

路径是打开还是关闭并不重要。我所关心的只是在任何地标上获得一个有效的 CGPoint。最终我也会对眼睛和嘴巴产生一些影响,只要我弄清楚如何为面部标志之一获取有效的 CGPoint。

这是我尝试过的。我声明了一些全局变量,并在 Apples 绘图代码中添加了一些逻辑,以帮助找出左眉上的 CGPoints。


    var sampleLeftEyebrowPoint = false
    var mostRecentLeftEyebrowPoint = CGPoint()

由于在所有地标上的循环中调用了 addPoints,因此我不得不尝试挑选出与左眉毛相对应的循环。

在 addPoints Apple 中有这行代码,他们使用任何给定地标上的点:


            let points: [CGPoint] = landmarkRegion.normalizedPoints

我在那行代码之后添加了这个代码片段:


if sampleLeftEyebrowPoint
{
                
mostRecentLeftEyebrowPoint = points[1]               
mostRecentLeftEyebrowPoint = mostRecentLeftEyebrowPoint.applying(affineTransform)

sampleLeftEyebrowPoint = false
          
}

请注意,points[1] 是眉毛上的第二个点,它是中间点之一。

请注意,我将相同的仿射变换应用于 Apple 在其逻辑中应用的单点。

我在这个 Apple 例程中将 sampleLeftEyebrowPoint 设置为 true,并使用一些逻辑来确定左眉当前是否正在循环:


    fileprivate func addIndicators(to faceRectanglePath: CGMutablePath, faceLandmarksPath: CGMutablePath, for faceObservation: VNFaceObservation)

在该例程中,Apple 在开放的地标上有一个 for 循环,如下所示。我添加了一些逻辑来设置 sampleLeftEyebrowPoint,以便 addPoints 中的逻辑能够识别左眉当前正在工作,因此可以设置。


            for openLandmarkRegion in openLandmarkRegions where openLandmarkRegion != nil {
                if openLandmarkRegion == landmarks.leftEyebrow
                {
                    sampleLeftEyebrowPoint = true
                }

我获得的 mostRecentLeftEyebrowPoint 似乎在某种程度上与我想要的 CGPoint 相关,但并不完全相关。X 坐标似乎可以跟踪,但需要一些缩放。但是 Y 坐标似乎是倒置的,可能还有其他事情发生。

谁能提供一个例程,让我得到与 mostRecentLeftEyebrowPoint 对应的所需 CGPoint ?

一旦我有了这个,我已经想出了如何隐藏面部标志,这样只有我的效果是可见的,我的效果会实时跟踪左眉毛。要隐藏显示的人脸检测线,只需注释掉 Apples call to :


// self.updateLayerGeometry()

标签: swiftface-detectionapple-vision

解决方案


推荐阅读