
iOS/macOSで「空」をセグメンテーションするための試行錯誤
iOS/macOSで使える Object Capture API の PhotogrammetrySession を利用してフォトグラメトリを行っていて、建物や地面のメッシュ・テクスチャの復元は概ねいい感じにいけるのだが、空の部分にメッシュが生成されてしまうのが気になる。

こういうのはちゃんとしたフォトグラメトリのワークフローであれば点群やメッシュの段階できれいにするのかもしれないが、なるべくiOS/macOSのAPIを使って、自動で解決できないかなぁと。
Object Capture API のフォトグラメトリでは入力にマスクを与えることができるので、入力のフレーム画像群から「空」のマスク(Sky Matte)を生成すればいいんじゃないかと。


幸いそのAPIには心当たりがある。すぐできるはず、と思って取り掛かってみたが、意外とうまくいかず、徒労に終わったのでそれらの試行錯誤をここで供養する。
(なお仕事等で必要なのではなく、発表のデモに必要なだけなので、自前でモデルを学習するといった時間のかかる選択肢は除外)
kCGImageAuxiliaryDataTypeSemanticSegmentationSkyMatte
一番の当てはこれだった。
iOS 12で追加されたPortrait Effects Matteという人間の高精度なマスクを生成するAPIがあり、
これの「空」版ともいえるAPIがiOS 14.1で追加されていた。
取得方法もおそらくPortrait Effects Matteとほぼ同等で、以下のような感じでタイプが kCGImageAuxiliaryDataTypeSemanticSegmentationSkyMatte な AVSemanticSegmentationMatte オブジェクトを画像から取得できると思っていた:
guard let info = CGImageSourceCopyAuxiliaryDataInfoAtIndex(self, 0, kCGImageAuxiliaryDataTypeSemanticSegmentationSkyMatte) as? [String : AnyObject] else { return nil }
let skyMatte = try? AVSemanticSegmentationMatte(fromImageSourceAuxiliaryDataType: kCGImageAuxiliaryDataTypeSemanticSegmentationSkyMatte, dictionaryRepresentation: info)
ところが結果は nil。
そういえば思い出したのだが、Portrait Effects Matteは、ポートレートモードで撮影し(つまりデプス情報が必要)、かつ写真内に人が入っている場合のみ取得できたんだった。
しかも SemanticSegmentationXxxxMatte 系は、カメラでの撮影時から isDepthDataDeliveryEnabled や enabledSemanticSegmentationMatteTypes の設定が必要になるんだった。
今回は動画から抽出したフレーム画像を使いたい & 撮影時の条件を問わず使える手法にしたいため、この時点で対象外。
最後まで読んでいただきありがとうございます!もし参考になる部分があれば、スキを押していただけると励みになります。 Twitterもフォローしていただけたら嬉しいです。 https://twitter.com/shu223/