当前位置: 首页 > news >正文

IOS ARKit进行图像识别

先讲一下基础控涧,资源的话可以留言,抽空我把它传到GitHub上,这里没写收积分,竟然充值才能下载,我下载也要充值,牛!
ARSCNView 可以理解画布或者场景
1 配置 ARWorldTrackingConfiguration AR追踪识别相关
ARFaceTrackingConfiguration 面部识别
2 加载资源 图片资源就不多讲,手机拍照去掉底图就可以了,3d模型需要带linda的ipad pro或者iphone pro构建
一共两种一种是识别图片,一种是识别3d模型,感觉图片识别效果较好,但是麻烦点是获取现实世界空间坐标,而且对运动物体还是不是很友好,所以后来准备看一下CoreML相关

let configuartion = ARWorldTrackingConfiguration()
var images :[UIImage] = []for i in 1...19{let image = UIImage(named: "AR\(i)")images.append(image!)}//加载图片资源,通过图片名configuartion.detectionImages = loadedImagesFromDirectoryContents(images)configuartion.maximumNumberOfTrackedImages = 1//加载3d资源,3d资源文件如下图所示
if let referenceObj = ARReferenceObject.referenceObjects(inGroupNamed: "AR Resource Group", bundle: nil){print("")configuartion.detectionObjects = referenceObj}configuartion.isAutoFocusEnabled = true // 确保自动对焦开启
//       configuartion.planeDetection = .horizontalconfiguartion.isLightEstimationEnabled = truesceneView.session.run(configuartion, options: [.resetTracking,.removeExistingAnchors])//遵守的代理协议ARSessionDelegate 会话协议sceneView.session.delegate = self//ARSCNViewDelegate scnview场景协议sceneView.delegate = self//显示调试参数sceneView.debugOptions = [SCNDebugOptions.showFeaturePoints]//通过图片名加载图片func loadedImagesFromDirectoryContents(_ images: [UIImage]) -> Set<ARReferenceImage>{var index = 0var customReferenceSet = Set<ARReferenceImage>()images.forEach { (downloadedImage) in//1. Convert The UIImage To A CGImageguard let cgImage = downloadedImage.cgImage else { return }//2. Get The Width Of The Imagelet imageWidth = CGFloat(cgImage.width)//3. Create A Custom AR Reference Image With A Unique Namelet customARReferenceImage = ARReferenceImage(cgImage, orientation: CGImagePropertyOrientation.up, physicalWidth: imageWidth)customARReferenceImage.name = "MyCustomARImage\(index)"//4. Insert The Reference Image Into Our SetcustomReferenceSet.insert(customARReferenceImage)print("ARReference Image == \(customARReferenceImage)")index += 1}//5. Return The Setreturn customReferenceSet}

3d资源文件,文件格式是.arobject,该文件是通过带Linda的iPad pro设备扫描生成的,详情参考代码demo
请添加图片描述

ARSessionDelegate 协议

/*会话失败*/func session(_ session: ARSession, didFailWithError error: any Error) {print("didFailWithError")}/*相机更改了追踪模式*/func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {let state = camera.trackingStateprint("cameraDidChangeTrackingState")}/*当会话中断时调用此方法。会话将被中断,不再能跟踪什么时候它无法接收所需的传感器数据。 当视频捕获中断时,例如当应用程序被发送到后台或当有的时候多个前台应用程序(请参阅AVCaptureSessionInterruptReason)。在中断结束之前,不会传送额外的帧更新。*/func sessionWasInterrupted(_ session: ARSession) {print("sessionWasInterrupted")}/*当会话中断结束时调用。会话将从最后一次已知的状态继续运行一次中断已经结束。 如果设备移动,锚点将不对齐。为避免这种情况,一些应用程序可能想要重置跟踪(请参阅ARSessionRunOptions)。*/func sessionInterruptionEnded(_ session: ARSession) {print("sessionInterruptionEnded")}/*当会话输出新的音频采样缓冲区时*/func session(_ session: ARSession, didOutputAudioSampleBuffer audioSampleBuffer: CMSampleBuffer) {print("didOutputAudioSampleBuffer")}func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {//更新锚点位置,存入的锚点信息,也可以是图片锚点for anchor in anchors {guard let objectAnchor = anchor as? ARObjectAnchor else { continue }// 查找对应的框节点if let frameNode = sceneView.scene.rootNode.childNode(withName: "frame", recursively: true) {
//                    frameNode.position = SCNVector3(
//                        objectAnchor.transform.columns.3.x,
//                        objectAnchor.transform.columns.3.y,
//                        objectAnchor.transform.columns.3.z
//                    )frameNode.simdTransform = anchor.transform}}//        guard let trackedAnchor = trackedAnchor else{return}
//        
//        for anchor in anchors{
//            if anchor.identifier == trackedAnchor.identifier{
//                let newTransform = anchor.transform
//                let position = SCNVector3(newTransform.columns.3.x,
//                                          newTransform.columns.3.y,
//                                          newTransform.columns.3.z)
//                
//                DispatchQueue.main.async {
//                    self.trackNode?.position = position
//                }
//            }
//        }
//        print("didupdate session")
//        //跟踪目标物体
//        for anchor in anchors {
//              if let objectAnchor = anchor as? ARObjectAnchor {
//                  print("Object moved to: \(objectAnchor.transform)")
//                  
//                  // 更新虚拟对象的位置
//                  if let node = sceneView.node(for: objectAnchor) {
//                      let transform = objectAnchor.transform
//                      node.simdTransform = transform
//                  }
//              }
//          }}func session(_ session: ARSession, didUpdate frame: ARFrame) {DispatchQueue.global().async {self.handleFrame(session: session, frame: frame)}}

ARSCNViewDelegate代理

 /*实现这个为给定的锚点提供一个自定义节点。@discussion 此节点将自动添加到场景图。如果未实现此方法,将自动创建一个节点。如果返回nil,锚点将被忽略。@param renderer渲染场景的渲染器。@param anchor添加的锚点。@return将映射到锚点或nil的节点*/
//    func renderer(_ renderer: any SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
//        return nil
//    }/*当新节点已映射到给定的锚点时调用。@param renderer 渲染场景的渲染器。@param node 映射到锚点的节点。@param anchor 添加的锚点。*/func renderer(_ renderer: any SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//        print("添加新的节点锚点数据到场景中")if let objectAnchor = anchor as? ARObjectAnchor {print("Detected object: \(objectAnchor.referenceObject.name ?? "Unknown")")// 创建一个框架来圈住物体let frameNode = createFrame(for: objectAnchor.referenceObject)frameNode.position = SCNVector3(objectAnchor.transform.columns.3.x,objectAnchor.transform.columns.3.y,objectAnchor.transform.columns.3.z)sceneView.scene.rootNode.addChildNode(frameNode)}//        if let imageAnchor = anchor as? ARImageAnchor{
//            let image = imageAnchor.referenceImage
//            
//            if let imagename = image.name, imagename.hasPrefix("MyCustomARImage"){
//                // 创建一个虚拟对象(如盒子)来标记目标位置let box = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)let material = SCNMaterial()material.diffuse.contents = UIColor.redbox.materials = [material]let boxNode = SCNNode(geometry: box)boxNode.position = SCNVector3(0, 0, 0)node.addChildNode(boxNode)
//                DispatchQueue.main.async {
//                    self.showToast()
//                }
//            }
//        }
}/*当节点将使用给定锚点的数据进行更新时调用。@param renderer 渲染场景的渲染器。@param node 将被更新的节点。@param anchor 即将更新的锚点。*/func renderer(_ renderer: any SCNSceneRenderer, willUpdate node: SCNNode, for anchor: ARAnchor) {
//        print("即将更新新节点锚点数据")}/*当节点将使用给定锚点的数据进行更新时调用。@param renderer 渲染场景的渲染器。@param node 将被更新的节点。@param anchor 已更新的锚点。*/func renderer(_ renderer: any SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
//        print("已经更新节点锚点数据")}/*当映射节点已从给定锚点的场景图中删除时调用。@param renderer渲染场景的渲染器。@param node已删除的节点。@param anchor已删除的锚点。*/func renderer(_ renderer: any SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) {print("删除节点")}

以上是整个代码流程
图片识别部分如下

 private func handleFrame(session: ARSession,frame: ARFrame){let i = frame.timestamp - (self.currentFrmae?.timestamp ?? 0)
//        print("time i\(i)")if i < 1{return}self.currentFrmae = frameguard let frameImg = getCurrentFrameImage(from: session) else{return}var isMatched:Bool = falsefor img in self.images{
//            if compareImages(image1: frameImg, image2: img) == 1{
//                isMatched = true
//                break
//            }let im1 = frameImglet im2 = imgmatchImages(image1: frameImg, image2: img) { [weak self]isok inif isok{DispatchQueue.main.async {self?.showToast()}}}}if isMatched{DispatchQueue.main.async {self.showToast()}}}//获取当前会话帧数据func getCurrentFrameImage(from session: ARSession) -> UIImage? {guard let currentFrame = session.currentFrame else {print("当前没有 ARFrame")return nil}let pixelBuffer = currentFrame.capturedImagelet ciImage = CIImage(cvPixelBuffer: pixelBuffer)let context = CIContext()guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else {return nil}return UIImage(cgImage: cgImage)}//对比图片2func matchImages(image1: UIImage, image2: UIImage, completion: @escaping (Bool) -> Void) {guard let cgImage1 = image1.cgImage, let cgImage2 = image2.cgImage else {completion(false)return}//使用自定义检测任务let request1 = VNGenerateImageFeaturePrintRequest()let request2 = VNGenerateImageFeaturePrintRequest()let request3 = VNDetectRectanglesRequest()request3.minimumConfidence = 0.8request3.minimumAspectRatio = 0.1request3.maximumAspectRatio = 1.0request3.quadratureTolerance = 10let handler1 = VNImageRequestHandler(cgImage: cgImage1, options: [:])let handler2 = VNImageRequestHandler(cgImage: cgImage2, options: [:])let handler3 = VNImageRequestHandler(cgImage: cgImage1, options: [:])do {try handler1.perform([request1])try handler2.perform([request2])try handler3.perform([request3])guard let featurePrint1 = request1.results?.first as? VNFeaturePrintObservation,let featurePrint2 = request2.results?.first as? VNFeaturePrintObservation else {completion(false)return}if let observations = request3.results as? [VNRectangleObservation], !observations.isEmpty{// 假设目标区域是第一个匹配的矩形let boundingBox = observations.first?.boundingBoxprint("boundRext: \(boundingBox)")}var distance: Float = 0try featurePrint1.computeDistance(&distance, to: featurePrint2)print("匹配值 \(distance)")if distance < 0.8{ //距离0.8mprint("图片相似")}completion(distance < 0.8) // 设定相似度阈值} catch {print("匹配失败:\(error)")completion(false)}}

相关文章:

IOS ARKit进行图像识别

先讲一下基础控涧&#xff0c;资源的话可以留言&#xff0c;抽空我把它传到GitHub上&#xff0c;这里没写收积分&#xff0c;竟然充值才能下载&#xff0c;我下载也要充值&#xff0c;牛&#xff01; ARSCNView 可以理解画布或者场景 1 配置 ARWorldTrackingConfiguration AR追…...

初级数据结构——二叉搜索树

目录 前言一、定义二、基本操作三、时间复杂度分析四、变体五、动态图解六、代码模版七、经典例题[1.——700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/)代码题解 [2.——938. 二叉搜索树的范围和](https://leetcode.cn/problems/ra…...

C++设计模式之组合模式中如何实现同一层部件的有序性

在组合模式中&#xff0c;为了实现同一层上部件的有序性&#xff0c;可以采取以下几种设计方法&#xff1a; 1. 使用有序集合 使用有序集合&#xff08;如 std::list、std::vector 或其他有序容器&#xff09;来存储和管理子部件。这种方法可以确保子部件按照特定顺序排列&am…...

duxapp RN 端使用AppUpgrade 进行版本更新

版本更新包含了组件和工具的组合 注册 下面这是 duxcms 入口文件检查更新的注册方法&#xff0c;注册的同时会检查更新 import {request,updateApp,userConfig } from ./utils// 检查app更新 setTimeout(async () > {if (process.env.TARO_ENV rn) {// eslint-disable-n…...

【计网】自定义序列化反序列化(三) —— 实现网络版计算器【下】

&#x1f30e;实现网络版计算器【下】 本次序列化与反序列化所用到的代码&#xff0c;Tcp服务自定义序列化反序列化实现网络版计算器。 文章目录&#xff1a; 实实现网络版计算器【下】 客户端实现     基于守护进程的改写 &#x1f680;客户端实现 在这之前&#xff0c…...

神经网络中的优化方法(一)

目录 摘要Abstract1. 与纯优化的区别1.1 经验风险最小化1.2 代理损失函数1.3 批量算法和小批量算法 2. 神经网络中优化的挑战2.1 病态2.2 局部极小值2.3 高原、鞍点和其他平坦区域2.4 悬崖和梯度爆炸2.5 长期依赖2.6 非精确梯度2.7 局部和全局结构间的弱对应 3. 基本算法3.1 随…...

Linux 计算机网络基础概念

目录 0.前言 1.计算机网络背景 1.1 独立模式 1.2 网络互联 1.3 局域网&#xff08;Local Area Network&#xff0c;LAN&#xff09; 1.4 广域网&#xff08;Wide Area Network&#xff0c;WAN&#xff09; 2.协议 2.1什么是协议 2.2协议分层和软件分层 2.3 OSI七层网络模型 2.3…...

qt QGraphicsEllipseItem详解

1、概述 QGraphicsEllipseItem是Qt框架中QGraphicsItem的一个子类&#xff0c;它提供了一个可以添加到QGraphicsScene中的椭圆项。QGraphicsEllipseItem表示一个带有填充和轮廓的椭圆&#xff0c;也可以用于表示椭圆段&#xff08;通过startAngle()和spanAngle()方法&#xff…...

Python websocket

router.websocket(/chat/{flow_id}) 接口代码&#xff0c;并了解其工作流程、涉及的组件以及如何基于此实现你的新 WebSocket 接口。以下内容将分为几个部分进行讲解&#xff1a; 接口整体概述代码逐行解析关键组件和依赖关系如何基于此实现新功能示例&#xff1a;创建一个新的…...

【MySQL-5】MySQL的内置函数

目录 1. 整体学习的思维导图 2. 日期函数 ​编辑 2.1 current_date() 2.2 current_time() 2.3 current_timestamp() 2.4 date(datetime) 2.5 now() 2.6 date_add() 2.7 date_sub() 2.8 datediff() 2.9 案例 2.9.1 创建一个出生日期登记簿 2.9.2 创建一个留言版 3…...

深度学习笔记之BERT(三)RoBERTa

深度学习笔记之RoBERTa 引言回顾&#xff1a;BERT的预训练策略RoBERTa训练过程分析静态掩码与动态掩码的比较模型输入模式与下一句预测使用大批量进行训练使用Byte-pair Encoding作为子词词元化算法更大的数据集和更多的训练步骤 RoBERTa配置 引言 本节将介绍一种基于 BERT \t…...

C++知识点总结(59):背包型动态规划

背包型动态规划 一、背包 dp1. 01 背包&#xff08;限量&#xff09;2. 完全背包&#xff08;不限量&#xff09;3. 口诀 二、例题1. 和是质数的子集数2. 黄金的太阳3. 负数子集和4. NASA的⻝物计划 一、背包 dp 1. 01 背包&#xff08;限量&#xff09; 假如有这几个物品&am…...

C++:反向迭代器的实现

反向迭代器的实现与 stack 、queue 相似&#xff0c;是通过适配器模式实现的。通过传入不同类型的迭代器来实现其反向迭代器。 正向迭代器中&#xff0c;begin() 指向第一个位置&#xff0c;end() 指向最后一个位置的下一个位置。 代码实现&#xff1a; template<class I…...

webGL入门教程_04vec3、vec4 和齐次坐标总结

vec3、vec4 和齐次坐标总结 1. vec3 和 vec4 1.1 什么是 vec3 和 vec4&#xff1f; vec3&#xff1a; GLSL 中的三维向量类型&#xff0c;包含 3 个浮点数&#xff1a;(x, y, z)。常用于表示三维坐标、RGB 颜色、法线、方向等。 vec4&#xff1a; GLSL 中的四维向量类型&…...

uniapp中父组件数组更新后与页面渲染数组不一致实战记录

简单描述一下业务场景方便理解: 商品设置功能,支持添加多组商品(点击添加按钮进行增加).可以对任意商品进行删除(点击减少按钮对选中的商品设置进行删除). 问题: 正常添加操作后,对已添加的任意商品删除后,控制台打印数组正常.但是与页面显示不一致.已上图为例,选中尾…...

优化 Conda 下载速度:详细的代理配置和网络管理策略

优化 Conda 下载速度&#xff1a;详细的代理配置和网络管理策略 为了彻底解决使用 Conda 下载 PyTorch 时遇到的速度问题&#xff0c;并确保下载过程稳定可靠&#xff0c;这需要一个详细、综合的技术方案。让我们更深入地分析问题原因&#xff0c;然后详尽地解释采取的解决策略…...

服务器遭受DDoS攻击后如何恢复运行?

当服务器遭受 DDoS&#xff08;分布式拒绝服务&#xff09;攻击 后&#xff0c;恢复运行需要快速采取应急措施来缓解攻击影响&#xff0c;并在恢复后加强防护以减少未来攻击的风险。以下是详细的分步指南&#xff1a; 一、应急处理步骤 1. 确认服务器是否正在遭受 DDoS 攻击 …...

MFC音视频播放器-支持电子放大等功能

前言 本播放器在VS2019下开发&#xff0c;使用ffmpegD3D实现视频播放渲染功能。同时本播放器支持录像功能、截图功能、音视频播放功能、码流信息显示、电子放大功能等。D3D的渲染同时支持surface和texture两种方式&#xff0c;电子放大功能是在D3D Texture方式下进行实现。以下…...

c语言编程1.17蓝桥杯历届试题-回文数字

题目描述 观察数字&#xff1a;12321&#xff0c;123321 都有一个共同的特征&#xff0c;无论从左到右读还是从右向左读&#xff0c;都是相同的。这样的数字叫做&#xff1a;回文数字。 本题要求你找到一些5位或6位的十进制数字。满足如下要求&#xff1a; 该数字的各个数位之…...

el-table 纵向 横向 多级表头

<el-table :data"tableData" class"diaTable":span-method"handleSpanMethod"border:header-cell-style"{background:#292929,color:#fff}"><!-- 纵向表头 --><el-table-column label"纵向表头" width"…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目&#xff0c;设置虚拟环境&#xff0c;出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...