【iOS ARKit】人形提取

打印 上一主题 下一主题

主题 806|帖子 806|积分 2418

      为办理人形分离和深度估计问题,ARKit 新增长了 Segmentation Buffer(人体分隔缓冲区)和Estimated Depth Data Buffer(深度估计缓冲区)两个缓冲区。人体分隔缓冲区作用雷同于图形渲染管线中的 Stencil Buffer(模板缓冲区),用于区分人形区域与配景区域,它是一个像素级的缓冲区,用于准确地描述人形区域。
     人体分隔缓冲区用于标识人形区域,所以可以使用非常简单的结构,如使用1标识该像素是人形区域,而用。标识该像素为配景区。人体分隔缓冲区每帧都更新,所以可以动态地追踪摄像头采集的人形变化。
     既然人体分隔缓冲区标识了人形区域,我们也就可以使用该缓冲区提取出场景中的人形以便后续应用,如将人形图像通过网络传输到其他AR装备中,实现雷同虚拟会议的效果;或者将人形图像放入虚拟世界中,营造更绚酷的体验;或者对提取的人形图像进行模糊和打马赛克等处理,实现以往只能使用绿幕才华实现的及时人形捕捉效果。
     为简单起见,本节我们直接获取人体分隔缓冲区数据并将其生存为图像,关键代码如代码如下所示。
  1. //
  2. //  HumanExtraction.swift
  3. //  ARKitDeamo
  4. //
  5. //  Created by zhaoquan du on 2024/2/4.
  6. //
  7. import SwiftUI
  8. import ARKit
  9. import RealityKit
  10. import Combine
  11. import VideoToolbox
  12. import AVFoundation
  13. struct HumanExtraction: View {
  14.    
  15.     var viewModel = HumanExtractionViewModel()
  16.    
  17.     var arView: ARView {
  18.         let arView = ARView(frame: .zero)
  19.         
  20.         return arView
  21.     }
  22.    
  23.     var body: some View {
  24.         HumanExtractionContainer(viewModel: viewModel)
  25.             .overlay(
  26.             VStack{
  27.                 Spacer()
  28.                 Button(action:{viewModel.catchHuman()}) {
  29.                     Text("截取人形")
  30.                         .frame(width:120,height:40)
  31.                         .font(.body)
  32.                         .foregroundColor(.black)
  33.                         .background(Color.white)
  34.                         .opacity(0.6)
  35.                 }
  36.                 .offset(y:-30)
  37.                 .padding(.bottom, 30)
  38.             }
  39.     )
  40.         .edgesIgnoringSafeArea(.all)
  41.     }
  42. }
  43. struct HumanExtractionContainer : UIViewRepresentable{
  44.    
  45.     var viewModel: HumanExtractionViewModel
  46.    
  47.    
  48.     func makeUIView(context: Context) -> some ARView {
  49.         let arView = ARView(frame: .zero)
  50.         
  51.       
  52.         
  53.         return arView
  54.     }
  55.    
  56.     func updateUIView(_ uiView: UIViewType, context: Context) {
  57.         guard ARWorldTrackingConfiguration.supportsFrameSemantics(.personSegmentation) else {
  58.             return
  59.         }
  60.         
  61.         let config = ARWorldTrackingConfiguration()
  62.         config.frameSemantics = .personSegmentation
  63.         uiView.session.delegate = viewModel
  64.         uiView.session.run(config)
  65.     }
  66.    
  67.    
  68.    
  69. }
  70. class HumanExtractionViewModel: NSObject,ARSessionDelegate {
  71.     var arFrame: ARFrame? = nil
  72.     func session(_ session: ARSession, didUpdate frame: ARFrame) {
  73.         arFrame = frame
  74.     }
  75.     func catchHuman(){
  76.         if let segmentationBuffer = arFrame?.segmentationBuffer {
  77.             
  78.             if let uiImage = UIImage(pixelBuffer: segmentationBuffer)?.rotate(radians: .pi / 2) {
  79.                 UIImageWriteToSavedPhotosAlbum(uiImage, self, #selector(imageSaveHandler(image:didFinishSavingWithError:contextInfo:)), nil)
  80.             }
  81.         }
  82.     }
  83.     @objc func imageSaveHandler(image:UIImage,didFinishSavingWithError error:NSError?,contextInfo:AnyObject) {
  84.         if error != nil {
  85.             print("保存图片出错")
  86.         } else {
  87.             print("保存图片成功")
  88.         }
  89.     }
  90.    
  91. }
  92. extension UIImage {
  93.     public convenience init?(pixelBuffer:CVPixelBuffer) {
  94.         var cgimage: CGImage?
  95.         
  96.         VTCreateCGImageFromCVPixelBuffer(pixelBuffer, options: nil, imageOut: &cgimage)
  97.         
  98.         if let cgimage = cgimage{
  99.             
  100.             self.init(cgImage: cgimage)
  101.             
  102.         }else{
  103.             return nil
  104.         }
  105.     }
  106.    
  107.     func rotate(radians: CGFloat) -> UIImage {
  108.         let rotatedSize = CGRect(origin: .zero, size: size).applying(CGAffineTransform(rotationAngle: CGFloat(radians))).integral.size
  109.         UIGraphicsBeginImageContext(rotatedSize)
  110.         if let context = UIGraphicsGetCurrentContext() {
  111.             let origin = CGPoint(x: rotatedSize.width / 2.0, y: rotatedSize.height / 2.0)
  112.             context.translateBy(x: origin.x, y: origin.y)
  113.             context.rotate(by: radians)
  114.             
  115.             draw(in: CGRect(x: -origin.y, y: -origin.x, width: size.width, height: size.height))
  116.             
  117.             let rotateImage = UIGraphicsGetImageFromCurrentImageContext()
  118.             UIGraphicsEndImageContext()
  119.             
  120.             return rotateImage ?? self
  121.             
  122.         }
  123.         
  124.         return self
  125.     }
  126. }
复制代码
     在代码 中,人体分隔缓冲区数据每帧都会更新,所以我们需要从 ARFrame 中及时获取值,然后将缓冲区中的数据转换成图像,由于缓冲区中的数据是直接对应硬件摄像头采集的图像数据,为与屏幕表现保持一致,需要对图像进行90°旋转,生存的图像如下右图所示。

     进行人形提取时,只是提取屏幕空间中的人形图像,无须使用深度信息,因此无须使用personSegmentation WithDepth 语义,只使用 personSegmentation 语义有助于提高应用性能。
具体代码地点:GitHub - duzhaoquan/ARkitDemo

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81429

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表