【iOS ARKit】人形提取

news2024/10/6 16:31:14

      为解决人形分离和深度估计问题,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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1438249.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构第九天(堆排序)

目录 前言 概述 源码: 主函数: 运行结果: 其他 前言 哈哈,这个堆排序算法很久之前就已经敲过一遍了,时间一久,思路有点淡忘。今天重新看过一遍之后,又亲自撸代码,幸运的是&am…

python毕设选题 - 基于时间序列的股票预测于分析

文章目录 1 简介2 时间序列的由来2.1 四种模型的名称: 3 数据预览4 理论公式4.1 协方差4.2 相关系数4.3 scikit-learn计算相关性 5 金融数据的时序分析5.1 数据概况5.2 序列变化情况计算 最后 1 简介 Hi,大家好,今天向大家介绍一个大数据项目…

IEC 104电力规约详细解读(三) - 遥信

1.功能简述 遥信,、即状态量,是为了将断路器、隔离开关、中央信号等位置信号上送到监控后台的信息。遥信信息包括:反应电网运行拓扑方式的位置信息。如断路器状态、隔离开关状态;反应一次二次设备工作状况的运行信息,如…

位运算:进制

4982. 进制 - AcWing题库 给定两个整数 a,b 请你计算,在 [a,b] 范围内有多少个整数满足其二进制表示恰好有一个 0。 不考虑前导 0。 例如,当 a5,b10 时,[5,10]范围内的所有整数及其二进制表示如下: 可以看出,只有 5 和…

Python HTTP隧道在远程通信中的应用:穿越网络的“魔法门”

在这个数字化时代,远程通信就像是我们日常生活中的“魔法门”,让我们可以随时随地与远方的朋友、同事或服务器进行交流。而在这扇“魔法门”的背后,Python HTTP隧道技术发挥着举足轻重的作用。 想象一下,你坐在家里的沙发上&…

多维时序 | MATLAB实现基于CNN-LSSVM卷积神经网络-最小二乘支持向量机多变量时间序列预测

多维时序 | MATLAB实现基于CNN-LSSVM卷积神经网络-最小二乘支持向量机多变量时间序列预测 目录 多维时序 | MATLAB实现基于CNN-LSSVM卷积神经网络-最小二乘支持向量机多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于CNN-LSSVM卷积神经…

【知识图谱--第二讲知识图谱的表示】

知识图谱的表示 知识表示Knowledge Representation 知识表示方法知识图谱的符号表示基于图的知识表示与建模简单图建模-最简单的无向图有向标记图OWL与Ontology 知识图谱的向量表示 知识表示 Knowledge Representation 知识表示(KR)就是用易于计算机处…

【C语言】socket函数

一、socket函数函数的原型 int socket(int domain, int type, int protocol); 其中: domain参数指定套接字应该使用的协议族(例如,AF_INET表示IPv4协议族)。type参数指定套接字类型(例如,SOCK_STREAM表示…

老是抓不准现货白银实时报价怎么办?

现货白银的实时报价是不断变动的,投资者要了解当下的现货白银实时走势,并且依靠对实时报价的分析预判未来的趋势,这是不容易的,但是不是不能做到呢?也不是。因为市场不是横盘就是趋势,只要有趋势&#xff0…

机器学习--K近邻算法,以及python中通过Scikit-learn库实现K近邻算法API使用技巧

文章目录 1.K-近邻算法思想2.K-近邻算法(KNN)概念3.电影类型分析4.KNN算法流程总结5.k近邻算法api初步使用机器学习库scikit-learn1 Scikit-learn工具介绍2.安装3.Scikit-learn包含的内容4.K-近邻算法API5.案例5.1 步骤分析5.2 代码过程 1.K-近邻算法思想 假如你有一天来到北京…

Django前后端分离之后端实践2

小实践:实现用户登录、注销及ORM管理功能、事务开启小实践 models.py class Books(models.Model):id models.CharField(primary_keyTrue,max_length20,verbose_name"图书ID")name models.CharField(max_length20,verbose_name图书名称)status models…

Spring如何扫描自定义的注解?

目录 一、Spring框架介绍 二、什么是自定义注解 三、如何扫描自定义的注解 一、Spring框架介绍 Spring框架是一个开源的Java应用程序框架,它提供了一种全面的编程和配置模型,用于构建现代化的企业级应用程序。Spring框架的核心原则是依赖注入&#x…

零基础学Python之面向对象

1.面向对象编程简介 (1)什么是面向对象 面向对象程序设计(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。任何一个模型都不可能反映客观事…

Java实现批量视频抽帧2.0

继上个版本 对其进行略微升级 &#x1f913; 上个版本仅对一个视频进行抽帧处理 此版本可对一个文件夹内的全部视频进行抽帧并对应的文件夹进行帧图片的保存 1️⃣配置pom.xml &#xff08;保持上次不变&#xff09; <dependencies><dependency><grou…

推理系统学习笔记

一些学习资料 最近对MLsys比较感兴趣&#xff0c;遂找些资料开始学习一下 https://fazzie-key.cool/2023/02/21/MLsys/https://qiankunli.github.io/2023/12/16/llm_inference.htmlhttps://dlsyscourse.orghttps://github.com/chenzomi12/DeepLearningSystem/tree/main/04Infe…

数智文旅:智慧文旅中的数字化转型

在数字化浪潮席卷全球的今天&#xff0c;旅游业作为传统服务业的代表&#xff0c;正面临着前所未有的转型压力与机遇。智慧文旅&#xff0c;作为旅游业与数字技术深度融合的产物&#xff0c;不仅标志着旅游业进入了全新的发展阶段&#xff0c;更预示着未来旅游业将朝着更加智能…

QAnything之BCEmbedding技术路线

QAnything和BCEmbedding简介 QAnything[github]是网易有道开源的检索增强生成式应用&#xff08;RAG&#xff09;项目&#xff0c;在有道许多商业产品实践中已经积累丰富的经验&#xff0c;比如有道速读和有道翻译。QAnything是一个支持任意格式文件或数据库的本地知识库问答系…

【开源】JAVA+Vue+SpringBoot实现公司货物订单管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 客户管理模块2.2 商品维护模块2.3 供应商管理模块2.4 订单管理模块 三、系统展示四、核心代码4.1 查询供应商信息4.2 新增商品信息4.3 查询客户信息4.4 新增订单信息4.5 添加跟进子订单 五、免责说明 一、摘要 1.1 项目…

Tauri 的基本使用笔记

文章目录 前言如何将 Tauri 集成到前端项目?进程间通信&#xff08;命令&#xff09;const invoke window.__TAURI__.invoke; 进程间通信&#xff08;事件&#xff09;前端 ⇒ RustRust ⇒ 前端我的疑问 开发时的一些技巧用代码打开前端的开发者工具让 Tauri 不要监听文件Rus…

Leetcode 30天高效刷数据结构和算法 Day1 两数之和 —— 无序数组

两数之和 —— 无序数组 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现…