iOS 12の新機能"Portrait Matte"(ポートレート・マット)の概要と、実装方法を紹介します。1

深度マップとセグメンテーション
昨今のiPhoneではデュアルカメラ(iPhone 7Plus, 8 Plus, Xの背面に搭載)、あるいはTrueDepthカメラ(iPhone Xの前面に搭載)から深度マップを作成し、奥行きを知ることができるようになっています。
深度マップは、
- AR表現における回り込み(オクルージョン)
- モノや人物の背景を差し替える 2
といった用途に用いられます。
どちらの例も要は人物やモノの境界を検出して分割する(セグメンテーション)ところがキーで、深度マップはそのセグメンテーションにおけるマスクとして有用なわけです。

(撮影した画像(左)と深度マップ(右))
iOS 12の新機能 "Portrait Matte"
深度マップ関連APIはiOS 11から追加されたわけですが、iOS 12では新たに"Portrait Matte"なる新機能が追加されました。"Portrait Effect Matte"とも呼ばれます。

(従来の深度マップ(左)とPortrait Matte(右))
聞き慣れない用語ですが、たぶんApple独自用語です。WWDC18の"Creating Photo and Video Effects Using Depth"から、「Portrait Matteとはなにか」という説明をしている部分を引用してみます。
so what is a portrait matte? A portrait matte is a segmentation from foreground to background and what this means precisely is that you have a mask which is 1.
0 in the background and you get soft and continuous values in between.
つまり、背景と前景の分離に用いるセグメンテーションに特化したフォーマットで、
- 前景領域のピクセル値は1(白)
- 背景領域のピクセル値は0(黒)
とスッパリ分かれており、輪郭部分の髪の毛のような詳細もその間の連続値で表現される、というもののようです。

True Depthな前面カメラからだけではなく、背面カメラからも取得できるようです。
It is available for both the front and the rear facing camera.
ただし、静止画のみ(動画では取得不可)かつ人間が写っている場合だけ取得可能です。
It is available to you with portrait still images and at the moment only when there are people in the scene.
Portrait Matteの取得方法
Portrait Matteの取得方法は従来の深度データ(AVDepthData
)の取得方法と非常に似ています。
CGImageSource
を作成したら、CGImageSourceCopyAuxiliaryDataInfoAtIndex
でkCGImageAuxiliaryDataTypePortraitEffectsMatte
を指定してAuxiliaryデータを取得すれば、
guard let info = CGImageSourceCopyAuxiliaryDataInfoAtIndex(source, 0, kCGImageAuxiliaryDataTypePortraitEffectsMatte) as? [String : AnyObject] else { return }
それをそのままAVPortraitEffectsMatte
のイニシャライザに渡せます。
let matte = AVPortraitEffectsMatte(fromDictionaryRepresentation: info)
AVPortraitEffectsMatte
はCVPixelBuffer
型のmattingImage
プロパティを持っており、そこからセグメンテーション用のマスクとしてCore ImageなりMetalなりで用いることができます。
var mattingImage: CVPixelBuffer { get }