iPhone(iPad)と物体の距離を正確に測る
物体が何mデバイスから離れているか測りたい時ってありますよね。
ARKitの深度情報(奥行き情報)を使えば正確に測れます。
Lidar搭載デバイス必須です。
方法
DepthDataの取得
let configuration = ARWorldTrackingConfiguration()
configuration.frameSemantics = .smoothedSceneDepth
sceneView.session.run(configuration)
func session(_ session: ARSession, didUpdate frame: ARFrame) {
guard let sceneDepth = frame.smoothedSceneDepth ?? frame.sceneDepth else {
print("Failed to acquire scene depth.")
return
}
let depthPixelBuffer = sceneDepth.depthMap
これで、カメラ画像の各ピクセルについてm単位の深度をとったマップ画像が取得できます。
黒いところほど近い(ピクセル値が低い)です。
アスペクトはカメラ画像と同じですが、256:192の小さなサイズになっています。
あと、カメラ画像は元は横向きになっているので、回転させて使おう。
メートル単位で距離を取得する
さて、画像のピクセル値を物体への距離に変換します。
画像中央のピクセルで取ってみます。
let ciImage = CIImage(cvPixelBuffer: pixelBuffer).oriented(.right)
let width = CVPixelBufferGetWidth(pixelBuffer)
let height = CVPixelBufferGetHeight(pixelBuffer)
let centerX = width / 2
let centerY = height / 2
CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer)?.assumingMemoryBound(to: Float32.self)
let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
let pixelIndex = Int(centerY) * bytesPerRow / MemoryLayout<Float32>.stride + Int(centerX)
let depthValue = baseAddress?[pixelIndex]
CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
if let depthValue = depthValue {
let distanceInMeters = Double(depthValue)
print(distanceInMeters)
}
0.3746262788772583
0.37mなので、37cm離れています。画面中央のうさぎまでの距離。
後ろの壁は3〜4m離れていますが、測定できました。正確です。
smoothSceneDepthとsceneDepth
sceneDepthはlidarのプリミティブな値、
smoothedSceneDepthは、
時間の経過とともに深度データを平滑化し、フレーム間のデルタを軽減する
ということで、smoothedSceneDepthの方が安定して距離を測る方が良さそうです。
🐣
フリーランスエンジニアです。
AIについて色々記事を書いていますのでよかったらプロフィールを見てみてください。
もし以下のようなご要望をお持ちでしたらお気軽にご相談ください。
AIサービスを開発したい、ビジネスにAIを組み込んで効率化したい、AIを使ったスマホアプリを開発したい、
ARを使ったアプリケーションを作りたい、スマホアプリを作りたいけどどこに相談したらいいかわからない…
いずれも中間コストを省いたリーズナブルな価格でお請けできます。
お仕事のご相談はこちらまで
rockyshikoku@gmail.com
機械学習やAR技術を使ったアプリケーションを作っています。
機械学習/AR関連の情報を発信しています。