【ARFoundation自学04】AR Tracked Image 图像追踪识别

news2024/11/28 20:46:56

图像识别是很常用的AR功能!AR foundation 可以帮助我们轻松实现!

1.安装插件

首先还是在资源包中导入ARfoundation 。然后搭建基本的AR ARFoundation框架!

2.创建AR session 和XR origin结构!

3.然后在XR Origin 物体身上添加AR Tracker Image Manager组件!

这个组件主要负责实现目标图像的识别和追踪! 但是我们需要思考,识别那个图片,识别后让谁追踪图片!他的主要原理是,创建一个图像库Library(Serialized Library),把要被识别的图都放进去,将来所有在库里面的图都可以被单独识别!

然后,识别图片后,为了让我们能够看到追踪图片的视觉效果,AR Tracker Image Manager会为识别后的图像克隆一份Tracked Image Prefab 用于跟随识别到的图像一起运动(移动或者旋转)!如何创建一个Tracked Image Prefab ,我们后面再讲!

4.创建图像识别库

这个图像库,需要用户安装插件后,在Assets 仓库面板空白点右键-Create-XR-Reference Image Library ,然后点击创建的图像库,在右侧属性面板添加将来要被识别的图!

这些图将来都会可识别!

5.创建识别后追踪的预制体(UI、模型等)Tracked Image Prefab  

这个预制体是图像识别专用的,因此需要挂载AR Tracked Image 组件!任何物体挂在了这个组件都可以作为识别图像后的追踪预制体!

那么我们自己的模型放在那里才可以追踪图片呢?只需要放在搭载AR Tracked Image 组件的父物体下面即可!

例如创建一个空物体,挂载AR Tracked Image 组件。把我们的模型放在这个空物体的子物体下面即可!

6. 把创建好可识别图像库以及追踪预制体赋值给 AR Tracker Image Manager组件!完毕

最后 AR Tracker Image Manager组件!还有个属性Max Number Of Moving Image 是最大可跟踪的动态图像数量!

7.其他参数介绍

图像跟踪技术,是指通过图像处理技术对摄像头中拍摄到的2D图像进行定位,并对其姿态进行跟踪的技术。图像跟踪技术的基础是图像识别,图像识别是指识别和检测出数字图像或视频中对象或特征的技术,图像识别技术是信息时代的一门重要技术,其产生目的是为了让计算机代替人类去处理大量的图形图像及真实物体信息,因而成为其他许多重要技术的基

  1. 最大并发跟踪数(Max Simultaneous Tracked Images):

    指定同时能够被识别和跟踪的图像数量。由于图像跟踪较为耗能,限制此数值可以避免性能问题。

    2. 参考图像(Reference Image)    

  • 这些是您希望AR应用能够识别的特定2D图像。比如,一张海报或标志。您需要事先在Unity项目中定义这些图像作为资源。别2D图像的过程实际是一个特征值对比的过程,ARFoundation将从摄像头中获取的图像信息与参考图像库的图像特征点信息进行对比,存储在参考图像库中的用于对比的图像就叫做参考图像。一旦对比成功,真实环境中的图像将与参考图像库的参考图像建立对应关系,每一个真实2D图像的姿态信息也一并被检测。

      3.参考图像库(Reference Image Library)    :

参考图像库用来存储一系列的参考图像用于对比,每一个图像跟踪程序都必须有一个参考图像库,但需要注意的是,参考图像库中存储的实际是参考图像的特征值信息而不是原始图像,这有助于提高对比速度与鲁棒性。参考图像库越大,图像对比就会越慢,建议参考图像库的图像不要超过1000张。跟踪组件提供方(Provider)    ARFoundation是架构在底层SDK图像跟踪API之上的,也即是说ARFoundation并不具体负责图像识别过程的算法,它只提供一个接口,具体图像识别由算法提供方提供。

8.动态修改TrackedImageManager的状态

  • 在代码中,你可以访问TrackedImageManager实例并根据需要动态改变其行为。例如,你可以暂时禁用所有图像的跟踪,或者针对特定图像进行开关控制
    public class ImageTrackingController : MonoBehaviour
    {
        public TrackedImageManager trackedImageManager;
        
        public void DisableImageTracking()
        {
            if (trackedImageManager != null)
            {
                trackedImageManager.enabled = false; // 关闭图像跟踪
            }
        }
    
        public void EnableImageTracking()
        {
            if (trackedImageManager != null)
            {
                trackedImageManager.enabled = true; // 启用图像跟踪
            }
        }
    }

    8.多图像跟踪

对于多图像跟踪,你可能不只希望实例化一个Prefab,而是根据识别到的不同图像实例化不同的Prefab。这时,传统的方式是为每个图像在数据集中指定对应的Prefab。但ARFoundation本身并不直接支持每个图像直接关联不同Prefab,因此需要一些额外的编程逻辑来实现这一功能。

实现逻辑

编写自定义脚本

创建一个C#脚本,用于处理图像识别后的逻辑。在这个脚本中,你需要监听TrackedImageUpdated事件,该事件会在图像被识别或跟踪状态改变时触发。

using System.Collections; // 引入集合相关的命名空间,用于列表(List)和字典(Dictionary)等数据结构
using System.Collections.Generic;
using UnityEngine; // 引入Unity引擎的基本功能
using UnityEngine.XR.ARSubsystems; // 引入AR相关子系统的命名空间
using UnityEngine.XR.ARFoundation; // 引入ARFoundation命名空间,提供AR功能的支持
using TMPro; // 引入TextMeshPro文本组件支持

public class ImageTrackControl : MonoBehaviour // 定义一个新的类,继承自MonoBehaviour,这是Unity中脚本的基础类
{
    // 公开变量,用于在Inspector面板中指定图像识别的核心组件
    public ARTrackedImageManager MyImageManagerCom;

    // 定义字符串变量,用于存储当前状态信息
    string myString;

    // 引用TextMeshProUGUI组件,用于在界面上显示文本信息
    public TextMeshProUGUI textdis;
    public TextMeshProUGUI textdis2;

    // 创建一个列表,用来存储预先准备好的图像追踪预制体
    public List<GameObject> MyImagePre = new List<GameObject>();

    // 使用Dictionary存储每个跟踪图的ID与其对应的预制体GameObject
    public Dictionary<string, GameObject> DityprefabMap = new Dictionary<string, GameObject>();

    // 临时对象变量,用于存储实例化后的游戏对象
    GameObject tempobj;

    // 当此脚本所属的游戏对象被唤醒时调用
    private void Awake()
    {
        // 确保MyImageManagerCom有被指定,若未指定,则尝试从该脚本所挂载的游戏对象上获取ARTrackedImageManager组件
        if (MyImageManagerCom == null)
        {
            MyImageManagerCom = this.transform.GetComponent<ARTrackedImageManager>();
        }

        // 初始化字典,将图像名称与预制体关联起来
        // 注意:这里假设MyImagePre列表已经被正确填充了相应的预制体
        DityprefabMap.Add("a", MyImagePre[0]);
        DityprefabMap.Add("b", MyImagePre[1]);
        DityprefabMap.Add("c", MyImagePre[2]);
        DityprefabMap.Add("d", MyImagePre[3]);
        DityprefabMap.Add("e", MyImagePre[4]);
    }

    // 当脚本或其所属的游戏对象变为可用时调用
    private void OnEnable()
    {
        // 绑定ARTrackedImageManager的trackedImagesChanged事件,当跟踪到的图像发生变化时会调用MyImChanged方法
        if (MyImageManagerCom != null)
        {
            MyImageManagerCom.trackedImagesChanged += MyImChanged;
        }
    }

    // 当脚本或其所属的游戏对象变为不可用时调用
    private void OnDisable()
    {
        // 解绑ARTrackedImageManager的trackedImagesChanged事件,防止内存泄漏或在对象不可用时继续接收事件
        if (MyImageManagerCom != null)
        {
            MyImageManagerCom.trackedImagesChanged -= MyImChanged;
        }
    }

    // 自定义事件处理方法,响应ARTrackedImageManager的trackedImagesChanged事件
    private void MyImChanged(ARTrackedImagesChangedEventArgs obj)
    {
        // 输出日志,表明图像跟踪状态已改变
        Debug.Log("追踪的图像发生变化了,调用委托函数");

        // 遍历新增的图像
        foreach (var trackedImage in obj.added)
        {
            // 更新UI显示新增的图像名称
            textdis.text = "新增图像: " + trackedImage.referenceImage.name;

            // 根据图像的名称从字典中获取对应的预制体,并在该图像的位置和旋转状态下实例化
            tempobj = Instantiate(DityprefabMap[trackedImage.referenceImage.name], trackedImage.transform.position, trackedImage.transform.rotation, trackedImage.transform);

            // 更新UI显示已克隆的预制体名称
            textdis2.text = "克隆了对象" + DityprefabMap[trackedImage.referenceImage.name].name;
        }

        // 下面注释掉的部分原本用于处理更新和移除的图像,可以根据需要启用并实现相应逻辑
        // ...
        
        // 遍历移除的图像,这里只是记录了移除的信息,实际操作如销毁相关游戏对象的逻辑可以根据需求添加
        foreach (var trackedImage in obj.removed)
        {
            myString = "移除图像: " + trackedImage.referenceImage.name;
            Debug.Log("移除图像: " + trackedImage.name);
        }
    }
}

下面是一些关于上面代码中核心类和方法的详细解释:

没有调用过ARTrackedImageManager 类下面的相关方法,尤其是 trackedImagesChanged,他是什么意思呢,什么作用? 

trackedImagesChanged 是 ARFoundation 中 ARTrackedImageManager 类的一个事件(可以去复习C#中的委托和事件的使用)。这个事件在图像跟踪状态发生改变时被触发!就会调用这个事件委托的函数(自己定义的)
在程序中如何使用呢?

 trackedImageManager.trackedImagesChanged += OnTrackedImagesChanged;

其中 trackedImageManager 是AR Tracked Image Manager 组件的对应类变量。存储了你场景中的一个AR Tracked Image Manager 组件!

+= OnTrackedImagesChanged;

这个意思是这个  trackedImageManager.trackedImagesChanged ,组件调用了一个委托事件trackedImagesChanged(代表识别的物体有变化,不管是位置、旋转、还是内容都算),一旦有变化我就委托一个函数去执行一个事情。trackedImageManager.trackedImagesChanged+=OnTrackedImagesChanged;

OnTrackedImagesChanged;就是一个自己定义的函数,被委托了!下面是这个函数的标准定义

 private void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        //具体事情
    }

函数里面有个形式参数,这个参数是必须带的,就像我让你去办一件事,去把车门打开,我得给你钥匙,这个钥匙就是形式参数 ARTrackedImagesChangedEventArgs eventArgs!

ARTrackedImagesChangedEventArgs eventArgs

ARTrackedImagesChangedEventArgs 是 ARFoundation 提供的一个类,它作为参数传递给 ARTrackedImageManagertrackedImagesChanged 事件处理方法。这个类封装了在图像跟踪状态发生改变时的所有相关信息,包括哪些图像被新增、哪些被更新以及哪些被移除。通过分析 eventArgs 参数,开发者可以得知当前跟踪图像集合的具体变化情况,并据此做出相应的逻辑处理,比如实例化或销毁游戏对象、更新UI、执行特定动画等。

ARTrackedImagesChangedEventArgs 类包含三个主要的属性:

  1. added: 这是一个 NativeArray<ARTrackedImage> 类型的集合,包含了所有新被识别和开始跟踪的图像。每一个 ARTrackedImage 对象代表一个被跟踪的图像,包含了图像的 ID、大小、位置、旋转等信息。

  2. updated: 同样是 NativeArray<ARTrackedImage> 类型,包含了所有已跟踪图像中状态有所更新的图像(比如位置、姿态的微小变动)。开发者可以通过这些信息来实时调整已存在的AR内容,确保与实际跟踪状态同步。

  3. removed: 包含了 NativeArray<ARTrackedImage> 类型的集合,表示那些不再被跟踪的图像,可能是由于图像离开视野、遮挡或是其他原因导致跟踪丢失。对于这些图像,开发者通常需要清理与其关联的任何游戏对象或资源,以避免内存泄漏或视觉混乱。

在实际应用中,通过检查和响应 eventArgs 的这三个集合,开发者可以灵活地管理AR体验中的图像跟踪逻辑,保证应用的动态性和响应性。

完整示例代码:

using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class ImageTrackingEventHandler : MonoBehaviour
{
    public ARTrackedImageManager trackedImageManager;

    void Start()
    {
        // 确保ARTrackedImageManager组件已经附加到了某个游戏对象上
        if (trackedImageManager == null)
        {
            trackedImageManager = GetComponent<ARTrackedImageManager>();
        }

        // 订阅trackedImagesChanged事件
        if (trackedImageManager != null)
        {
            trackedImageManager.trackedImagesChanged += OnTrackedImagesChanged;
        }
    }

    // 当跟踪的图像集合发生变化时,此方法会被调用
    private void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        // 遍历新增的图像
        foreach (var trackedImage in eventArgs.added)
        {
            Debug.Log("新增图像: " + trackedImage.name);
            // 这里可以添加实例化预设体或其他处理逻辑
        }

        // 遍历更新的图像
        foreach (var trackedImage in eventArgs.updated)
        {
            Debug.Log("更新图像: " + trackedImage.name);
            // 可以在这里根据需要更新图像相关联的游戏对象状态
        }

        // 遍历移除的图像
        foreach (var trackedImage in eventArgs.removed)
        {
            Debug.Log("移除图像: " + trackedImage.name);
            // 这里可以添加销毁相关联游戏对象的逻辑
        }
    }

    void OnDestroy()
    {
        // 当这个脚本被销毁时,取消订阅事件,防止内存泄漏
        if (trackedImageManager != null)
        {
            trackedImageManager.trackedImagesChanged -= OnTrackedImagesChanged;
        }
    }
}

9. 再来一份代码,实现图像不在被追踪是清除克隆的Image prefab

using UnityEngine; // 引入Unity基本库,提供游戏对象、组件、物理等基础功能
using UnityEngine.XR.ARFoundation; // 引入ARFoundation库,用于AR开发的核心功能
using UnityEngine.XR.ARSubsystems; // 引入AR子系统,提供低级AR支持
using System.Collections.Generic; // 引入通用集合类型,如List、Dictionary等

public class TrackedImageHandler : MonoBehaviour // 定义一个Unity组件类,可以挂载到游戏对象上
{
    public ARTrackedImageManager trackedImageManager; // 公开的ARTrackedImageManager组件引用,用于管理图像跟踪
    public GameObject imagePrefab; // 公开的GameObject预设体,当识别到图像时将克隆这个预设体

    private Dictionary<XRCameraImageId, GameObject> trackedObjects = new Dictionary<TrackableId, GameObject>(); // 私有的字典,用于存储跟踪图像ID与对应实例化游戏对象的关系

    void Start() // Unity生命周期方法,当游戏对象启动时调用
    {
        if (trackedImageManager == null) // 检查是否已经指定了trackedImageManager
        {
            trackedImageManager = FindObjectOfType<ARTrackedImageManager>(); // 如果没有指定,则尝试在场景中自动查找ARTrackedImageManager组件
        }

        if (trackedImageManager != null) // 确保找到了ARTrackedImageManager
        {
            trackedImageManager.trackedImagesChanged += OnTrackedImagesChanged; // 注册事件处理器,当跟踪图像变化时调用OnTrackedImagesChanged方法
        }
        else
        {
            Debug.LogError("ARTrackedImageManager not found in the scene."); // 如果找不到ARTrackedImageManager,打印错误信息
        }
    }

    void OnDestroy() // Unity生命周期方法,在游戏对象被销毁前调用
    {
        if (trackedImageManager != null) // 确保trackedImageManager仍然有效
        {
            trackedImageManager.trackedImagesChanged -= OnTrackedImagesChanged; // 解除事件注册,避免内存泄漏
        }
    }

    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs) // 处理图像跟踪状态变化的事件方法
    {
        foreach (var trackedImage in eventArgs.removed) // 遍历移除的图像
        {
            GameObject trackedObject;
            if (trackedObjects.TryGetValue(trackedImage.trackableId, out trackedObject)) // 尝试从字典中获取关联的GameObject
            {
                Destroy(trackedObject); // 销毁关联的GameObject
                trackedObjects.Remove(trackedImage.trackableId); // 从字典中移除该条目
            }
        }

        foreach (var trackedImage in eventArgs.added) // 遍历新增的图像
        {
            if (!trackedObjects.ContainsKey(trackedImage.trackableId)) // 确保这个图像还没有被处理过
            {
                GameObject newObject = Instantiate(imagePrefab, trackedImage.transform.position, trackedImage.transform.rotation); // 实例化预设体,并放置在图像的位置和旋转
                trackedObjects.Add(trackedImage.trackableId, newObject); // 记录新实例化对象与图像ID的关联
            }
        }

        foreach (var trackedImage in eventArgs.updated) // 遍历更新的图像(位置或状态改变)
        {
            GameObject trackedObject;
            if (trackedObjects.TryGetValue(trackedImage.trackableId, out trackedObject)) // 获取关联的GameObject
            {
                trackedObject.transform.position = trackedImage.transform.position; // 更新游戏对象的位置
                trackedObject.transform.rotation = trackedImage.transform.rotation; // 更新游戏对象的旋转
            }
        }
    }
}

其他部分读者根据前面的理解应该能看懂!

解释一下其中的 if (trackedObjects.TryGetValue(trackedImage.trackableId, out trackedObject)) { Destroy(trackedObject); trackedObjects.Remove(trackedImage.trackableId); }

这段代码的作用是从一个字典(trackedObjects)中查找与特定跟踪图像ID(trackedImage.trackableId)关联的游戏对象,并在找到后进行销毁和从字典中移除的操作。让我逐步解释每一部分:

  1. if (trackedObjects.TryGetValue(trackedImage.trackableId, out trackedObject)):

    • TryGetValue 是 Dictionary 类的一个方法,用于尝试从字典中获取与指定键(这里是 trackedImage.trackableId)相关联的值(即游戏对象 GameObject)。
    • 方法有两个参数:键(key,这里是 trackedImage.trackableId)和一个输出参数(out parameter),用于接收查找到的值。如果找到了对应的键值对,这个值会被输出到 out 参数中;如果没有找到,输出参数会被赋予类型的默认值(对于引用类型,如 GameObject,默认值是 null)。
    • 这行代码的意思是尝试从 trackedObjects 字典中查找 trackedImage.trackableId 对应的 GameObject,并将找到的对象赋值给 trackedObject 变量。如果找到,TryGetValue 方法会返回 true,让 if 条件成立,执行后续代码。
  2. Destroy(trackedObject);:

    • 如果 trackedObject 不为 null(即字典中找到了与之关联的游戏对象),Destroy 函数会被调用,用来销毁这个 GameObject 实例。在Unity中,Destroy 方法用于清理游戏对象及其所有的子对象,释放它们占用的资源。
  3. trackedObjects.Remove(trackedImage.trackableId);:

    • 在销毁了游戏对象之后,这行代码从 trackedObjects 字典中移除与 trackedImage.trackableId 关联的条目。这样做是为了保持字典的整洁,避免保留不再使用的键值对,也有助于内存管理。

综上所述,这段代码块旨在处理图像跟踪移除事件,当一个AR跟踪图像不再被识别或跟踪时,它会安全地销毁与该图像关联的任何游戏对象实例,并清理字典中的记录,确保系统资源得到合理释放和管理。

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

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

相关文章

ubuntu22.04编译OpenCV4.9(带contrib-4.9.0)

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;4.9.0 opencv_contrib版本&#xff1a;4.9.0 源码下载 OPenCV4.9.0下载地址&#xff1a;https://github.com/opencv/opencv/releases/tag/4.9.0 如下图所示&#xff1a; 按箭头所指点击下载source code(tar.gz)文件到…

电机专用32位MCU PY32MD310,Arm® Cortex-M0+内核

PY32MD310是一颗专为电机控制设计的MCU&#xff0c;非常适合用做三相/单相 BLDC/PMSM 的主控芯片。芯片采用了高性能的 32 位 ARM Cortex-M0 内核&#xff0c;QFN32封装。内置最大 64 Kbytes flash 和 8 Kbytes SRAM 存储器&#xff0c;最高48 MHz工作频率&#xff0c;多达 16 …

Day51 动态规划part10+Day52 动态规划part11

LC121买卖股票的最佳时机&#xff08;未掌握&#xff09; 暴力&#xff1a;双层循环寻找最优间距&#xff0c;每一次都确定一个起点&#xff0c;遍历剩余节点当作终点 贪心&#xff1a;取最左最小值&#xff0c;不断遍历那么得到的差值最最大值就是最大利润。 动态规划 dp数组…

【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

0基础学习Elasticsearch-使用Java操作ES

文章目录 1 背景2 前言3 Java如何操作ES3.1 引入依赖3.2 依赖介绍3.3 隐藏依赖3.4 初始化客户端&#xff08;获取ES连接&#xff09;3.5 发送请求给ES 1 背景 上篇学习了0基础学习Elasticsearch-Quick start&#xff0c;随后本篇研究如何使用Java操作ES 2 前言 建议通篇阅读再回…

SpringBoot: 可执行jar的特殊逻辑

这一篇我们来看看Java代码怎么操作zip文件(jar文件)&#xff0c;然后SpringBoot的特殊处理&#xff0c;文章分为2部分 Zip API解释&#xff0c;看看我们工具箱里有哪些工具能用SpringBoot的特殊处理&#xff0c;看看SpringBoot Jar和普通Jar的不同 1. Zip API解释 1. ZipFil…

NRF24L01(2.4G)模块的使用——SPI时序(软件)篇

一、SPI的简介&#xff1a; SPI 是英语Serial Peripheral interface的缩写&#xff0c;顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。 SPI&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;并且在芯片的管脚…

R语言 | 使用最简单方法添加显著性ggpubr包

本期教程原文&#xff1a;使用最简单方法添加显著性ggsignif包 本期教程 获得本期教程代码和数据&#xff0c;在后台回复关键词&#xff1a;20240605 小杜的生信笔记&#xff0c;自2021年11月开始做的知识分享&#xff0c;主要内容是R语言绘图教程、转录组上游分析、转录组下游…

毫米波SDK使用2

5.5 毫米波SDK-TI组件 毫米波SDK功能分解成组件将在接下来的几小节中解释。有关这些模块的详细文档&#xff0c;请参阅位于mmwave_mcuplus_sdk_<ver>/docs/mmwave_sdk_module_document .html的顶层文档。 5.5.1 演示 5.5.1.1 毫米波演示 这个演示位于mmwave_mcuplus_sd…

批量高效调整图片像素:自定义缩小bmp图片,画质优先,一键实现高效优化

图片已经成为我们生活中不可或缺的一部分。无论是社交媒体分享&#xff0c;还是工作文件传输&#xff0c;图片总是扮演着重要的角色。然而&#xff0c;有时候&#xff0c;我们可能会面临一个问题&#xff1a;图片像素过大&#xff0c;不仅占用过多的存储空间&#xff0c;还可能…

【网络教程】Iptables官方教程-学习笔记7-简单理解IPTABLES规则的作用流程

前面学习了IPTABLES的所有功能介绍后&#xff0c;一个Linux设备里的IPTABLES规则集是如何运行的&#xff0c;这里简单做个介绍。 在Linux设备里输入"iptables -nvl",得到该设备的所有防火墙规则&#xff0c;得到的结果中可以看到这个设备防火墙里所有的链以及链里的…

STM32F103C8移植uCOSIII并以不同周期点亮两个LED灯(HAL库方式)【uCOS】【STM32开发板】【STM32CubeMX】

STM32F103C8移植uC/OSIII并以不同周期点亮两个LED灯&#xff08;HAL库方式&#xff09;【uC/OS】【STM32开发板】【STM32CubeMX】 实验说明 将嵌入式操作系统uC/OSIII移植到STM32F103C8上&#xff0c;构建两个任务&#xff0c;两个任务分别以1s和3s周期对LED进行点亮—熄灭的…

力扣hot100:394. 字符串解码(递归)

LeetCode&#xff1a;394. 字符串解码 本题容易想到用递归处理&#xff0c;在写递归时主要是需要明确自己的递归函数的定义。 不过我们也可以利用括号匹配的方式使用栈进行处理。 1、递归 定义递归函数string GetString(string & s,int & i); 表示处理处理整个numbe…

高中数学:数列-基础概念

一、什么是数列&#xff1f; 一般地&#xff0c;我们把按照确定的顺序排列的一列数称为数列&#xff0c;数列中的每一个数叫做这个数列的项&#xff0c;数列的第一项称为首项。 项数有限个的数列叫做有穷数列&#xff0c;项数无限个的数列叫做无穷数列。 二、一般形式 数列和…

2024高考作文引发的人工智能争议

又是一年高考季&#xff0c;多少学子的修行成果也在这这一刻迎来了终极检验&#xff0c;多少学子的梦也在这一刻拉开了揭晓序幕&#xff0c;多少学习的命运也在这一刻迎来了人生中的第一次转变。每年的高考不仅是学子们的人生大事&#xff0c;也是多少父母的热切期望&#xff0…

Java Web学习笔记25——Vue组件库Element

什么是Element&#xff1f; Element: 是饿了么团队研发的&#xff0c;一套为开发者、设计师和产品经理准备的基于Vue2.0的桌面端组件库。 组件&#xff1a;组成网页的部件&#xff0c;例如&#xff1a;超链接、按钮、图片、表格、表单、分页条等等。 官网&#xff1a;https:…

详解C++中的ANSI、Unicode和UTF8三种字符编码及相互转换

目录 1、概述 2、Visual Studio中的字符编码 3、ANSI窄字节编码 4、Unicode宽字节编码 5、UTF8编码 6、如何使用字符编码 7、三种字符编码之间的相互转换&#xff08;附源码&#xff09; 8、Windows系统对使用ANSI窄字节字符编码的程序的兼容 9、字符编码导致程序启动…

1-8 C语言分支循环语句

C语言的语句分为 5 类 1&#xff1a;表达式语句2&#xff1a;函数调用语句3&#xff1a;控制语句4&#xff1a;复合语句5&#xff1a;空语句 控制语句&#xff1a;用于控制程序的执行流程&#xff0c;以实现程序的各种结构方式&#xff0c;它们由特定的语句定义符组成&#x…

【日记】遇到了一个 “不愿睁眼看世界也没受过社会毒打” 的逆天群友(464 字)

正文 今天坐在柜台玩了一天手机…… 手机都玩没电了快。下午在劝一个群友睁眼看世界&#xff0c;实在劝不动。他真的太逆天了&#xff0c;我不清楚这么高学历的人&#xff0c;怎么能说出这么天真的话。逆天又离谱。 晚上的时间几乎全在做家务。平时晚上都是跳舞来着&#xff0c…

云原生架构案例分析_1.某旅行公司云原生改造

随着云计算的普及与云原生的广泛应用&#xff0c;越来越多的从业者、决策者清晰地认识到“云原生化将成为企业技术创新的关键要素&#xff0c;也是完成企业数字化转型的最短路径”。因此&#xff0c;具有前瞻思维的互联网企业从应用诞生之初就扎根于云端&#xff0c;谨慎稳重的…