見出し画像

iOS/macOSで「空」をセグメンテーションするための試行錯誤

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

Object Capture APIで生成した3Dモデル

こういうのはちゃんとしたフォトグラメトリのワークフローであれば点群やメッシュの段階できれいにするのかもしれないが、なるべくiOS/macOSのAPIを使って、自動で解決できないかなぁと。

Object Capture API のフォトグラメトリでは入力にマスクを与えることができるので、入力のフレーム画像群から「空」のマスク(Sky Matte)を生成すればいいんじゃないかと。

Object Capture API に入力した画像のうちの1枚
空のマスクの例(左下) / On-device Panoptic Segmentation for Camera Using Transformers - Apple Machine Learning Research より

幸いその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 の設定が必要になるんだった。

今回は動画から抽出したフレーム画像を使いたい & 撮影時の条件を問わず使える手法にしたいため、この時点で対象外。

ここから先は

1,142字 / 4画像

文章やサンプルコードは多少荒削りかもしれませんが、ブログや書籍にはまだ書いていないことを日々大量に載せています。たったの400円で、すぐに購読解除してもその月は過去記事もさかのぼって読めるので、少しでも気になる内容がある方にはオトクかと思います。

技術的なメモやサンプルコード、思いついたアイデア、考えたこと、お金の話等々、頭をよぎった諸々を気軽に垂れ流しています。

最後まで読んでいただきありがとうございます!もし参考になる部分があれば、スキを押していただけると励みになります。 Twitterもフォローしていただけたら嬉しいです。 https://twitter.com/shu223/