我正在使用 ARKit 和 RealityKit 以及 ARFaceAnchor 对象。我想确保该人的脸部靠近或靠近设备屏幕中心椭圆的边界。
我不知道如何获取脸部的尺寸,例如 minX/maxX 和 minY/maxY,以及如何将这些值转换为屏幕的坐标,特别是椭圆形状所在的位置。
谁能指出解决方案吗?
我在我的一个应用程序中实现了类似的方法来跟踪用户的面部。我将它用于
ARSCNView
和 SceneKit
,但它也应该适用于 ARView
和 RealityKit
(可能你需要做一些小的调整)
实现这一点并使其适应您的逻辑。
该功能打印出每一帧的面部位置。然后,您可以实施一些边界检查或其他任何措施来保持面部居中,或提醒用户靠近中心。
extension ViewController {
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
guard let faceAnchor = anchors.first as? ARFaceAnchor else { return }
checkFacePosition(faceAnchor: faceAnchor)
}
private func checkFacePosition(faceAnchor: ARFaceAnchor) {
guard let frame = arSession.currentFrame else { return }
// Combine the camera's transform with the face transform
let faceTransform = faceAnchor.transform
let cameraTransform = frame.camera.transform
let combinedTransform = cameraTransform.inverse * faceTransform
// Extract the face's translation (position relative to the camera)
let translation = combinedTransform.columns.3
// Normalize offsets using a reference distance
let referenceDistance: Float = 0.5
let xOffset = translation.y / referenceDistance // Flip x/y to match screen orientation
let yOffset = translation.x / referenceDistance
// Define thresholds for an ellipse (values can be adjusted)
let ellipseWidth: Float = 0.2 // Adjust for the horizontal size of the ellipse
let ellipseHeight: Float = 0.3 // Adjust for the vertical size of the ellipse
// Check if the face is within the ellipse bounds
let isInsideEllipse = pow(xOffset, 2) / pow(ellipseWidth / 2, 2) + pow(yOffset, 2) / pow(ellipseHeight / 2, 2) <= 1.0
// Log the result
if isInsideEllipse {
print("Face is inside the ellipse: xOffset: \(xOffset), yOffset: \(yOffset)")
} else {
print("Face is outside the ellipse: xOffset: \(xOffset), yOffset: \(yOffset)")
}
}
}
这是控制台记录器的一些打印输出:
Face is outside the ellipse: xOffset: 0.026052857, yOffset: -0.2010466
Face is outside the ellipse: xOffset: 0.018577524, yOffset: -0.18251653
Face is outside the ellipse: xOffset: 0.009894665, yOffset: -0.16267225
Face is inside the ellipse: xOffset: 0.0024384973, yOffset: -0.13900988
Face is inside the ellipse: xOffset: 0.002202771, yOffset: -0.11147189
Face is inside the ellipse: xOffset: 0.008226621, yOffset: -0.08980697
您可以通过使用
ARKit
引擎设置默认的 SceneKit
项目来快速查看它。然后用该代码替换您的 ViewController
场景套件解决方案
class ViewController: UIViewController, ARSCNViewDelegate, ARSessionDelegate {
@IBOutlet var sceneView: ARSCNView!
private var arSession: ARSession {
return sceneView.session
}
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
sceneView.session.delegate = self
// Show statistics such as fps and timing information
sceneView.showsStatistics = true
// Create a new scene
let scene = SCNScene()
// Set the scene to the view
sceneView.scene = scene
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
guard ARFaceTrackingConfiguration.isSupported else {
print("ARFaceTracking is not supported on this device.")
return
}
let configuration = ARFaceTrackingConfiguration()
configuration.isLightEstimationEnabled = true // Enable light estimation if needed
// Run the view's session with face tracking
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
// MARK: - ARSCNViewDelegate (Optional Node Configuration)
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
guard anchor is ARFaceAnchor else { return nil }
// Return a new node for face anchor (optional for visualization)
let node = SCNNode()
node.geometry = SCNSphere(radius: 0.02)
node.geometry?.firstMaterial?.diffuse.contents = UIColor.red
return node
}
func session(_ session: ARSession, didFailWithError error: Error) {
// Present an error message to the user
print("ARSession failed with error: \(error.localizedDescription)")
}
func sessionWasInterrupted(_ session: ARSession) {
// Inform the user that the session has been interrupted
print("ARSession was interrupted.")
}
func sessionInterruptionEnded(_ session: ARSession) {
// Reset tracking if consistent tracking is required
print("ARSession interruption ended.")
}
}
我希望这能帮助您实现您正在寻找的目标,或者至少为您指明某个方向。