iOS開發之視覺框架中的人員與背景分割
theme: scrolls-light
入門
在本教程中,您將學習:
- 什麼是影象分割以及不同型別的分割。
- 為照片建立了人物分割。
- 瞭解不同的質量水平和效能。
- 人物為影片錄製建立了分割槽。
- 提供人員分割槽的其他框架。
- 細分人群的最佳實踐。
注意:本教程假設您具備SwiftUI、UIKit和AVFoundations的工作知識。SwiftUI 的更多資訊,請參閱SwiftUI:入門。您還需要一個物理的 iOS 15 相關裝置來跟隨。
您將看到一張照片和一個漂亮的問候影片家庭語。照片中的人員將在兩個選項卡中顯示和使用教程的背景。背景上。點選影片標籤並顯示您將看到顯示的相機源頭。啟動專案設定為許可權和相機框架。您更新實時以生成問候!
在深入瞭解這些之前,您需要什麼人員細分。準備好是好有趣的旅行社。
介紹影象分割
影象分割將影象劃分為多個影象並進行細化而處理。它提供了更多對畫素的理解。
分割有型別:影象分割和例項分割。
當您的一個分割例項是一個相同的部分是其組合的過程。每個人的掩體。程式碼分割為影象中的每個人生成一個單獨的掩體。
Apple 的 Vision 框架的人員分割 API 是單幀碼。它的使用 API 是面向中流式分割為框架中的單獨提供的。它用於分割處理和離線處理。
人物分割的過程有四個步驟:
- 建立使用者細分請求。
- 為該請求建立請求處理程式。
- 處理請求。
- 處理結果。
,您將使用 API 和步驟來建立使用照片!
建立照片
你有一個家庭的形象和一個形象。你的目標家庭背景中的人在背景上的背景,以產生背景。
開啟 RayGreetings並開啟GreetingProcessor.swift。
在下面新增以下內容import Combine
:
進口願景
下一個,將下面的內容新增到下面的GreetingProcessor
內容中@Published var photoOutput = UIImage()
:
讓請求= VNGeneratePersonSegmentationRequest ()
在這裡,您建立個人細分用於請求的例項。一個有狀態的請求,可以重複整個幀的離線處理影片。
將以下內容新增到GreetingProcessor
:
``` func generatePhotoGreeting(問候:問候) { // 1 警衛 讓 backgroundImage = greeting.backgroundImage.cgImage, 讓foregroundImage.foregroundImage.c else { print ( "呼喚的影象" ) 返回 }
// 2 // 建立請求處理程式 讓 requestHandler = VNImageRequestHandler ( cgImage:自己的影象, 選項: [:])
// 執行 } ```
這是上面的程式碼正在做的事情:
cgImage
從backgroundImage
和訪問foregroundImage
。然後,它確保兩個影象都是有效的。您將很容易使用它們來使用 Core Image 混合影象。- 建立
requestHandler
為的例項VNImageRequestHandler
。它接收影象以及指定如何處理影象的任選字典。
替換// TODO
為以下內容:
``` 做 { // 1 試用 requestHandler.perform([request])
// 2 守衛讓掩碼= request.results ? .first else { print ( "生成分割掩碼時出錯" ) 返回 }
// 3 讓屬性= CIImage (cgImage:foregroundImage) 讓 maskImage = CIImage (cvPixelBuffer: mask.pixelBuffer) 讓背景= CIImage(cgImage:backgroundImage)
// TODO:混合影象 } 抓住 { print ( "處理人員分割槽請求異常" ) } ```
這是自己的程式碼細分:
requestHandler
使用處理人員分割perform(_:)
。如果有多個請求,則在所有請求存在完成或失敗後返回。perform(_:)
在請求處理時可能會通過錯誤提示,因此您可以將其包含在do-catch
。- 然後,您從結果中檢索掩飾碼。因為您只提交了一個請求,所以從結果中檢索第一個物件。
- 返回結果的
pixelBuffer
屬性掩碼。然後建立 CIImage 有背景和蒙版的版本。CIImage 是 Core Image 過濾器將處理的影象的混合表示。您將需要它來影象。
混合所有影象
在下面的 GreetingProcessor.swift中新增以下內容import Vision
:
匯入CoreImage 。CIFilterBuiltins
Core Image 提供了提供型別安全例項的方法CIFilter
。在這裡,您可以匯入CIFilterBuiltins
訪問型別的安全 API。
將以下內容新增到GreetingProcessor
:
``` 遊戲混合影象( 背景:CIImage,對應 :CIImage, 掩飾:CIImage ) -> CIImage? { // 1 讓 maskScaleX = foreground.extent.width / mask.extent.width 讓 maskScaleY = foreground.extent.height / mask.extent.height 讓 maskScaled = mask.transformed( 作者:__CGAffineTransformMake(maskScaleX, 0 , 0 , maskScaleY, 0 , 0 ))
// 2 讓 backgroundScaleX = (foreground.extent.width / background.extent.width) 讓 backgroundScaleY = (foreground.extent.height / background.extent.height) 讓 backgroundScaled = background.transformed( 作者:__CGAffineTransformMake(backgroundScaleX, 0 , 0 , backgroundScaleY, 0 , 0 ))
// 3 讓 blendFilter = CIFilter .blendWithMask() blendFilter.inputImage =其他 blendFilter.backgroundImage = backgroundScaled blendFilter.maskImage = maskScaled
// 4 返回 blendFilter.outputImage } ```
的程式碼:
- 計算蒙版相對於用於相同影象的 X 和 Y 比例。然後它將縮放
CGAffineTransformMake
縮放到影象。mask``foreground
- 與的縮放一樣
mask
,它計算出 X 和 Y 的大小,background
然後縮放background
到的大小foreground
。 - 建立一個核心
blendFilter
影象過濾器,inputImage
設定為後續過濾器的和縮放版本foreground
。backgroundImage``maskImage
outputImage
包含混合的結果。
返回的結果是型別CIImage
。您需要將其轉換為一個UIImage
以在 UI 中顯示的。
在GreetingProcessor
以下中,在頂部、新增以下內容let request = VNGeneratePersonSegmentationRequest()
:
讓時間= CIContext ()
在這裡,您建立一個CIContext
。它用於從CIImage
物件建立 Quartz 2D 影象。
將以下內容新增到GreetingProcessor
:
函式 renderAsUIImage(_image : CIImage ) -> UIImage ? {
守衛讓 cgImage = context.createCGImage(image, from: image.extent) else {
返回零
}
返回UIImage (cgImage: cgImage)
}
在這裡,您用於從例項context
建立。CGImage``CIImage
使用cgImage
,然後建立一個UIImage
。使用者將看到該影象。
顯示照片問候語
替換// TODO: Blend images
並generatePhotoGreeting(greeting:)
新增以下內容:
``` // 1守衛讓輸出= blendImages ( 背景:背景, 作案:特殊, 掩碼:掩碼影象)否則{ 列印(“錯誤混合影象”) 返回 }
// 2 如果讓 photoResult = renderAsUIImage(output) { self .photoOutput =照片結果 } ```
這是正在發生的事情:
blendImages(background:foreground:mask:)
混合影象並確保輸出不是nil
。- 然後,將輸出轉換為一個例項並將其設定為。是已釋出的屬性。訪問它以在
UIImage
PhotoGreetingView.swift中顯示。photoOutput``photoOutput
最後,開啟PhotoGreetingView.swift。// TODO: Generate Photo Greeting
在行動中閉包中替換Button
為以下內容:
GreetingProcessor .shared.generatePhotoGreeting(問候語:問候語)
在這裡,您呼叫以在被點選generatePhotoGreeting(greeting:)
時生成問候語。Button
在照片裝置上製造和執行。點選問候。
預設情況下,您將獲得質量最好的節目,它確實不適合這種情況,並且實時所有場景。瞭解可能的不同質量和效能的處理選項。一點。
質量和效能選項
您之前建立的個人細分請求的預設質量等級為VNGeneratePersonSegmentationRequest.QualityLevel.accurate
。
您可以從三個質量等級中進行選擇:
accurate
:非常適合您想要獲得最高質量且不受時間限制的情況。balanced
:非常適合處理影片幀。fast
:最適合處理流媒體內容。
生成掩碼的質量等級集。
請注意,隨著質量級別的提高,蒙版的質量看起來要好得多。準確的質量在蒙版中顯示更精細的細節。幀大小、記憶體和處理時間因質量級別而異。
與快速質量級別相比,精確級別的幀大小高達 64 倍。與快速和平衡的關卡相比,處理準確關卡所需的記憶體和時間要高得多。這代表了對掩碼質量和生成掩碼所需資源的權衡。
現在您知道了權衡,是時候生成一個有趣的影片問候了!:]
建立影片問候
開啟CameraViewController.swift。它設定了所有功能來捕獲相機幀並使用 Metal 渲染它們。要了解有關使用 AVFoundation 和 SwiftUI 設定相機的更多資訊,請檢視本教程和本影片系列。
檢視 中的邏輯CameraViewController
,符合AVCaptureVideoDataOutputSampleBufferDelegate
.
extension CameraViewController : AVCaptureVideoDataOutputSampleBufferDelegate {
func captureOutput ( _ output : AVCaptureOutput ,
didOutput sampleBuffer : CMSampleBuffer ,
from connection : AVCaptureConnection ) {
// 從相機輸出
守衛中獲取畫素緩衝幀 let pixelBuffer = sampleBuffer.imageBuffer else {
return
}
自.currentCIImage = CIImage (cvPixelBuffer: pixelBuffer)
}
}
在這裡,注意pixelBuffer
從 中檢索sampleBuffer
。然後通過更新渲染它currentCIImage
。您的目標是將其pixelBuffer
用作前景影象並建立影片問候語。
開啟GreetingProcessor.swift並將以下內容新增到GreetingProcessor
:
``` func processVideoFrame( 前景:CVPixelBuffer, 背景:CGImage )-> CIImage?{ 讓ciForeground = CIImage (cvPixelBuffer: 前景)
// TODO:人物分割請求
返回 零 } ```
CIImage
在這裡,您從前景建立一個例項,CVPixelBuffer
以便您可以使用 Core Image 過濾器混合影象。
到目前為止,您已經使用Vision框架來建立、處理和處理人員細分請求。儘管它易於使用,但其他框架提供由相同技術支援的類似功能。接下來你會學到這個。
生成人員分割的替代方案
您可以使用這些框架作為 Vision 的替代方案來生成人物分割掩碼:
- AVFoundation:可以在某些較新的裝置上拍攝照片時生成人物分割蒙版。您可以通過
portraitEffectsMatte
.AVCapturePhoto
- ARKit:在處理相機饋送時生成分割掩碼。
segmentationBuffer
您可以使用 的屬性獲取掩碼ARFrame
。它在具有 A12 Bionic 及更高版本的裝置上受支援。 - Core Image:Core Image 在 Vision 框架上提供了一個瘦包裝器。它公開了
qualityLevel
您設定的屬性VNGeneratePersonSegmentationRequest
。
接下來,您將使用 Core Image 為影片問候生成人物分割掩碼。
使用核心影象生成人物分割掩碼
替換// TODO: person segmentation request
為processVideoFrame(foreground:background:)
以下內容:
``` // 1 讓personSegmentFilter = CIFilter .personSegmentation() personSegmentFilter.inputImage = ciForeground personSegmentFilter.qualityLevel = 1
// 2 if let mask = personSegmentFilter.outputImage { guard let output = blendImages( 背景:CIImage(cgImage:背景), 前景:ciForeground, mask: mask) else { print ( "Error blending images" ) return nil } 返回輸出 } ```
這就是這樣做的:
-
personSegmentFilter
使用核心影象建立CIFilter
並設定inputImage
前景影象。接受一個qualityLevel
數字。不同的質量級別選項包括:- 0:準確
- 1平衡
- 2:快
在這裡,您設定
qualityLevel
為 1。 -
outputImage
從of 中獲取掩碼personSegmentationFilter
並確保它不是nil
. 然後,它用於blendImages(background:foreground:mask:)
混合影象並返回結果。
開啟CameraViewController.swift。將副檔名中的內容替換為以下captureOutput(_:didOutput:from:)
內容:CameraViewController
``` // 1 保護 let pixelBuffer = sampleBuffer.imageBuffer, let backgroundImage = self .background ? .cgImage其他{ 返回 }
// 2 DispatchQueue .global().async { if let output = GreetingProcessor .shared.processVideoFrame( 前景:畫素緩衝區, 背景:背景影象){ DispatchQueue .main.async { self .currentCIImage =輸出 } } } ```
這是上面程式碼的細分。它:
- 檢查
pixelBuffer
並backgroundImage
有效。 - 通過呼叫
processVideoFrame(foreground:background:)
中定義的非同步處理影片幀GreetingProcessor
。然後,它更新currentCIImage
為output
.
在物理裝置上構建和執行。點選影片問候標籤。
不好了!沒有可見的攝像機流。發生了什麼?
開啟GreetingProcessor.swiftguard let output = blendImages
並在in處放置一個斷點processVideoFrame(foreground:background:)
。請注意在偵錯程式中使用 Quick Look 生成的掩碼。
面具是紅色的!您需要使用紅色蒙版而不是常規的白色蒙版建立一個混合濾鏡。
更新blendImages(background:foreground:mask:)
以採用新的布林引數,如下所示:
func blendImages(
背景:CIImage,
前景:CIImage,
掩碼:CIImage,
isRedMask:Bool = false
)-> CIImage?{
這用於isRedMask
確定要生成的混合過濾器的型別。預設情況下,它的值為false
。
let blendFilter = CIFilter.blendWithMask()
如下圖所示替換blendImages(background:foreground:mask:isRedMask:)
:
讓blendFilter = isRedMask ?
CIFilter .blendWithRedMask() :
CIFilter .blendWithMask()
在這裡,您blendFilter
使用紅色蒙版生成 if isRedMask
is true
。否則,您將使用白色蒙版進行建立。
接下來,替換:
守衛 讓輸出= blendImages(
背景:CIImage(cgImage:背景),
前景:ciForeground,
掩碼:掩碼)否則{
在processVideoFrame(foreground:background:) with the following:
守衛 讓輸出= blendImages(
背景:CIImage(cgImage:背景),
前景:ciForeground,
面具:面具,
isRedMask: true ) else {
在這裡,您指定生成帶有紅色蒙版的混合濾鏡。
在物理裝置上構建和執行。點選影片問候並將前置攝像頭對準您。
瞭解最佳實踐
雖然人物分割適用於照片和影片問候語,但請記住以下一些最佳做法:
- 嘗試在一個場景中最多分割四個人,並確保所有人都可見。
- 一個人的身高應該至少是影象高度的一半。
- 避免在框架中出現以下歧義:
- 雕像
- 遠距離
結束
您可以使用教程中的所有程式碼部分下載最終專案。
這裡也推薦一些面試相關的內容! * ① BAT等各個大廠iOS面試真題+答案大全
- iOS開發 Charles 代理教程
- iOS開發中的佈局入門教程
- Swift 與 Objective-C:您應該為下一個 iOS 移動應用選擇哪個語言?
- 適用於 iOS 的 HEIC 影象壓縮
- 5 個使用 Swift 高階函式簡化的複雜演算法
- iOS開發之視覺框架中的人員與背景分割
- iOS視覺框架教程:輪廓檢測
- Google Maps iOS SDK 教程:入門
- iOS 中的模型-檢視-控制器 (MVC)
- iOS視覺教程:身體和手部姿勢檢測
- 適用於 iOS 的 AR 人臉追蹤入門教程
- iOS開發—建立一個 iOS 圖書開啟動畫:第 1 部分
- iOS開發—建立一個 iOS 圖書開啟動畫:第 2 部分
- iOS 動畫教程:自定義檢視控制器演示轉換
- iOS開發之建立框架
- 適用於 iOS 的 ShazamKit 入門教程
- iOS開發—MVVM 教程:從 MVC 重構
- iOS開發—單元測試和UI測試教程
- iOS開發—核心影象教程:自定義過濾器
- iOS開發—核心影象教程:入門