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开发—核心图像教程:入门