为办理人形分离和深度估计问题,ARKit 新增长了 Segmentation Buffer(人体分隔缓冲区)和Estimated Depth Data Buffer(深度估计缓冲区)两个缓冲区。人体分隔缓冲区作用雷同于图形渲染管线中的 Stencil Buffer(模板缓冲区),用于区分人形区域与配景区域,它是一个像素级的缓冲区,用于准确地描述人形区域。
人体分隔缓冲区用于标识人形区域,所以可以使用非常简单的结构,如使用1标识该像素是人形区域,而用。标识该像素为配景区。人体分隔缓冲区每帧都更新,所以可以动态地追踪摄像头采集的人形变化。
既然人体分隔缓冲区标识了人形区域,我们也就可以使用该缓冲区提取出场景中的人形以便后续应用,如将人形图像通过网络传输到其他AR装备中,实现雷同虚拟会议的效果;或者将人形图像放入虚拟世界中,营造更绚酷的体验;或者对提取的人形图像进行模糊和打马赛克等处理,实现以往只能使用绿幕才华实现的及时人形捕捉效果。
为简单起见,本节我们直接获取人体分隔缓冲区数据并将其生存为图像,关键代码如代码如下所示。
- //
- // HumanExtraction.swift
- // ARKitDeamo
- //
- // Created by zhaoquan du on 2024/2/4.
- //
- import SwiftUI
- import ARKit
- import RealityKit
- import Combine
- import VideoToolbox
- import AVFoundation
- struct HumanExtraction: View {
-
- var viewModel = HumanExtractionViewModel()
-
- var arView: ARView {
- let arView = ARView(frame: .zero)
-
- return arView
- }
-
- var body: some View {
- HumanExtractionContainer(viewModel: viewModel)
- .overlay(
- VStack{
- Spacer()
- Button(action:{viewModel.catchHuman()}) {
- Text("截取人形")
- .frame(width:120,height:40)
- .font(.body)
- .foregroundColor(.black)
- .background(Color.white)
- .opacity(0.6)
- }
- .offset(y:-30)
- .padding(.bottom, 30)
- }
- )
- .edgesIgnoringSafeArea(.all)
- }
- }
- struct HumanExtractionContainer : UIViewRepresentable{
-
- var viewModel: HumanExtractionViewModel
-
-
- func makeUIView(context: Context) -> some ARView {
- let arView = ARView(frame: .zero)
-
-
-
- return arView
- }
-
- func updateUIView(_ uiView: UIViewType, context: Context) {
- guard ARWorldTrackingConfiguration.supportsFrameSemantics(.personSegmentation) else {
- return
- }
-
- let config = ARWorldTrackingConfiguration()
- config.frameSemantics = .personSegmentation
- uiView.session.delegate = viewModel
- uiView.session.run(config)
- }
-
-
-
- }
- class HumanExtractionViewModel: NSObject,ARSessionDelegate {
- var arFrame: ARFrame? = nil
- func session(_ session: ARSession, didUpdate frame: ARFrame) {
- arFrame = frame
- }
- func catchHuman(){
- if let segmentationBuffer = arFrame?.segmentationBuffer {
-
- if let uiImage = UIImage(pixelBuffer: segmentationBuffer)?.rotate(radians: .pi / 2) {
- UIImageWriteToSavedPhotosAlbum(uiImage, self, #selector(imageSaveHandler(image:didFinishSavingWithError:contextInfo:)), nil)
- }
- }
- }
- @objc func imageSaveHandler(image:UIImage,didFinishSavingWithError error:NSError?,contextInfo:AnyObject) {
- if error != nil {
- print("保存图片出错")
- } else {
- print("保存图片成功")
- }
- }
-
- }
- extension UIImage {
- public convenience init?(pixelBuffer:CVPixelBuffer) {
- var cgimage: CGImage?
-
- VTCreateCGImageFromCVPixelBuffer(pixelBuffer, options: nil, imageOut: &cgimage)
-
- if let cgimage = cgimage{
-
- self.init(cgImage: cgimage)
-
- }else{
- return nil
- }
- }
-
- func rotate(radians: CGFloat) -> UIImage {
- let rotatedSize = CGRect(origin: .zero, size: size).applying(CGAffineTransform(rotationAngle: CGFloat(radians))).integral.size
- UIGraphicsBeginImageContext(rotatedSize)
- if let context = UIGraphicsGetCurrentContext() {
- let origin = CGPoint(x: rotatedSize.width / 2.0, y: rotatedSize.height / 2.0)
- context.translateBy(x: origin.x, y: origin.y)
- context.rotate(by: radians)
-
- draw(in: CGRect(x: -origin.y, y: -origin.x, width: size.width, height: size.height))
-
- let rotateImage = UIGraphicsGetImageFromCurrentImageContext()
- UIGraphicsEndImageContext()
-
- return rotateImage ?? self
-
- }
-
- return self
- }
- }
复制代码 在代码 中,人体分隔缓冲区数据每帧都会更新,所以我们需要从 ARFrame 中及时获取值,然后将缓冲区中的数据转换成图像,由于缓冲区中的数据是直接对应硬件摄像头采集的图像数据,为与屏幕表现保持一致,需要对图像进行90°旋转,生存的图像如下右图所示。
进行人形提取时,只是提取屏幕空间中的人形图像,无须使用深度信息,因此无须使用personSegmentation WithDepth 语义,只使用 personSegmentation 语义有助于提高应用性能。
具体代码地点:GitHub - duzhaoquan/ARkitDemo
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |