第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により現実空間にタグ付けされます。