iOS/macOSのフォトグラメトリAPIは深度や重力の情報をどのように扱っているのか調べたメモ
今回はiOS 17で追加された撮影周りのObject Capture APIの話ではなく、2年前のWWDC21で発表された写真から3Dモデルを生成する方のObject Capture APIの話。
このフォトグラメトリAPI公開当時に、2D写真を撮影する方のサンプルコードも提供された。そのサンプルアプリを試し、コードを読んでみたのが下記記事なのだが、
このサンプルでは、写真撮影と同時にデプスデータと重力加速度も取得し、保存していたのだが、同時期に公開されていたフォトグラメトリ側のサンプルでは単に写真フォルダを渡すだけの実装となっており、
maybeSession = try PhotogrammetrySession(input: inputFolderUrl,
configuration: configuration)
デプスと重力を使用する実装にはなっていなかった。(2023.8.20修正: デプスや重力を明示的に指定するPhotogrammetrySampleを使用するイニシャライザを使用していないだけで、実際には画像フォルダを指定するだけのイニシャライザの場合でもデプスetc.の追加情報を使用している。)
本記事では、このデプスと重力の情報をiOS/macOSのフォトグラメトリAPIに食わせるにはどのように実装するのか、またデプスや重力の情報は、フォトグラメトリの処理においてどのように用いられるのか(生成される3Dモデルの品質にどのように影響するのか)について、公式リファレンス・公式サンプル・WWDCセッションの情報をベースに調査する。
iOS 17のObject Capture for iOSサンプルではどう実装されているか
iOS 17で追加された撮影側のObject Capture APIを使う場合でも、3Dモデル生成(Reconstruction)フェーズはこの従来からあるフォトグラメトリAPIを使うことになる。
サンプルコードはこちら:
iOS 17の新しいObject Capture APIは要LiDARなので、この公式サンプルでは当然フォトグラメトリAPIにLiDARで取得したデプスデータを渡していると思われる。
というわけで PhotogrammetrySession の実装を見てみると、
photogrammetrySession = try PhotogrammetrySession(
input: scanFolderManager.imagesFolder,
configuration: configuration)
あれ…普通に画像フォルダを渡しているだけ…
おかしい、ではLiDAR由来のデプスデータは使ってないのだろうか?
アプリの Documents 配下を見てみると、確かに HEIC しか保存されてない。
「Taking Pictures for 3D Object Capture」サンプルの方では HEIC 以外にデプスをTIFで、重力加速度をTXTで保存してたので、
どうやらiOS 17のスキャンサンプルではデプスは保存してないようだ。
要LiDARなのは、Guided Captureの体験を成立させるために使われてるのだろう。
ObjectCaptureSessionにデプスや重力データも保存するオプションでもないだろうかとドキュメントを見渡してみたが、なさそうだった。
追記: ObjectCaptureSession はデプス含め様々なデータをHEICに保存している
(2023.8.20追記)
この記事を書いたあとに調べてわかったことだが、ObjectCaptureSessionで撮影した画像のHEICファイルにはデプスが保存されていた。
それだけでなく、デプス以外にも様々なデータを保存していた。
次のように、画像ファイルに入っているデータを確認した:
CGImageSourceCopyProperties(imageSource, nil) as? [String: AnyObject]
これをprintした出力が以下:
["{FileContents}": {
ImageCount = 1;
Images = (
{
AuxiliaryData = (
{
AuxiliaryDataType = kCGImageAuxiliaryDataTypeDepth;
Height = 192;
Width = 256;
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#DepthConfidenceMap";
Height = 192;
Width = 256;
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#CameraTrackingState";
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#CameraCalibrationData";
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#ObjectTransform";
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#ObjectBoundingBox";
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#RawFeaturePoints";
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#PointCloudData";
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#BundleVersion";
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#SegmentID";
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#Feedback";
},
{
AuxiliaryDataType = "tag:apple.com,2023:ObjectCapture#WideToDepthCameraTransform";
}
);
Height = 3024;
ImageIndex = 0;
NamedColorSpace = kCGColorSpaceSRGB;
ThumbnailImages = (
{
Height = 240;
Width = 320;
}
);
Width = 4032;
}
);
}, "CanAnimate": 0, "FileSize": 3907659]
この AuxiliaryData に入っているデータがポイントで、kCGImageAuxiliaryDataTypeDepth のデプスデータだけでなく、
PointCloudData
RawFeaturePoints
ObjectBoundingBox
SegmentID
CameraCalibrationData
WideToDepthCameraTransform
といった情報まで保存していることがわかる。(※なお、kCGImageAuxiliaryDataTypeXxxxといったタイプが定義されていないこれらのデータは CGImageSourceCopyAuxiliaryDataInfoAtIndex で取得することはできなかった)
WWDC23のセッションでも
と言っているので、PhotogrammetrySesssionではLiDARで取得した情報も使っているということで間違いなさそう。
なおHEICファイルに入っているAuxiliary Dataの確認にはiOS-Depth-Samplerを使用した。
WWDC21 「Create 3D models with Object Capture」での言及
"Create 3D models with Object Capture" のトランスクリプトでdepthやgravityについて言及している箇所を抽出してみる。
ここからの学びは2点:
フォトグラメトリAPIにデプスや重力を渡す際には PhotogrammetrySample を用いる
デプスデータは HEIC ファイルに埋め込まれている?
TIF として出力されていると思ったが、あらためてコードを見てみる
iOS 17のサンプルで出力した HEIC にデプスマップが含まれてないか確認してみる
公式ドキュメントでの言及
PhotogrammetrySession にデプスや重力を渡す際には PhotogrammetrySample を用いることがわかった。
その公式ドキュメントを見てみる。
PhotogrammetrySample のAPIリファレンス
次のようなプロパティ群を持ち、使い方もわかりやすい。
metadata プロパティ
EXIF情報は何に使うのだろう、と metadata プロパティのドキュメントを見てみると、意外にも解説があった(※こういうニッチな class/struct にはたいてい何の解説もない)
RealityKitが利用するEXIFデータのキーの一覧:
TIFFMake
TIFFModel
TIFFOrientation
ExifBodySerialNumber
ExifLensMake
ExifLensModel
ExifLensSerialNumber
ExifFocalLength
ExifFocalLengthIn35mmFilm
GPSAltitude
GPSAltitudeRef
GPSLatitude
GPSLatitudeRef
GPSLongitude
GPSLongitudeRef
objectMaskプロパティ
object maskとは、たとえば Portrait Matte みたいなもののこと。
このプロパティにもがっつり解説があった。
RealityKitの内部処理にどう影響するかしっかり書いてあった。
depthDataMap
写真からのReconstructionプロセス自体に使われるというよりは、サイズ決定に関わるのか。
gravity
こちらは想像通り、写真のアラインメントに使用されるようだ。
最後まで読んでいただきありがとうございます!もし参考になる部分があれば、スキを押していただけると励みになります。 Twitterもフォローしていただけたら嬉しいです。 https://twitter.com/shu223/