【iOS ARKit】人形提取

      为解决人形分离和深度估计问题,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 AVFoundationstruct 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: HumanExtractionViewModelfunc 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 = .personSegmentationuiView.session.delegate = viewModeluiView.session.run(config)}}class HumanExtractionViewModel: NSObject,ARSessionDelegate {var arFrame: ARFrame? = nilfunc 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.sizeUIGraphicsBeginImageContext(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.mzph.cn/news/673336.shtml

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

相关文章

进程状态 | 僵尸进程 | 孤儿进程 | 前台后台进程 | 守护进程

文章目录 1.进程的三种基本状态2.Linux中进程状态查看2.1.进程检测脚本2.2.各种状态查看 3.孤儿进程4.前台、后台、守护进程 1.进程的三种基本状态 进程的在系统当中是走走停停的,「运行 - 暂停 - 运行」的活动规律;进程在活动期间的三种状态&#xff1…

【leetcode题解C++】450.删除二叉搜索树中的节点 and 669.修剪二叉搜索树 and 108.将有序数组转换为二叉搜索树

450. 删除二叉搜索树中的节点 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。 一般来说,删除节点可…

分别通过select、多进程、多线程实现一个并发服务器

select #include<myhead.h>#define PORT 8888 //端口号 #define IP "192.168.114.109" //IP地址int main(int argc, const char *argv[]) {//1、创建用于接受连接的套接字int sfd socket(AF_INET, SOCK_STREAM, 0);if(sfd -1){perror(&q…

【Langchain+Streamlit】旅游聊天机器人

【LangchainStreamlit】打造一个旅游问答AI-CSDN博客 项目线上地址&#xff0c;无需openai秘钥可直接体验&#xff1a;http://101.33.225.241:8502/ github地址&#xff1a;GitHub - jerry1900/langchain_chatbot: langchainstreamlit打造的一个有memory的旅游聊天机器人&…

什么是数据库软删除,什么场景下要用软删除?(go GORM硬删除)

文章目录 什么是数据库软删除&#xff0c;什么场景下要用软删除&#xff1f;go GORM硬删除什么是数据库软删除什么场景下要用软删除 什么是数据库软删除&#xff0c;什么场景下要用软删除&#xff1f; go GORM硬删除 使用的是 GORM&#xff0c;默认启用了软删除功能&#xff…

设计模式(结构型模式)桥接模式

目录 一、简介二、桥接模式2.1、手机品牌接口2.2、手机功能接口2.3、抽象部分2.4、具体抽象部分2.5、使用 三、优点和缺点 一、简介 桥接模式&#xff08;Bridge Pattern&#xff09; 是一种结构型设计模式&#xff0c;用于将抽象部分与它的实现部分分离&#xff0c;使它们可以…

【算法题】96. 不同的二叉搜索树

题目 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5 示例 2&#xff1a; 输入&#xff1a;n 1 输出&#x…

js逆向-某东验证码逆向分析

声明 本文仅供学习参考&#xff0c;如有侵权可私信本人删除&#xff0c;请勿用于其他途径&#xff0c;违者后果自负&#xff01; 如果觉得文章对你有所帮助&#xff0c;可以给博主点击关注和收藏哦&#xff01; 插句个人内容&#xff1a;本人最近正在找工作&#xff0c;工作城…

MySQL数据库常用语法回顾及知识点合集(持续更新中……)

前言 本文适合有一定基础的进行快速简单回顾复习。 对于现如今的无论哪一类软件或应用&#xff0c;都几乎无法离开数据库&#xff0c;常见使用的关系性数据库如MySQL、Oracle&#xff0c;非关系性数据库如MongoDB、Redis等。而MySQL数据库则是软件开发中最常用的数据库之一&…

基于SpringBoot的美妆管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

CS50x 2024 - Lecture 1 - C

本周学习C语言&#xff0c;重点是函数、变量、条件语句和循环。 05:11介绍了编程语言的转换过程&#xff0c;从源代码到机器码&#xff0c;以及编译器的作用。 编译器是将一种语言翻译成另一种语言的程序 09:18使用CS50.dev进行编程&#xff0c;介绍了VS Code和命令行界面的…

LeetCode Python - 1.两数之和

文章目录 题目答案运行结果 题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能…

数据结构——算法的时间复杂度和空间复杂度

1、算法效率 1.1如何衡量一个算法的好坏&#xff1f; 比如我们最熟悉的斐波那契数列 long long Fib(int N) {if(N < 3)return 1;return Fib(N-1) Fib(N-2); } 上面的斐波那契数列使用递归实现&#xff0c;看起来非常的简洁&#xff0c;那么代码一定是越简洁越好么&…

930. 和相同的二元子数组(多指针滑动窗口)

多指针滑动窗口 滑动窗口&#xff0c;由于题目中数组为二元组数组&#xff0c;对于每一个数组下标 j &#xff0c;当其满足 preSum[j]−preSum[i]goal的条件时&#xff0c;对应 i为一个连续区间&#xff0c;若能够求得 i 的左右边界 left1 与 left2&#xff0c;则此时共有 left…

对接社群团购的风险和坑,其实只有两点

社群团购对接合作的风险和坑&#xff0c;其实只有两点。 让大家更好地了解微信群团购&#xff08;社群团购&#xff09;&#xff0c;正确进入这个领域&#xff0c;借助社群团购进行创业以及货源方通过这个销售渠道进行产品销售。我们将行业的几个关键点进行总结分享&#xff0c…

MongoDB聚合: $skip

$skip聚合阶段用于跳过指定数量的输入文档&#xff0c;并将剩余文档传递到流水线的下一个阶段。 语法 { $skip: <positive 64-bit integer> }使用 $skip需要指定一个正整数来决定跳过的文档数量。从5.0开始&#xff0c;$skip阶段跳过文档的数量限制为一个64位的整数&a…

力扣15-三数之和

三数之和 题目链接 解题思路 1、枚举每个数&#xff0c;表示该数nums[i]已被确定&#xff0c;在排序后的情况下&#xff0c;通过双指针l&#xff0c;r分别从左边l i 1和右边n - 1往中间靠拢&#xff0c;找到nums[i] nums[l] nums[r] 0的所有符合条件的搭配 2、在找符合条…

Python CSV文件读取和写入

本文主要为Python 实现CSV文件读取和写入操作。 CSV文件写入和读取 因为没有现成的csv文件&#xff0c;所以csv的顺序为先写入后读取。 写入 创建csv文件并把数据写入&#xff0c;有两种实现方式&#xff1a;直接插入所有行和插入单行。 示例如下&#xff1a; import csv i…

vim最简单命令学习

安装vim sudo apt install vim在终端随便打开一个文本文件&#xff0c;或者源文件&#xff0c; vim filepath输入该命令后&#xff0c;从终端进入vim编辑器&#xff0c;此时为普通模式(Normal)。 按i键进入编辑模式(Insert)&#xff0c;按Esc键返回普通模式(Normal)。 在编辑…

C语言常见面试题:C语言中如何进行比较运算?

在C语言中&#xff0c;比较运算用于比较两个值的大小关系。比较运算符包括等于&#xff08;&#xff09;、不等于&#xff08;!&#xff09;、大于&#xff08;>&#xff09;、小于&#xff08;<&#xff09;、大于等于&#xff08;>&#xff09;和小于等于&#xff0…