web-dev-qa-db-ja.com

iOS 11 ARKitでカメラの視野を取得する

ARKitのARSCNViewを使用して、iPadのカメラからのビデオフィードをライブ表示しています。 Xcodeの拡張現実アプリテンプレートとまったく同じようにARSCNViewオブジェクトを設定しています。カメラの視野を確保する方法はあるのでしょうか?

@IBOutlet var sceneView: ARSCNView!

func start() {
    sceneView.delegate = self
    sceneView.session.run(ARWorldTrackingConfiguration())
    // Retrieve camera FOV here
}
11
harveytwoface

ここに行くにはいくつかの方法があり、誤ったスタートをする可能性があります。

⚠️ARKit + SceneKit(不正解)

SceneKit(ARSCNView)を介してすでにARKitを操作している場合、ARKitがSceneKitカメラを自動的に更新していると考えられるかもしれません(ビューの pointOfView 's- camera )は、ARKitで使用される投影変換と一致します。これは正しいです。

ただし、ARKitはSCNCameraの-​​ projectionTransform を直接設定します。 SCNCameraおよびzNearおよび zFar のようなfieldOfViewの幾何学的プロパティを操作する場合、SceneKitは、レンダリング。ただし、 projectionTransform を直接設定した場合、near/far値とxFov/yFov値を復元できる数学はないため、対応するSCNCameraプロパティは無効です。つまり、_sceneView.pointOfView.camera.fieldOfView_および同様のAPIは、ARKitアプリに対して常に偽の結果を返します。

では、代わりに何ができますか?読む...

投影マトリックス

ARセッションは、デリゲートを通じて継続的に ARFrame オブジェクトを販売します。または、そこから currentFrame を要求できます。各フレームには、イメージングパラメータを説明する ARCamera が付加されています。そのうちの1つは、視野に依存する projectionMatrix です。 (同じマトリックスである前述のSceneKit projectionTransformもあります。)

標準の3D射影行列には、垂直視野と縦横比に基づくスケーリング項が含まれています。具体的には、マトリックスは次のようになります。

_[ xScale    0     0    0  ]   xScale = yScale * aspectRatio (width/height)
[   0    yScale   0    0  ]   yScale = 1 / tan(yFov/2)
[   0       0    nf1  nf2 ]   nf1 and nf2 relate to near and far clip planes,
[   0       0     -1   0  ]     so aren't relevant to field of view
_

したがって、yFov方程式を解くことでyScaleを取得できるはずです。

_let projection = session.currentFrame!.camera.projectionMatrix
let yScale = projection[1,1]
let yFov = 2 * atan(1/yScale) // in radians
let yFovDegrees = yFov * 180/Float.pi
_

水平視野の場合は、アスペクト比(具体的には、幅/高さの比率)を掛けることができます。

_let imageResolution = session.currentFrame!.camera.imageResolution
let xFov = yFov * Float(imageResolution.width / imageResolution.height)
_

注:ここで、「水平」および「垂直」はカメラの画像を基準にしています。これは、デバイスまたはARの方法に関係なく、本来は横向きです。ビューのUIは指向的です。

ただし、よく見ると、ここのxFov/yFovのアスペクト比(およびimageResolutionのアスペクト比)は、必ずしもデバイスの画面(特にiPhone X)またはARコンテンツを描画しているビュー。これは、FOVの角度カメラの画像のを測定したためであり、アプリのARビューの角度ではありません。心配しないでください。そのためのAPIもあります...

ビューポート付きの射影行列

ARCameraは、射影行列を取得するための2つのAPIを提供します。先ほど説明したものの他に、プレゼンテーションを考慮に入れる projectionMatrix(for:viewportSize:zNear:zFar:) もあります。カメラのFOVではなく、ARSCNViewまたはARSKView(またはUnityまたはUnrealのいずれか)がARシーンをレンダリングする方法のFOVを一致させる場合は、これを使用してデバイスを渡します向きとあなたの見方を見る。次に、上記と同じ計算をすべて実行します。

_let imageResolution = session.currentFrame!.camera.imageResolution
let viewSize = sceneView.bounds.size
let projection = session.currentFrame!.camera.projectionMatrix(for: .portrait,
    viewportSize: viewSize, zNear: zNear, zFar: zFar)
let yScale = projection[1,1] // = 1/tan(fovy/2)
let yFovDegrees = 2 * atan(1/yScale) * 180/Float.pi
let xFovDegrees = yFovDegrees * Float(viewSize.height / viewSize.width)
_

zNearzFarに何を渡してもかまいません。これに依存するマトリックスの部分を使用していないためです。 (_zNear < zFar_および_zNear != zFar != 0_を確認する必要がある場合もあります。)

注:これで高さ/幅はビュー(またはむしろ、projectionMatrix(for:...)に渡すビューの属性)に基づいています)。この例では、方向がyFovであるため、portraitはUIに対して垂直です。したがって、高さ/幅のアスペクト比を掛けてxFovを取得します。横向きの場合は、代わりに幅/高さを掛けます。

カメラ組み込み関数

熱心な観察者は、上記の計算では射影行列の一部が無視されることに気づいたかもしれません。 FOV角度の定義 はカメラの光学的特性であり、3D投影とは関係がないため、投影行列全体は中間結果であり、実際には必要ない場合があります。

ARCameraは、カメラの光学特性を説明する intrinsics マトリックスも公開します。この行列の対角線に沿った最初と2番目の値は、カメラ画像の単一ピクセルの水平方向と垂直方向 焦点距離 です。焦点距離と画像の幅/高さがある場合、 FOV角度の定義 に従ってFOVを計算できます。

_let imageResolution = session.currentFrame!.camera.imageResolution
let intrinsics = session.currentFrame!.camera.intrinsics
let xFovDegrees = 2 * atan(Float(imageResolution.width)/(2 * intrinsics[0,0])) * 180/Float.pi
let yFovDegrees = 2 * atan(Float(imageResolution.height)/(2 * intrinsics[1,1])) * 180/Float.pi
_

注:projectionMatrixを使用するバージョンと同様に、これはcameraのサイズと常に横向きに基づいていますimage、デバイス画面またはARコンテンツを表示しているビューではありません。代わりにビューポートに基づいて何かが必要な場合は、「ビューポートを使用した投影マトリックス」まで上にスクロールしてください。

34
rickster