入门
在本教程中,您将学习:
- 什么是图像分割以及不同类型的分割。
- 为照片创建了人物分割。
- 了解不同的质量水平和性能。
- 人物为视频录制创建了分区。
- 提供人员分区的其他框架。
- 细分人群的最佳实践。
注意:本教程假设您具备SwiftUI、UIKit和AVFoundations的工作知识。SwiftUI 的更多信息,请参阅SwiftUI:入门。您还需要一个物理的 iOS 15 相关设备来跟随。
01.gif您将看到一张照片和一个漂亮的问候视频家庭语。照片中的人员将在两个选项卡中显示和使用教程的背景。背景上。点击视频标签并显示您将看到显示的相机源头。启动项目设置为权限和相机框架。您更新实时以生成问候!
在深入了解这些之前,您需要什么人员细分。准备好是好有趣的旅行社。
介绍图像分割
图像分割将图像划分为多个图像并进行细化而处理。它提供了更多对像素的理解。
分割有类型:图像分割和实例分割。
当您的一个分割实例是一个相同的部分是其组合的过程。每个人的掩体。代码分割为图像中的每个人生成一个单独的掩体。
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
在照片设备上制造和运行。点击问候。
02.gif默认情况下,您将获得质量最好的节目,它确实不适合这种情况,并且实时所有场景。了解可能的不同质量和性能的处理选项。一点。
质量和性能选项
您之前创建的个人细分请求的默认质量等级为VNGeneratePersonSegmentationRequest.QualityLevel.accurate
。
您可以从三个质量等级中进行选择:
-
accurate
:非常适合您想要获得最高质量且不受时间限制的情况。 -
balanced
:非常适合处理视频帧。 -
fast
:最适合处理流媒体内容。
生成掩码的质量等级集。
04.png请注意,随着质量级别的提高,蒙版的质量看起来要好得多。准确的质量在蒙版中显示更精细的细节。帧大小、内存和处理时间因质量级别而异。
05.png与快速质量级别相比,精确级别的帧大小高达 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
.
在物理设备上构建和运行。点击视频问候标签。
06.gif不好了!没有可见的摄像机流。发生了什么?
打开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 {
在这里,您指定生成带有红色蒙版的混合滤镜。
在物理设备上构建和运行。点击视频问候并将前置摄像头对准您。
08.gif了解最佳实践
虽然人物分割适用于照片和视频问候语,但请记住以下一些最佳做法:
- 尝试在一个场景中最多分割四个人,并确保所有人都可见。
- 一个人的身高应该至少是图像高度的一半。
- 避免在框架中出现以下歧义:
- 雕像
- 远距离
结束
您可以使用教程中的所有代码部分下载最终项目。
这里也推荐一些面试相关的内容,祝各位网友都能拿到满意offer!
GCD面试要点
block面试要点
Runtime面试要点
RunLoop面试要点
内存管理面试要点
MVC、MVVM面试要点
网络性能优化面试要点
网络编程面试要点
KVC&KVO面试要点
数据存储面试要点
混编技术面试要点
设计模式面试要点
UI面试要点
网友评论