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関連の情報を発信しています。