LoginSignup
2
4

More than 1 year has passed since last update.

iOSで人物きりぬきPersonSegmentation(バーチャル背景、背景ぼかし、合成)

Last updated at Posted at 2021-12-08

AppleのVisionでPersonSegmentationができるようになった。
iOSで人物切り抜きができる。

【セグメンテーション・マット】

GitHubサンプルコード: 

PersonSegmentationSampler

VisionのPersonSegmentationで画像の背景合成(ぼかし/画像合成)ができるアプリサンプル。

###既存のセグメンテーションとの違い

今までAVFoundationや、ARKitでもPersonSegmentationの機能があったが、いつでもセグメンテーションマットが得られるわけではなかった。
AVFoundationでは撮影時にPortrait Matteを設定した写真のみだし、
ARKitもマット画像が得られるわけではなかった。
その意味するところの一つは、AVFoundationやARKitでは、
既存の画像や動画の切り抜きができなかったということだ。
そうするためには、DeepLabなどの機械学習モデルをCoreMLで使う必要があった。
僕が作った人物の背景をぼかしたり合成するアプリではそうしていた)

2021年に追加されたVisionのPersonSegmentationで、既存の画像や動画の人物きりぬきもできるようになった。

【ぼかし/透過】

【合成】

#PersonSegmentationの使用手順
いつものVisionのやり方。
Requestを作成し、Handlerで実行、結果はPixelBufferで返されるので、すぐに白黒マット画像が得られる。

###Request作成

lazy var personSegmentationRequest: VNGeneratePersonSegmentationRequest = {
    request = VNGeneratePersonSegmentationRequest()
    request.qualityLevel = .balanced
    request.outputPixelFormat = kCVPixelFormatType_OneComponent8
    return request
}()

###qualityLevel
セグメンテーションの精度は3種類選択可能で、実行速度と消費リソースは精度とトレードオフの関係にある。

qualityLevel ユースケース
.fast ストリーミング
.balanced 動画
.accurate 画像

outputPixelFormatは出力のタイプ。

outputPixelFormat タイプ 出力値幅
kCVPixelFormatType_OneComponent8 8 bit uint [0;255]
kCVPixelFormatType_OneComponent16Half 16 bit float [0.0;1.0]
kCVPixelFormatType_OneComponent32Float 32 bit float [0.0;1.0]

###Handler実行
単一画像で解析を行う場合

let requestHandler = VNImageRequestHandler((cvPixelBuffer: pixelBuffer, orientation: .right, options: [:])
try? requestHandler.perform([personSegmentationRequest])
guard let resultPixelBuffer = personSegmentationRequest.results?.first?.pixelBuffer else { return }

動画シーケンス・フレームで解析を行う場合

let sequenceRequestHandler = VNSequenceRequestHandler()
try? sequenceRequestHandler.perform([personSegmentationRequest],
                            on: pixelBuffer,
                            orientation: .right)
        
guard let resultPixelBuffer = personSegmentationRequest.results?.first?.pixelBuffer else { return }

これまでのVision Requestと違い、VNGeneratePersonSegmentationRequestは状態保持(Stateful)リクエストで、.accurate(正確性重視)モードで実行した時に、フレームのシーケンス間でマット画像を滑らかにする。

###背景合成

let originalImage = CIImage(cvPixelBuffer: pixelBuffer)
var maskImage = CIImage(cvPixelBuffer: resultPixelBuffer)

// 結果のマスクイメージはサイズが変わっているので、オリジナルか背景のサイズに合わせる
var originalImage = CIImage(cvPixelBuffer: framePixelBuffer).oriented(.right)
let scaleX = backgroundImage.extent.width / originalImage.extent.width
let scaleY = backgroundImage.extent.height / originalImage.extent.height
originalImage = originalImage.transformed(by: .init(scaleX: scaleX, y: scaleY))

var maskImage = CIImage(cvPixelBuffer: maskPixelBuffer)
        
let scaleXForMask = backgroundImage.extent.width / maskImage.extent.width
let scaleYForMask = backgroundImage.extent.height / maskImage.extent.height
maskImage = maskImage.transformed(by: .init(scaleX: scaleXForMask, y: scaleYForMask))

let filter = CIFilter(name: "CIBlendWithMask", parameters: [
            kCIInputImageKey: originalImage,
            kCIInputBackgroundImageKey: backgroundImage,
            kCIInputMaskImageKey: maskImage])
let compositeImage = filter?.outputImage

VisionのPersonSegmentationで画像の背景合成(ぼかし/画像合成)ができるサンプルを作りました。
GitHubサンプルコード: 
PersonSegmentationSampler

🐣


フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com
開発したい内容を簡単に書いて、お気軽にメールしてください。

Core MLやARKitを使ったアプリを作っています。
機械学習/AR関連の情報を発信しています。

Twitter
Medium

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4