第2章 ARKit 堤 修一/@shu223
func session(_ session: ARSession, didUpdate frame: ARFrame) { let pixelBuffer = frame.capturedImage
ARSCNViewを利用している場合は、ARSCNViewDelegateの(実際にはSCNSceneRendererDelegateの)renderer(_:updateAtTime:)メソッドから最新フレームのARFrameオブジェクトを取得し、ピクセルバッファにアクセスする方法もあります。
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { guard let frame = sceneView.session.currentFrame else {return} let pixelBuffer = frame.capturedImage
■Core MLの認識を実行する
ARKitから取得した毎フレームの画像データを、Core ML+Visionに渡します。
VNImageRequestHandlerの初期化時に、引数に入力画像データを渡す必要がありますが、前項で解説した方法で得たCVPixelBufferオブジェクトをそのまま渡せます。
let handler = VNImageRequestHandler(cvPixelBuffer: imageBuffer)
VNImageRequestHandlerが作成できたら、あとはperform()メソッドを呼ぶだけです。
try? handler.perform([request]) // requestはVNCoreMLRequestオブジェクト
■Core MLの認識結果をテキストノードとして設置する
Inceptionv3モデルを利用した場合、認識結果はVNClassificationObservationオブジェクトとして得られます。結果が得られたら、ARSCNViewのhitTest(_:types:)メソッドによるヒットテスト注27)を、スクリーンの中心座標を対象に行います。そして、ヒットテスト結果を元にSCNTextをジオメトリに持つノードを設置します。
// 平面、特徴点を対象にヒットテストを実行 let results = sceneView.hitTest(screenCenterPos, types: [.existingPlaneUsingExtent, .featurePoint]) // 手前にある結果を取り出す if let result = results.first { // SCNTextジオメトリを持つノード let tagNode = TagNode() // ヒットテスト結果のワールド変換行列をセット tagNode.transform = SCNMatrix4(hitTestResult.worldTransform) // シーンに設置 sceneView.scene.rootNode.addChildNode(tagNode) }
実際のサンプルではもう少し細かい制御をしていますが、ポイントは以上です。実行すると、図2.17のようにCore MLによる認識結果がARKitにより現実空間にタグ付けされます。