面部除皱

iOS ARKit - 面部追踪

发布日期:2019-10-29 浏览次数:

ARSCNView

  • ARSCNView 会自动将设备摄像头的实时视频输入渲染为场景背景。

  • ARSCNView 的属性 scene 的世界坐标系直接响应由会话配置建立的AR世界坐标系。

  • ARSCNView 会自动移动它的 SceneKit 相机来匹配设备的实际移动。

SCNNode

ARFaceTrackingConfiguration

if (!ARFaceTrackingConfiguration.isSupported) { return; }

ARFaceAnchor

ARFaceGeometry

面部表情追踪

创建项目

首先需要添加一个 ARSCNView,在这个项目里面 ARSCNView 是懒加载的,代码如下:

-(ARSCNView *)sceneView {if(!_sceneView){_sceneView =[[ARSCNView alloc]initWithFrame:CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)];_sceneView.delegate =self;_sceneView.automaticallyUpdatesLighting =YES;}return_sceneView;}

然后根据 SCNGeometry 对象来设置 ARSCNView 的 scene 的节点。这里有3种节点,分别是网格状的人脸、面具人脸、机器人头部。机器人头部节点使用的是创建好的3D模型来进行初始化,所以不用传入代码创建的 SCNGeometry 对象。此外,我们可以根据需要来设置 scene 的背景内容,默认是以现实世界为背景。

/** 虚拟面部节点的类型 */typedefNS_ENUM(NSInteger,XHBVirtualFaceType){XHBVirtualFaceTypeMesh,/**< 面部拓扑的网格 */XHBVirtualFaceTypeMask,/**< 面具 */XHBVirtualFaceTypeRobot     /**< 机器人 */};/** 设置面部节点 */-(void)p_setupFaceNode {// fillMesh 设置为NO,会空出眼睛和嘴巴的区域ARSCNFaceGeometry *faceGeometry =[ARSCNFaceGeometry faceGeometryWithDevice:self.sceneView.device fillMesh:NO];switch(self.virtualFaceType){caseXHBVirtualFaceTypeMesh:self.meshFaceNode =[[XHBMeshFaceNode alloc]initWithFaceGeometry:faceGeometry];self.virtualFaceNode =(SCNNode *)self.meshFaceNode;// 更改场景的背景内容self.sceneView.scene.background.contents =[UIColor blackColor];//            self.sceneView.scene.background.contents = [UIImage imageNamed:@"head"];break;caseXHBVirtualFaceTypeMask:self.maskFaceNode =[[XHBMaskFaceNode alloc]initWithFaceGeometry:faceGeometry];self.virtualFaceNode =(SCNNode *)self.maskFaceNode;break;caseXHBVirtualFaceTypeRobot:self.robotFaceNode =[[XHBRobotFaceNode alloc]init];self.virtualFaceNode =(SCNNode *)self.robotFaceNode;self.sceneView.scene.background.contents =[UIColor lightGrayColor];break;}}

节点初始化的代码如下,这里只列举面部网格节点的代码:

@interfaceXHBMeshFaceNode :SCNNode-(instancetype)initWithFaceGeometry:(ARSCNFaceGeometry *)faceGeometry;-(void)updateWithFaceAnchor:(ARFaceAnchor *)faceAnchor;@end@implementationXHBMeshFaceNode#pragmamark -#pragmamark -------------------- Life Cycle ---------------------(instancetype)initWithFaceGeometry:(ARSCNFaceGeometry *)faceGeometry {self=[superinit];if(self){SCNMaterial *material =faceGeometry.firstMaterial;// 更改材料的填充模型为线条material.fillMode =SCNFillModeLines;// 漫反射的内容颜色material.diffuse.contents =[UIColor whiteColor];// 基于物理的阴影,包含了真实世界灯光和材料之间相互作用的光照模型material.lightingModelName =SCNLightingModelPhysicallyBased;self.geometry =faceGeometry;}returnself;}#pragmamark -#pragmamark -------------------- Public Method ---------------------(void)updateWithFaceAnchor:(ARFaceAnchor *)faceAnchor {[(ARSCNFaceGeometry *)self.geometry updateFromFaceGeometry:faceAnchor.geometry];}@end

接着使用 ARSCNView 的 ARSession 属性配置 ARFaceTrackingConfiguration 运行起来,代码如下:

/** 设置追踪会话 */-(void)p_setupTrackingSession {// 是否可以使用面部追踪if(!ARFaceTrackingConfiguration.isSupported){return;}// 禁用系统的“空闲计时器”,防止屏幕进入屏幕变暗的睡眠状态[[UIApplication sharedApplication]setIdleTimerDisabled:YES];ARFaceTrackingConfiguration *configuration =[[ARFaceTrackingConfiguration alloc]init];// YES,为 trackingSession 中捕获的 ARFrame 对象的 lightEstimate 属性提供场景照明信息[configuration setLightEstimationEnabled:YES];[self.trackingSession runWithConfiguration:configuration                                       options:ARSessionRunOptionResetTracking |ARSessionRunOptionRemoveExistingAnchors];}-(ARSession *)trackingSession {returnself.sceneView.session;}

当 ARSCNView 首次捕捉到脸部时,会添加一个和 ARAnchor 对应的 SCNNode,然后后就会调用 ARSCNView 的代理方法,我们可以在这里让之前创建的自定义 SCNNode 成为系统创建的 SCNNode 的子节点,子节点会继承父节点的坐标系。代码如下:

-(void)p_setupFaceNodeContent {if(!self.faceNode){return;}if(self.virtualFaceNode){[self.faceNode addChildNode:self.virtualFaceNode];}}-(void)renderer:(id<SCNSceneRenderer>)renderer didAddNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor {self.faceNode =node;[selfp_setupFaceNodeContent];}

之后 ARSCNView 会以一定的频率来更新 ARAnchor,然后调用代理方法。我们可以在代理方法里面把新的 ARAnchor 传给自定义节点,让节点更新它的顶点数据。代码如下:

/** 节点实现的方法  */-(void)updateWithFaceAnchor:(ARFaceAnchor *)faceAnchor {[(ARSCNFaceGeometry *)self.geometry updateFromFaceGeometry:faceAnchor.geometry];}-(void)renderer:(id<SCNSceneRenderer>)renderer didUpdateNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor {if(!anchor){return;}switch(self.virtualFaceType){caseXHBVirtualFaceTypeMesh:[self.meshFaceNode updateWithFaceAnchor:(ARFaceAnchor *)anchor];break;caseXHBVirtualFaceTypeMask:[self.maskFaceNode updateWithFaceAnchor:(ARFaceAnchor *)anchor];break;caseXHBVirtualFaceTypeRobot:[self.robotFaceNode updateWithFaceAnchor:(ARFaceAnchor *)anchor];break;}}

到这里,就可以让虚拟世界的面部跟着我们的现实世界的面部做动作了。完整的项目在这里。

参考资料

X

截屏,微信识别二维码

微信号:18612316852

(点击微信号复制,添加好友)

  打开微信

微信号已复制,请打开微信添加咨询详情!