iOSで「髪」「肌」「歯」「空」をセグメンテーションする
"Matte"は、背景合成等において前景と背景を分離するために使用する、マスク専用の画像を意味します。
iOS 13以降で「Semantic Segmentation Matte」というものを取得できるようになったのですが、これがどういうものかを知るために、まずはiOS 12からある「Portrait Effect Matte」をおさらいしましょう。
おさらい: Portrait Effect Matte
Portrait Effect Matte(以下PEM)は、iOS 12から取得できるようになった、「人間の全身」のセグメンテーション[1]に特化したマスク画像です。
デュアルカメラやTrueDepthカメラでの撮影時に取得できるデプス(深度)情報だけでなく、機械学習も使用しており、高精細であることが特長です。[2]
髪の毛の部分の再現度も高い
Semantic Segmentation Matteの種類
そしてiOS 13から取得できるようになったSemantic Segmentation Matte(以下SSM)は、人の「髪」「肌」「歯」といった部位をセマンティックセグメンテーションするためのマスクです。
左から、Hair / Skin / Teeth
これらを使って、たとえば髪の色を変える、肌の色を変える、歯を白くする、といったことができます。
SSMを使用して肌の色を変える
Semantic Segmentation Matteの取得方法
PEMの場合は以下のように取得できました。
let info = CGImageSourceCopyAuxiliaryDataInfoAtIndex(
source,
0,
kCGImageAuxiliaryDataTypePortraitEffectsMatte
) as? [String : AnyObject]
CGImageSource
オブジェクトから、CGImageSourceCopyAuxiliaryDataInfoAtIndex
関数を利用して、kCGImageAuxiliaryDataTypePortraitEffectsMatte
を指定してPEMを取得しています。[3]
SSMもほぼPEMと同様の方法でCGImageSource
オブジェクトから取得します。それぞれ次のようなAuxiliaryDataType
が定義されており、
kCGImageAuxiliaryDataTypeSemanticSegmentationHairMatte
kCGImageAuxiliaryDataTypeSemanticSegmentationSkinMatte
kCGImageAuxiliaryDataTypeSemanticSegmentationTeethMatte
CGImageSourceCopyAuxiliaryDataInfoAtIndex
の第3引数でこれらを指定するだけです。
let info = CGImageSourceCopyAuxiliaryDataInfoAtIndex(
source,
0,
kCGImageAuxiliaryDataTypeSemanticSegmentationHairMatte // Hair
) as? [String : AnyObject]
AVSemanticSegmentationMatte
AVFoundationでPEMを扱うクラスとして、AVPortraitEffectsMatte
が用意されており、次のように(上述のCGImageSourceCopyAuxiliaryDataInfoAtIndex
関数から取得した)Dictionaryを渡して初期化することができました。
let matte = AVPortraitEffectsMatte(fromDictionaryRepresentation: info)
iOS 13ではSSMを扱うクラスとしてAVSemanticSegmentationMatte
が追加されました。イニシャライザは次のように定義されています。
convenience init(
fromImageSourceAuxiliaryDataType imageSourceAuxiliaryDataType: CFString,
dictionaryRepresentation imageSourceAuxiliaryDataInfoDictionary:
[AnyHashable : Any]) throws
AVPortraitEffectsMatte
と同様に、[AnyHashable : Any]
型のDictionaryを渡して初期化できるようになっています。
第1引数にimageSourceAuxiliaryDataType
を渡す点だけが違っていて、kCGImageAuxiliaryDataTypeSemanticSegmentationHairMatte
,
〜SkinMatte
,
〜TeethMatte
のいずれかを渡します。
let skinMatte = AVSemanticSegmentationMatte(
fromImageSourceAuxiliaryDataType:
kCGImageAuxiliaryDataTypeSemanticSegmentationSkinMatte,
dictionaryRepresentation: info)
AVSemanticSegmentationMatte
もAVPortraitEffectsMatte
と同様にmattingImage
というPEMのピクセルデータを保持するプロパティを持ち、
var mattingImage: CVPixelBuffer { get }
これがCVPixelBuffer
型なので、Core ImageやMetalといった既存のフレームワークを利用してこのピクセルバッファにある画像データを処理することができます。
SSMをCIImage経由で取得する
前述のCGImageSource
からSSMを取得する方法以外に、CIImage
として取得する方法もあります。
CIImage
の各種イニシャライザはCIImageOption
を渡せるようになっているので、
init?(contentsOf url: URL,
options: [CIImageOption : Any]? = nil)
次のCIImageOption
のいずれかをキーに、
static let auxiliarySemanticSegmentationHairMatte: CIImageOption
static let auxiliarySemanticSegmentationSkinMatte: CIImageOption
static let auxiliarySemanticSegmentationTeethMatte: CIImageOption
値にtrue
をセットすることでCIImage
オブジェクトとしてSSMを取得できます。
「空」のSSM
iOS 14.1で、kCGImageAuxiliaryDataTypeSemanticSegmentationSkyMatte
が追加されました。
名前の通り、「空」をセグメンテーションするためのマスク画像が得られます。
guard let info = CGImageSourceCopyAuxiliaryDataInfoAtIndex(self, 0, kCGImageAuxiliaryDataTypeSemanticSegmentationSkyMatte) as? [String : AnyObject] else { return nil }
let skyMatte = try? AVSemanticSegmentationMatte(fromImageSourceAuxiliaryDataType: kCGImageAuxiliaryDataTypeSemanticSegmentationSkyMatte, dictionaryRepresentation: info)
関連:
-
画像の領域を分割する処理。 ↩︎
-
取得のための実装方法等の詳細は、拙著「Depth in Depth - iOSデプス詳解」(https://booth.pm/ja/items/1313752)をご参照ください。 ↩︎
-
"Auxiliary"は「補助」という意味。デプス等のデータはメインの画像ではなく、補助的な画像データであるという意味でこう命名されているのでしょう。 ↩︎
Discussion