数组根据key值排序

//封装一个数组排序方法 function compare(key, desc) {//key: 用于排序的数组的key值; desc: 布尔值,为true是升序排序,false是降序排序 return function(a, b) { let value1 = a[key]; let value2 = b[key]; if (desc == true) { // 升序排列 return value1 - value2; } else { // 降序排列 return value2 - value1; } }; } //调用 arr.sort(compare('age',false)); 以上代码来源:js:数组对象按key值进行升序降序排序 // 升序 quickFun(params) { //当进行递归的数组的长度小于等于 1 的时候直接返回该数组 if (params.length <= 1) { return params; } let middleIndex = Math.floor(params.length / 2); //获取基准数据的下标 let middleItem = params.

winform桌面程序如何调用后台API的方法(一)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 目录 前言 一、如何解决? 二、使用步骤 步骤一:构建后台API 步骤二:构建后台API 步骤三:效果展示 三、总结 前言 每当进行winform桌面程序开发时,为了实现项目之间的代码复用,通常会将一些通用的方法封装成动态库(.dll)。但是这样也存在一个问题,假设将方法A方法封装成动态库MyDll后,项目Project1引用了MyDll,可以使用A方法;在项目Project2引用MyDll使用A方法时,发现A方法有bug,并对A方法进行修复。此时,Project1使用的方法A仍然存在bug,需要重新引用最新的MyDll才能修复A的bug。那么,是否有更好的解决方法,在Project2修复完成时,Project1引用的方法A也同步修复呢? 提示:以下是本篇文章正文内容,下面案例可供参考 一、如何解决? 现在我给大家介绍的,就是如何使用winform调用后台的API 二、使用步骤 步骤一:构建后台API 开发工具:VS2019目标框架:.net core 3.1先在后台写一个简单的方法GetDateTime,用于winform端进行调用。 代码如下(GetDateTime): using Agreement.Business.System; using Agreement.Entity.Enum; using Agreement.Entity.Models.AgreementEntity; using log4net; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace tokendemo.Controllers { [ApiController] [Route("[controller]/[action]")] public class MyTestDemoController : CommServers { private readonly ILog _logger; public MyTestDemoController() { _logger = LogManager.GetLogger(typeof(MyTestDemoController)); } [HttpGet] public async Task<TData> GetDateTime() { string strResult= "

基于Bootstrap的登录&注册模板(html+css)

基于Bootstrap的登录&注册模板(html+css) 1、简介2、功能2.1 登录2.2 注册 3、展示4、下载地址 1、简介 基于Bootstrap的登录&注册模板(html+css),适合django等框架,可直接修改对接后端 2、功能 登录、注册、输入信息错误提醒、记住密码、自动登录等等 2.1 登录 <div class="col-lg-6 bg-white"> <div class="form d-flex align-items-center"> <div class="content"> <form method="post" action="login.html" class="form-validate" id="loginFrom"> <div class="form-group"> <input id="login-username" type="text" name="userName" required data-msg="请输入用户名" placeholder="用户名" value="admin" class="input-material"> </div> <div class="form-group"> <input id="login-password" type="password" name="passWord" required data-msg="请输入密码" placeholder="密码" class="input-material"> </div> <button id="login" type="submit" class="btn btn-primary">登录</button> <div style="margin-top: -40px;"> <div class="custom-control custom-checkbox " style="float: right;"> <input type="checkbox" class="custom-control-input" id="check2" > <label class="custom-control-label" for="

【已解决】Windows 的 docker 删除容器后 WSL2 磁盘空间不释放的问题

【已解决】Windows 的 docker 删除容器后 WSL2 磁盘空间不释放的问题 1、起因及原因2、解决2.1 找到要压缩的虚拟磁盘文件2.2 关闭 Docker Desktop2.3 压缩虚拟磁盘文件 3、偏招 1、起因及原因 很多同学拉取镜像使用一段时间后发现 C 盘快满了,把之前用过的镜像和容器删除,发现 WSL 挂载目录的虚拟磁盘大小没有变化,非常的奇怪。 其实,不同于 WSL1,WSL2 本质上是虚拟机,所以 Windows 会自动创建 vhdx 后缀的虚拟磁盘文件作为存储。这个 vhdx 后缀的虚拟磁盘文件特点是可以自动扩容,但是一般不会自动缩容。一旦有很多文件把它“撑大”,即使把这些文件删除它也不会自动“缩小”。所以删除文件后还需要我们手动进行压缩才能释放磁盘空间。 2、解决 2.1 找到要压缩的虚拟磁盘文件 如果你没更改挂载磁盘的位置,那他位置在 C:\Users\<你当前用户名>\AppData\Local\Docker\wsl\data\ext4.vhdx ,记下路径,后面要用到。 2.2 关闭 Docker Desktop 在任务栏右下角右键单击 Docker Desktop 图标关闭 Docker 桌面,选择退出 Docker 桌面,等一会 Docker 图标没了之后,就证明 Docker 完全关闭了,然后,打开命令提示符: wsl --list -v 我们就能能够看到,确保两个状态都已停止。 如果这一步没关闭也没问题,最后所有操作结束后,重启 Docker Desktop 即可。 2.3 压缩虚拟磁盘文件 在 PowerShell 中执行: # 关闭 WSL2 中的 linux distributions wsl --shutdown # 运行管理计算机的驱动器的 DiskPart 命令 diskpart 会新打开一个叫 DiskPart 的命令窗口,如下图:

linux 离线安装包

1、下载离线安装包 我们设备有网的时候,可以先使用apt install package_name安装,然后观看该软件对应的版本号。然后再到上面两个网址中下载相应版本号的.deb包。一定要注意版本号,不然的话,可能会因为需要的依赖环境不符合等原因导致安装失败。 sudo apt-get -d install 包名 如 sudo apt-get -d install iputils-ping 安装包会下载到 /var/cache/apt/archives/ 将安装包复制到需要的目录下取出 sudo cp -r /var/cache/apt/archives/* /需要复制到的目录 2、在另一台无网络环境下的电脑中安装。 切换到安装包所在路径 使用dpkg -i 安装包名.deb的方式离线安装对应软件包。

性能测试只知道Jmeter? 5个常用开源性能测试工具介绍

互联网应用具备高并发高负载的特性,为了保障应用上线后面对海量请求仍可正常提供各项服务,进行性能测试是非常重要的一环。 通过对应用进行负载测试,确定系统在高负载情况下的承受能力,找出系统中可能存在的瓶颈和问题。 本文将介常5个开源性能测试工具,每个工具都有详细的介绍、Git 地址、并为每个工具提供一个简单的示例。 1. Apache JMeter Apache JMeter 是一个纯 Java 应用程序,可用于测试静态和动态 Web 资源、FTP、数据库、LDAP 等服务器和网络协议。它能模拟大量用户同时访问目标服务器,并记录和分析响应时间、吞吐量、错误率等指标。 使用场景: 1) 对 Web 应用进行压力测试 2) 测试 REST API 接口的性能 3) 测试 FTP、JDBC 和 LDAP 服务的性能 Git 仓库地址: https://github.com/apache/jmeter 使用示例: jmeter -n -t test.jmx -l test-results.jtl -e -o test-report/ 2. Gatling Gatling 是一个基于 Scala 的高性能负载测试工具,采用异步非阻塞 I/O 技术,支持 HTTP、JMS、WebSocket 等多种协议。它提供了丰富的 DSL(Domain Specific Language) 语法,使得测试脚本编写更加简单灵活。 使用场景: 1) 对 Web 应用进行压力测试 2) 测试 REST API 接口的性能 3) 测试 WebSocket 和 JMS 服务的性能

【面经】2023年软件测试面试题大全(持续更新)附答案

前阵子一位读者告诉我,某位大厂HR给他发了我之前做的面试题答案合集。 这个消息让我开心了一整天😂,因为这说明我之前做的面试题系列真的能帮助到部分测试同学,也算是侧面得到了一种认可吧。 坚持可是我们程序员家族的优良传统🐶 今天写的这份面试题我之前就整理分享过,但当时有一部分是没有参考答案的。断断续续总有读者来问我要答案。所以今天吃完饭抽空把遗漏的给补上了,分享给出来,希望能帮到大家。 老规矩,看到面试题,还是希望大家先不要马上看答案。先自己心里想一遍,如果是你你会怎么回答。另外,因为是面试题,所以回答时思维展现尽量全面一些。本文为抛砖引玉,如果大家对哪题有更好的答案,非常欢迎在评论区留言讨论。 在这里也预祝大家面试顺利! 标签:百度腾讯阿里抖音滴滴京东快手测试开发面试题 开始正文: 👉排查问题的思路 🍉Q:网页崩溃的原因是什么? 1. 内存泄漏 2. 网页代码复杂和浏览器bug 3. 网页数据过多 4. Ajax的Web服务漏洞 🍉Q:有个用户反馈上传头像失败,分析原因? 🍉Q:app闪退的原因? 🍉Q:偶然闪退的排查? 一般成熟的团队都会有 crash 的监控平台,可以从 crash 平台上去查看 crash 发生位点。 手工尝试复现 crash,一般偶然的闪退,都不会特别容易复现,可能需要适当施加一些比较苛刻的条件(弱网、断网、快速点击、快速划动等等)。 查看 crash 日志,比如 Android APP 可以用 adb 命令去查看: // mac 下面 adb logcat *:E | grep CRASH // windows 下面 adb logcat *:E | findstr CRASH 执行 Monkey 或遍历测试,暴力操作手机,尝试复现 bug。 🍉Q:网页卡顿的原因是什么? 原因一:http 请求次数太多 解决:规范接口设计,减少 http 请求次数。 原因二:接收数据时间过长,如下载资源过大 解决:对 HTTP 传输进行压缩,可采用 gzip 无损压缩,压缩效果最佳。

Windows 环境下 Docker 安装伪分布式 Hadoop

Windows 环境下 Docker 安装伪分布式 Hadoop 1、环境2、拉取镜像3、启动容器4、预备操作4.1安装vim4.1.1 更新软件包信息4.1.2 安装vim 4.2 换源4.2.1 备份镜像源设置文件4.2.2 编辑镜像源设置文件4.2.3 重新更新一下软件包信息 4.3 同步上海时间4.3.1 安装 tzdata4.3.2 设置 tzdata 4.4 安装 ssh 配置免密登陆4.4.1 安装 ssh4.4.2 设置允许 root 远程访问 5、配置远程连接6、号外 1、环境 Windows 11 Docker 20.0.2 2、拉取镜像 我选择 ubuntu20.04: docker pull ubuntu:20.04 然后我们用命令看一下本地镜像: docker images 3、启动容器 docker run -it IMAGE_ID bash 4、预备操作 4.1安装vim 4.1.1 更新软件包信息 apt-get update 4.1.2 安装vim apt-get install vim 4.2 换源 4.2.1 备份镜像源设置文件 cp /etc/apt/sources.list /etc/apt/sources.list.bak 4.2.2 编辑镜像源设置文件 vim /etc/apt/sources.

Spring Cloud Feign 请求添加headers

目录 方案一:方法上的@RequestMapping注解添加headers信息方案二:接口上的@RequestMapping注解添加headers信息方案三:使用@Headers注解添加headers信息方案四:自定义RequestInterceptor添加headers信息方案五:自定义RequestInterceptor实现添加动态数据到header 方案一:方法上的@RequestMapping注解添加headers信息 @RequestMapping注解的属性中包含一个headers数组,所以尝试使用,在指定的方法上@RequestMapping注解中添加需要的headers,可以是写死的,也可以读取配置,测试是有效的 同理@RequestMapping一组的@PostMapping,@GetMapping注解等均适用 @FeignClient(name = "server",url = "127.0.0.1:8080") public interface FeignTest { @RequestMapping(value = "/test",headers = {"app=test-app","token=${test-app.token}"}) String test(); } 方案二:接口上的@RequestMapping注解添加headers信息 针对单个方法可以在方法上的@RequestMapping注解中添加headers,如果同一个接口中所有的方法都需要同样的headers时在方法上加就比较繁琐了,可以在接口上的@RequestMapping注解中添加headers,使整个接口的方法均被添加同样的headers @FeignClient(name = "server",url = "127.0.0.1:8080") @RequestMapping(value = "/",headers = {"app=test-app","token=${test-app.token}"}) public interface FeignTest { @RequestMapping(value = "/test") String test(); } @RequestMapping(value = "/student", headers = {"token=${localdebug.feignclient.token:}"}) 方案三:使用@Headers注解添加headers信息 @FeignClient(name = "server",url = "127.0.0.1:8080") @Headers({"app: test-app","token: ${test-app.token}"}) public interface FeignTest { @RequestMapping(value = "/test") String test(); } 查看openfeign官方文档发现其使用的是@Headers来添加headers,测试发现并没有生效,spring cloud使用了自己的SpringMvcContract来解析注解,所以需要自己实现一个Contract来实现对@Headers注解的支持,具体实现参照https://juejin.

Unity游戏开发学习——基础知识

1.类的三大特性 在面向对象编程中,类的三大特性是封装、继承和多态。 封装(Encapsulation):封装指的是将数据和操作数据的方法包装在一个单元中,通过对外提供公共接口来访问数据,同时隐藏内部实现的细节,使得代码更加易读、易用和易于维护。这样可以保证数据的安全性和一致性,并且可以更好地组织和管理代码。 继承(Inheritance):继承是指一个类可以继承另一个类的属性和方法。被继承的类称为父类或基类,继承的类称为子类或派生类。子类可以继承父类的特性,并且可以在此基础上进行扩展或修改。 代码的重用和扩展:子类可以继承父类的属性和方法,避免了重复编写代码,提高了代码的复用性。子类还可以在继承基础上进行扩展和修改,实现代码的灵活性和可扩展性。统一的代码结构和接口:继承可以建立类之间的层级关系,使得代码更具有组织性和可读性。子类可以通过重写父类的方法,实现不同对象的不同行为,同时保持了统一的方法接口。 多态(Polymorphism):多态指的是同一种操作可以在不同的对象上具有不同的表现形式。具体来说,多态允许使用父类类型的变量来引用子类类型的对象,通过方法的重写和重载来实现不同对象的不同行为。 简化代码的逻辑和维护:多态允许使用父类类型的变量来引用子类类型的对象,通过统一的方法调用方式,简化了代码的逻辑,使得代码更加易读和易于维护。提高代码的灵活性和可扩展性:通过多态,可以在运行时根据对象的实际类型来决定调用哪个类的方法,实现了动态绑定。这样可以在不修改原有代码的情况下,通过添加新的子类来扩展功能。 这三大特性共同构成了面向对象编程的基础,它们使得代码更加结构化、可维护和可扩展,同时提高了代码的重用性和灵活性。 高内聚,低耦合 高内聚(High Cohesion)和低耦合(Low Coupling)是软件设计中的两个重要原则,用于指导模块、组件或类的设计方式。下面对这两个概念进行解释: 高内聚(High Cohesion):高内聚是指一个模块、组件或类内部的各个元素相互关联紧密,共同完成特定的功能或任务。高内聚的设计使得模块内的功能职责清晰,并且各个元素之间的依赖关系较强。 高内聚的特点: 模块或类内的功能相关性强,每个元素都是为了完成同一类任务而设计。模块或类内部的协作较多,各个元素之间的控制流程简单且清晰。修改某个元素时,影响范围较小,不会对其他元素产生太大影响。 高内聚的好处: 提高代码的可读性和可维护性。方便重用和测试。减少模块间的依赖,提高系统的灵活性和扩展性。 低耦合(Low Coupling):低耦合是指模块、组件或类之间的相互依赖关系较弱,彼此之间的关联关系尽可能减少。低耦合的设计使得模块、组件或类可以独立开发、测试和修改,提高系统的灵活性和可维护性。 低耦合的特点: 模块或类之间的依赖关系少,相互之间尽量减少直接引用。使用抽象接口或中间层来解除直接依赖,提供松耦合的方式进行交互。模块或类之间的通信通过松散的接口或消息传递完成。 低耦合的好处: 提高系统的灵活性和可扩展性,模块或类的替换和重用更容易。减少修改某个模块或类时对其他模块或类的影响。降低系统的复杂度,便于理解和维护。 通过高内聚和低耦合的设计,可以提高代码的可读性、可维护性和可扩展性,降低模块或类之间的相互影响,从而构建出更优雅和可靠的软件系统。 2.值类型和应用类型区别 C#中常见的一些数据类型: 值类型: 数值类型:整型(byte、sbyte、short、ushort、int、uint、long、ulong)、浮点型(float、double、decimal)字符类型:字符类型(char)布尔类型:布尔类型(bool)结构体类型:结构体(struct)枚举类型:枚举(enum) 引用类型: 字符串类型:字符串(string)数组类型:数组(array)类类型:类(class)接口类型:接口(interface)委托类型:委托(delegate)对象类型:对象(object) 除了以上基本数据类型,还可以通过组合、泛型等方式创建和使用其他复杂的数据类型。 值类型引用类型存储方式值类型的变量存储的是实际的数据值。当值类型的变量被赋值给另一个变量或作为参数传递给方法时,会复制该值的副本。对副本的操作不会影响原始值。引用类型的变量存储的是对象的引用或地址,而不是实际的数据值。当引用类型的变量被赋值给另一个变量或作为参数传递给方法时,复制的是引用或地址,两个变量引用同一个对象。对于引用类型的副本和原始对象的操作都会影响到同一个对象。内存分配值类型的变量通常直接存储在栈(Stack)上,它们的内存分配和销毁都是自动的,且具有较高的效率。引用类型的对象通常存储在堆(Heap)上,它们的内存分配和销毁需要由垃圾回收器(Garbage Collector)来管理,引用类型的变量存储在栈上,实际存储的是对象的引用。传递方式值类型在赋值给其他变量或作为参数传递给方法时,会进行复制,因此会占用更多的内存空间。对于大型值类型的传递,可能会带来性能上的开销。引用类型在赋值给其他变量或作为参数传递给方法时,只是复制了引用,它们共享相同的对象,因此不会占用额外的内存空间。 3.GC是什么,为什么会产生GC,怎么避免GC GC(Garbage Collection)是一种自动内存管理机制,它负责在程序运行时自动检测和释放不再使用的内存。GC通过标记和回收垃圾对象来实现内存的回收和重用,以避免内存泄露和提高内存使用效率。 产生GC的原因主要有以下几点: 动态分配内存:在程序运行过程中,可能会动态地创建对象和分配内存空间。如果没有及时释放不再使用的内存,将会导致内存泄露。 对象的生命周期:程序中的对象会在不同的时刻被创建和销毁。一些对象可能只在局部范围内使用,一旦超出范围就不再需要。如果没有及时销毁这些不再使用的对象,将会引发内存泄露。 内存管理方式:对于手动管理内存的编程语言(如C、C++),如果程序员没有正确地进行内存分配和释放,容易导致内存泄露和内存访问错误。 为了避免GC或减少GC的发生,可以采取以下策略: 尽量减少对象的创建:可以通过重用对象、使用对象池等方式来避免频繁地创建和销毁对象,减少内存管理的开销。 及时释放不再使用的对象:当某个对象不再被使用时,可以手动将其置为null或显式调用析构函数来释放其占用的内存空间。 尽量使用局部变量:将对象的作用域限制在局部范围内,使得对象超出作用域后可以被自动销毁。 避免循环引用:循环引用是指多个对象相互引用,形成一个环状结构,导致它们之间无法被垃圾回收器正确地识别和释放。可以通过断开循环引用、使用弱引用(Weak Reference)等方式来解决循环引用问题。 避免大对象和大数组:大对象和大数组占用大量内存空间,容易导致内存碎片等问题。可以将大对象拆分为多个小对象,或者使用流式处理等方式来避免一次性加载大量数据。 需要注意的是,GC是一种自动化的内存管理机制,通常由编程语言或运行时环境提供支持。在大多数情况下,我们无需过多关注GC的具体实现细节,只需要编写良好的代码,及时释放不再使用的对象,并避免常见的内存泄露情况即可。 4.MonoBehaviour的生命周期有那些,它们之间的执行顺序是什么 Awake: Awake方法在对象被创建后立即被调用,用于初始化对象的状态和变量。不同对象的Awake方法会按照它们在场景中的出现顺序依次执行。 OnEnable: OnEnable方法在对象被激活时调用,可用于启用相关的组件、注册事件或进行其他初始化操作。 Start: Start方法在对象的第一个更新帧之前调用,常用于执行一些只需在游戏开始时执行一次的逻辑。 FixedUpdate: FixedUpdate方法在固定时间间隔内被调用,用于处理物理相关的计算和操作。它与Update方法的不同之处在于,它以固定的时间间隔进行调用而不受帧率的影响。 Update: Update方法在每一帧被调用,用于处理游戏逻辑的更新。例如,处理玩家输入、移动物体、更新游戏状态等。 LateUpdate: LateUpdate方法在Update方法之后被调用,在每一帧更新之后执行。一般用于处理在Update中可能修改了位置或旋转的逻辑。例如,相机跟随玩家移动。 OnDisable: OnDisable方法在对象被禁用时调用,通常用于执行资源的释放、取消事件的注册等清理操作。 OnDestroy: OnDestroy方法在对象被销毁之前调用,用于进行最后的清理工作。例如,释放占用的资源、取消注册的事件等。 5.Array,List,Dictionary之间的区别是什么 是什么大小存储Array(数组)数组是一种固定长度且连续存储的数据结构,可以在内存中按索引快速访问元素。数组的长度在创建时确定,无法动态增加或减少。数组可以具有多个维度数组可以存储任意类型的元素,包括基础类型、对象等。List(列表)列表是一种动态长度的数据结构,可以根据需要动态增加或减少元素。只具有一个维度,但可以使用数组列表或列表的列表。列表可以存储任意类型的元素,通过索引访问和修改。Dictionary(字典)字典是一种键值对(Key-Value)的数据结构,每个元素都由一个唯一的键和对应的值组成。字典的元素无序存储,通过键快速访问对应的值。 只具有一个维度。字典可以存储不同类型的键和值,键和值的类型可以不同。 数组可以具有多个维度,而 ArrayList或泛型List始终只具有一个维度,但是我们可以轻松创建数组列表或列表的列表。

python列表映射相关

Python list 常用操作 | 菜鸟教程 Python map() 函数 | 菜鸟教程 li = [1, 9, 8, 4] [elem*2 for elem in li] Python 2.x 返回列表。 Python 3.x 返回迭代器。 list(map(lambda x: x ** 2, [1, 2, 3, 4, 5]))

vs报错:线程间操作无效: 从不是创建控件的线程访问它

winform中如果是从其它线程访问控件,而不是创建控件的线程那么就会报错(编译器的跨线程访问) 方法1:禁止编译器跨线程检查 Control.CheckForIllegalCrossThreadCalls = false; 方法2:使用Action和Invoke FrmWelcom frmWelcom = new FrmWelcom(); Thread thread = new Thread(() => { Thread.Sleep(2000); //frmWelcom.Close(); //【方法2】使用invoke,这个是异步invoke的意思,Action可以放到外面写 frmWelcom.BeginInvoke(new Action(() => { frmWelcom.Close(); })); }); 方法3:使用BackgroundWorker组件

Python:Numpy中的cumsum()函数的使用

1、作用 cumsum 的作用主要就是计算轴向的累加和。 def cumsum(self, axis=None, dtype=None, out=None): """ :param axis: :param dtype: :param out: """ 2、每个参数意义 2.1 axis 假设二维数组: 2.1.1 不指定参数 不指定 axis 参数时,把二维数组当作了一维数组处理,进行累计求和运算。即1,1+2,1+2+3,1+2+3+4,1+2+3+4+5,1+2+3+4+5+6 import numpy as np a = np.array([[1, 2, 3], [4, 5, 6]]) np.cumsum(a) 输出: array([ 1, 3, 6, 10, 15, 21], dtype=int32) 2.1.2 axis = 0 axis=0 指的是按行累加,即 本行 = 本行 + 上一行,即:5=1+4,7=2+5,9=3+6 import numpy as np a = np.array([[1, 2, 3], [4, 5, 6]]) np.

OpenCV - 图片增加透明通道,图片合并透明通道

1 为图像增加透明通道 一般人像抠图相关的AI模型会输出一个Mask图,这个Mask图就是我们需要的可以将人物抠出来的Alpha通道信息,我们需要将这个Mask图附加到原始图片上,从BGR图片转成BGRA图片或者从RGB图片转成RGBA图片。 如果使用OpenCV进行图像处理,在为图像增加透明通道时会使用到cv::split和cv::merge方法,先使用cv::split方法分离原始图片各个通道,然后将Mask加入到原始通道中,最后使用cv::merge合成新的通道生成最后的图片。 示例代码如下 #include "opencv2/opencv.hpp" cv::Mat MergeAlpha(const cv::Mat& src_image, const cv::Mat& alpha_image) { std::vector<cv::Mat> channels; cv::split(src_image, channels); channels.push_back(alpha_image); cv::Mat src_alpha; cv::merge(channels, src_alpha); return src_alpha; } 需要注意的是,Mask图片必须与原始图片具有相同的分辨率大小和相同的数据类型,比如原始图片是1920x1080,CV_8UC3的图片,那么Mask图片必须是1920x1080,CV_8UC1的图片。 如果你的OpenCV是编译了CUDA,还可以将上述代码修改成CUDA版本 cv::Mat MergeAlphaCUDA(const cv::Mat& src_image, const cv::Mat& alpha_image) { cv::cuda::GpuMat src_image_gpu; src_image_gpu.upload(src_image); cv::cuda::GpuMat alpha_image_gpu; alpha_image_gpu.upload(alpha_image); std::vector<cv::cuda::GpuMat> channels; cv::cuda::split(src_image_gpu, channels); channels.push_back(alpha_image_gpu); cv::cuda::GpuMat src_alpha_gpu; cv::cuda::merge(channels, src_alpha_gpu); cv::Mat result; src_alpha_gpu.download(result); src_image_gpu.release(); alpha_image_gpu.release(); src_alpha_gpu.release(); for (int i = 0; i < channels.size(); ++i) { channels[i].release(); } return result; } 按理来说,使用OpenCV的CUDA版本进行计算相比CPU会快很多,但是经过我对上面CPU和CUDA版本的运行时间的测试,发现最终处理的时间是差不多的,我分析这个原因是在使用CUDA版本时,需要将cpu上的图片使用upload方法从内存传递到显存中,计算完成还需要将最终的结果图片通过download方法从显存传递到内存中,如果图片比较大,这种HostToDevice和DeviceToHost是比较耗时的。

Vue3添加高德地图、Vue3添加省市区三级联动

目录 1.进入高德地图官网 官网地址:高德开放平台 | 高德地图API 2.到这步直接运行代码 3.注意写入你的key 4.注意更改你所需的初始化地图中心位置 1-1 Vue3添加省市区三级联动 1-1.1代码 1-1.2省市区都选择 1.进入高德地图官网 官网地址:高德开放平台 | 高德地图API # 安装地图命令 npm i @amap/amap-jsapi-loader --save 注册账号 - 认证 - 控制台 - 应用 -我的应用 -添加 key 2.到这步直接运行代码 <template> <div class="app-container"> <div style="background-color: #ffffff;"> <div id="container"></div> </div> </div> </template> <script setup> import AMapLoader from '@amap/amap-jsapi-loader'; /*在Vue3中使用时,需要引入Vue3中的shallowRef方法(使用shallowRef进行非深度监听, 因为在Vue3中所使用的Proxy拦截操作会改变JSAPI原生对象,所以此处需要区别Vue2使用方式对地图对象进行非深度监听, 否则会出现问题,建议JSAPI相关对象采用非响应式的普通对象来存储)*/ import { shallowRef } from '@vue/reactivity'; import {ref} from "vue"; // const map = shallowRef(null); const path = ref([]); const current_position = ref([]); function initMap() { window.

IMX6ULL-Linux6.3.5版本网卡调试深入讲解

目录 一、先来了解一下imx6ull的网络节点的如何定义的 二、使用默认网卡配置 三、查找eth1对应FEC1复位失败原因 1.修改smsc_phy_reset函数 2.ENET1和ENET2的TX_CLK引脚复位寄存器的SION位为1 3.读取phy寄存器 4.使用正点原子给的内核和设备树文件 5.使用linux-5.19版本测试 6.上NXP论坛查资料 接着上一章移植Linux 6.3.5系统到imx6ull开发板 ,现在我们来讲解一下Linux下网卡调试 一、先来了解一下imx6ull的网络节点的如何定义的 首先找到 imx6ull 开发板设备树文件 imx6ull-toto.dts,打开文件内容如下: #include "imx6ull.dtsi" #include "imx6ul-14x14-evk.dtsi" / { model = "Freescale i.MX6 UltraLiteLite 14x14 EVK Board"; compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull"; }; &clks { assigned-clocks = <&clks IMX6UL_CLK_PLL3_PFD2>; assigned-clock-rates = <320000000>; }; 从上面可以看出,包含两个.dtsi文件,下面我就从这两个dtsi文件中找到fec节点的定义。 最终在imx6ul.dtsi文件找到关于fec节点的定义,如下: fec1: ethernet@2188000 { compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec"; reg = <0x02188000 0x4000>; interrupt-names = "int0", "pps"; interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6UL_CLK_ENET>, <&clks IMX6UL_CLK_ENET_AHB>, <&clks IMX6UL_CLK_ENET_PTP>, <&clks IMX6UL_CLK_ENET_REF>, <&clks IMX6UL_CLK_ENET_REF>; clock-names = "

java.lang.IllegalArgumentException: object is not an instance of declaring class] with root cause

java.lang.IllegalArgumentException: object is not an instance of declaring class] with root cause 问题描述报错详情解决方法 问题描述 微服务调用时,传入的参数为List类型;经过调试,当传入list.size()小于7时,可以正常调用,大于等于7时,服务调用失败,报错显示object is not an instance of declaring class。 报错详情 09:34:13.628 [http-nio-9205-exec-3] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - [log,175] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: object is not an instance of declaring class] with root cause java.lang.IllegalArgumentException: object is not an instance of declaring class at sun.

Python中的移动应用开发库有哪些?

Python中常用的移动应用开发库有以下几个: Kivy:Kivy是一个开源的Python库,用于快速开发跨平台的移动应用程序。它提供了丰富的UI组件和事件处理功能,支持Android、iOS、Windows、Mac等多个平台。 BeeWare:BeeWare是一个开源项目,旨在提供一套工具和库,帮助开发者使用Python构建原生移动应用。它支持Android、iOS、Windows、Mac等多个平台,并提供了各种UI组件和设备接口。 PySide:PySide是Python绑定Qt框架的一部分,可以用于创建移动应用程序。它提供了丰富的UI组件和功能,支持多个平台,如Android、iOS、Windows、Mac等。 Pygame:Pygame是一个开源的Python库,主要用于游戏开发,但也可以用于创建简单的移动应用。它为开发者提供了图形渲染、音频、输入事件等功能。 Flask、Django和FastAPI:这些库都是用于创建Web应用程序的框架,可以与移动应用的后端进行交互。通过API接口,移动应用可以与服务器进行数据交换和功能调用。 请注意,尽管Python提供了这些库来支持移动应用开发,但相对于专门的移动开发语言(如Java、Swift或Kotlin),Python在移动应用开发领域的应用相对较少。因此,如果你需要开发复杂的、性能要求较高的移动应用,可能需要考虑使用其他语言和框架。

【前端笔记】HTML 纯文件 整理 使用 Vue3 + element-plus + 字节cdn

HTML 纯文件 整理 使用 Vue3 + element-plus + 字节cdn 收藏下,方便用的到时,来此复制下. 本来打算尝试 做成 组件版的,但是 尝试了几种方案都没成功,有知道如何做的,有空帮忙评论区里告知下,谢谢. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>HTML 纯文件 整理 使用 Vue3 + element-plus + 字节cdn </title> <link href="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-plus/2.0.4/index.min.css" type="text/css" rel="stylesheet" /> <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/3.2.31/vue.global.min.js" type="application/javascript"></script> <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-plus/2.0.4/index.full.min.js" type="application/javascript"></script> <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/element-plus/2.0.4/locale/zh-cn.min.js" type="application/javascript"></script> <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript"></script> <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/qs/6.10.3/qs.min.js" type="application/javascript"></script> <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/echarts/5.3.0/echarts.min.js" type="application/javascript"></script> </head> <style> .flex-grow { flex-grow: 1; } </style> <body> <div id="app"> <div> <el-menu :default-active="

MQTT QoS 0,1,2 的介绍

原文地址:https://dev.to/emqx/introduction-to-mqtt-qos-0-1-2-oba 什么是QoS? 在不稳定的网络环境中,建立MQTT协议连接的设备仅靠TCP传输协议来保证通信的可靠性是很困难的事情。为了解决这个问题,MQTT协议引入了服务质量(Quality of Service,QoS)的机制来提供多种消息交互方式以提供不同级别的服务,满足用户在不同场景下对消息送达可靠性的特殊要求。 在MQTT中有3种QoS级别: QoS 0,最多一次QoS 1,至少一次QoS 2,仅且只有一次 以上QoS数值和消息发送的可靠性相匹配,值越大通信可靠性越强。QoS 0可能会丢失消息,QoS 1能保证消息送达但有机率重复收到消息,QoS 2能保证消息正确送达且不会重复。随着QoS级别的提高,消息送达的可靠性也在增强,但与此同时传输过程也变的越来越复杂。 在发布者向订阅者发送消息的过程中,发布者可以在PUBLISH包中指定消息的QoS级别。一般情况下Broker向订阅者转发消息的时候会使用发布者指定的QoS级别,不过某些情况下订阅者也会把收到的消息降级。 例如,如果订阅者指定了只接收QoS等级为1或0的消息那么Broker会把所有QoS2的消息降级为QoS1然后再转发给订阅者。QoS 1或QoS 0的消息会使用原有指定的等级转发给订阅者,不做改变。 我们来看一下QoS是如何工作的? QoS 0 - 最多一次 QoS 0 是服务质量中的最低级,也被称为“发出即忘记”。该级别下发布者不会等待消息确认接收或发送失败的时候进行重传,所以订阅者无需担心收到重复的消息。 为什么QoS 0会丢消息? QoS 0 级别的消息的可靠性取决于TCP连接的稳定性,如果连接稳定,TCP可以保证消息的成功发送,而如果连接被关闭或重置了,那么消息在传输过程中或在操作系统缓存中就会有丢失的风险,从而导致消息发送失败。 QoS 1 - 至少一次 为了保证消息的成功发送,QoS 1 引入了消息接收确认和重传的机制。当发布者准备向订阅者发送消息的时候,发布者首先会把PUBLISH包保存下来,发布者发送后若从订阅者接收到一个PUBACK包则视为消息已经接收成功,若未收到PUBACK包则会用已经保存的PUBLISH包进行重传。发布者利用PacketID唯一标识PUBLISH包和PUBACK包,确认发布成功后会从缓存中删除之前保存的记录。 为什么QoS 1会导致收到重复的消息? 有两种情况发布者无法收到PUBACK包: PUBLISH包未到达接收者。PUBLISH包已经送达接收者但接收者发出的PUBACK包未送达发送者。 在第一种情况下发布者会进行消息重传,订阅者只收到一条消息。 在第二种情况下发布者也会进行消息重传,而且订阅者会再次收到消息,从而导致重复接收同一条消息。 即使在重传的PUBLISH包中DUP标记被置为1以标识它是一条重传的消息,订阅者也不能把该消息视为重复消息来处理,而是必须视为一条新的消息。 这是因为订阅者在接收到PUBLISH包DUP标记为1的消息时有两种情况: 在第一种情况中发布者由于没有收到PUBLISH包因此会进行重传,订阅者会收到两个有同样PacketID的消息,其中第二个消息中DUP标记为1,该情况下第二次接收到的消息确实是重复的消息。 在第二种情况下,发布者先成功的向订阅者发送了一条消息,成功发送后该消息的PacketID会释放,用于一条新的、不相关的消息,此时新消息又再次使用1024这个PacketID,很不巧发送失败了,需要再次重传。最终重传的消息PUBLISH包中有同样的PacketID而且DUP被标识为了1,但它确实是一条新消息。 因此订阅者无法区分以上两种情况,必须把所有的消息都视为新消息,不能靠DUP标记进行区分。这也就意味着使用QoS 1的时候必定存在收到重复消息的可能性。 甚至在某些极端情况下,Broker在向订阅者转发消息的期间也会重复收到来自发布者的消息,而且会再次进行重传,这会导致订阅者额外收到一条重复的消息。 例如,发布者只发出了一条消息,但订阅者最终收到三条相同的消息。 以上就是使用QoS 1的缺点。 QoS 2 - 仅且只有一次 和QoS 0和QoS 2不同,QoS 2 能保证发出的消息既不丢失又不重复,然而它的通信交互最复杂、额外消耗也最高,因为发布者到订阅者的每条消息至少需要两对请求和响应流。 准备发送QoS 2消息的时候,发布者先保存消息再发送,然后等待接收来自于订阅者的PUBREC响应。这个过程和QoS 1很像,只是QoS 2等待的是PUBREC响应而不是PUBACK响应。当收到PUBREC响应的时候发布者可以确认订阅者已经接收到消息,可以删除本地的缓存,后续也将不会再重传该消息了。接着发布者会发一个PUBREL包通知订阅者准备释放刚才发送成功消息的PackID。和PUBLISH包一样,PUBREL包也需要可靠的发送给订阅者,所以PUBREL包也需要先储存用于失败时重传,另外PUBREL包发出后需要等待响应包。当订阅者收到PUBREL后它可以确认已经收到的PUBLISH包在该当前事务中不会再重传,订阅者会响应一个PUBCOMP包告诉发布者它已经准备好在新的消息中再次使用当前消息同样的PackID。 当发布者接收到PUBCOMP包后QoS 2的消息发送流程也就结束了。发布者可以将当前的PackID用于新的消息上,订阅者也同样会把它视为新消息处理。 为什么QoS 2消息不会重复接收? QoS 2用于保证消息不会丢失的机制和QoS 1一样,因此我们不再重复叙述。

Electron+Vue3开发桌面文件加密工具应用

成果展示: 一、Electron+Vue3项目搭建步骤 1、查看node版本,版本必须16及以上版本;查看是否安装npm cmd => node -v 2、切换镜像 yarn config set registry https://registry.yarnpkg.com 或 npm config set registry https://registry.npmjs.org 3、安装Vue脚手架,若已安装则可以跳过,未安装可用如下方式安装 npm install -g @vue/cli # OR yarn global add @vue/cli 4、创建项目 项目名,可自己定义 vue create myproject 选择Vue3版本 如图,安装完成,我这边安装的yarn,所以vue默认用yarn作包管理了, cd myproject 切换到 myproject目录下,yarn serve即可启动Vue3项目。 如果你使用的npm或cnpm,使用npm run serve 运行即可。 5、配置Electron 首先进入项目目录:cd myproject 然后通过运行以下命令安装并调用vue-cli-plugin-electron-builder的生成器: vue add electron-builder 如下图所示,提示我们选择Electron版本,直接选择最新13.0.0版本即可 。 如下图,则项目创建成功。 6、项目启动 使用yarn(推荐使用yarn),则直接执行: yarn electron:serve 或者使用npm,则直接执行 npm run electron:serve 7、打包 使用yarn(推荐使用yarn),则直接执行: yarn electron:build 或者使用npm,则直接执行 npm run electron:build 桌面应用配置,在vue.

数学 {罗尔中值定理}

数学 {罗尔中值定理} 罗尔中值定理 定义 条件: 函数满足 C [ a , b ] C[a,b] C[a,b], D ( a , b ) D(a,b) D(a,b), f ( a ) = f ( b ) f(a) = f(b) f(a)=f(b); 结论: ∃ ξ ∈ ( a , b ) , f ′ ( ξ ) = 0 \exist \xi \in (a,b), f'(\xi) = 0 ∃ξ∈(a,b),f′(ξ)=0; @DELI; #证明# 由极值定理, 函数在 [ a , b ] [a,b] [a,b]上一定取到最大值 M A MA MA与最小值 M I MI MI;

Vue路由守卫详解

路由守卫 什么是路由守卫全局前置守卫路由独享的守卫组件内的守卫 举例说明 什么是路由守卫 路由守卫是Vue Router提供的一种机制,用于在导航过程中对路由进行控制和管理。通过使用路由守卫,你可以在路由切换前、切换后以及错误处理时执行相应的逻辑。 Vue Router提供了三种类型的路由守卫: 1、全局前置守卫 2、路由独享的守卫 3、组件内的守卫 全局前置守卫 全局前置守卫( router.beforeEach):这些守卫会在路由切换之前被调用,可以用来进行权限验证、登录状态检查等操作。常见的全局前置守卫有beforeEach。 语法 : router.beforeEach((to, from, next) => { // 在每次路由导航触发前执行的逻辑 }); 在router/index.js中的具体配置 // index.js import Vue from 'vue'; import VueRouter from 'vue-router'; Vue.use(VueRouter); const router = new VueRouter({ // 路由配置 routes: [ // ...定义路由... ] }); router.beforeEach((to, from, next) => { // 全局前置守卫逻辑 }); export default router; 在上述示例中,我们通过 router.beforeEach 方法注册了一个全局前置守卫。在每次路由导航之前,该守卫会被调用。守卫的回调函数接收三个参数: to:即将跳转的目标路由对象from:当前导航正要离开的路由对象next:用于控制导航行为的回调函数 在守卫的回调函数中,你可以根据业务需求执行相应的操作,如验证用户权限、检查登录状态、取消导航或重定向到其他路由。next 函数用于控制导航的继续或中断。 若要中断当前导航并取消跳转,可以调用 next(false)。若要重定向到其他路由,并且希望中断当前导航,可以调用 next('/other-route')。若无需中断导航,则调用 next() 允许导航继续。 全局前置守卫(Global before Guards)可以在以下场景中发挥作用:

React中 setStatez中数组和对象的修改方式?

一、为什么React中修改数组时不能使用数组的可变方法。 在React中使用setState修改数组的值时,不推荐使用数组的可变方法(如push、unshift等)。这是因为React会对比新旧状态,在发现状态变化后,更新组件的渲染。但当你调用可变方法修改数组时,虽然数组已经被改变,但数组的地址并没有发生变化,React并不会察觉到这个变化,也就不会更新组件。 二、我们可以使用以下几种方法。 (1)对数组进行修改 // 1、修改object中某项 this.setState({ object: {...object, key: value} }); // 2、删除数组首位 array.splice(0, 1); this.setState({ array }); // 3、删除数组尾部 array.splice(array.length - 1); this.setState({ array }); // 4、删除数组任意一项 array.splice(index, 1); this.setState({ array }); // 5、数组尾部添加一项 this.setState({ array: [...array, item] }); // 6、数组头部添加一项 this.setState({ array: [item, ...array] }); 7、数组任意位置添加一项 array.splice(index, 0, item); this.setState({ array }); // 8、修改数组中任意一项中值 function updateArrayItem(index, key, value) { this.setState({ array: array.map((item, _index) => _index == index ?

K8S的概念和基本应用

学习视频:Kubernetes基本概念和应用_哔哩哔哩_bilibili 零 . 架构概览 master节点:管理调度集群资源,一般为多节点构成,可以是物理机,也可以是虚拟机。worker节点:资源的提供者,一般为多节点构成,可以是物理机,也可以是虚拟机。pod:绿色部分,相当于云平台的虚拟机容器container:cpu和内存、资源的隔离单位,多节点部署,主容器+辅助容器。它共享pod的存储资源和网络栈。k8s平台:解决集群资源调度的问题,将空闲的pod合理的分配到worker节点上面去。监控集群,如有节点或pod挂了,重新协调和启动pod,保证应用高可用,称为治愈。保证集群的网络,保证pod服务之间可以互通互联。 master节点组件构成 master节点:k8s集群的大脑,分布式数据库etcd,k8s集群集中的状态存储:节点,pod,发布,配置等都存储在里面。高可用部署的话,至少需要部署3个节点。所有的操作都是通过调用apiserver来实现的,可以认为是etcd的代理。scheduler:负责调度决策的组件,比如:pod应该分配到那些worker里面去。controller manager:保证集群状态最终一致的组件。通过apiserver 监控集群的状态,确保实际状态与预期状态一致。 worker节点组件构成 kubelet :worker节点的资源管理者,相当于agent角色。监听apiserver的事件,执行master下发的任务,汇报情况给APIserver等,是worker节点的小脑。container runtime:结点容器资源的管理者。kubelet不直接参与动作,而是委托给container runtime。比如:启动或关闭容器,收集容器状态。在启动容器的时候,如果本地没有镜像缓存,会从docker hub 去拉取相应的镜像,缓存到本地。kube-proxy:管理k8s中的服务网络的(servernetwork),当需要把服务暴露给外网的时候,需要kube-proxy代理作为转发。pod:瞬息的,不固定的,ip可能会变(可变+不可变)。 K8S发布pod流程样例 流程解读如下: 1、使用kubectl命令行工具向apiserver发送一个创建一个新的replicaset 的请求。apiserver会将该资源请求先存储到etcd中。 2、controller manager 监听replicaset的 创建或修改相关的事件。接收到上一步的创建pod的一个通知。 3、controller manager比较当前集群状态和预期集群的状态,当发现不一致时,调用第一步中的创建pod的模板,在apiserver中创建预期的pod。 4、scheduler监听到apiserver创建新pod的请求,运行调度算法,选择空闲的work节点。然后通过apiserver更新创建pod的定义。把这些pod指定到具体要发布到哪些work节点上。、 注意,此时:controller manager、scheduler 只是通过apiserver更新了希望创建的集群状态,pod并没有真正创建。 5、一旦pod被分配到某个worker节点,apiserver就会通知相应节点上面的kubelet,kubelet接到通知以后,就会指示他的节点上的container runtime 去运行对应的容器。 6、container runtime就会开始下载镜像,启动容器。同时kubelet开始监控容器的运行。 K8S总体架构 小结各个组件的作用 虚拟机抽象-pod 容器 = 应用 + 操作系统,是一种资源隔离抽象;pod 是容器的包装,是一种虚拟机抽象;k8s 是管理pod虚拟机的数据中心抽象; https://kubernetes.io/docs/concepts/workloads/pods/pod/ 一般是一个pod对应一个容器,但也有一对多的情况,一个主,一个辅助。 https://hub.docker.com/r/spring2go/spring-petclinic/tags 发布pod:按照要求书写发布规范。 Pod | Kubernetes 如何访问pod? 针对测试环境: 端口转发功能开启外部访问: kubectl port-forword petclinic 8080:8080 (主机端口:pod端口) nodeport service 传统数据中心反向代理原理 通过在数据中心的网络边界部署反向代理(proxy service)将内网资源暴露出去,使得公网可访问。 反向代理2大作用: 反向路由 + 负载均衡

华为开发者大会2023(Cloud)之旅

【摘要】 金鱼哥畅游记:华为开发者大会2023(Cloud) 2023年7月7日华为开发者大会2023(Cloud)在广东东莞正式揭开帷幕,金鱼哥很庆幸能有机会参加此次盛大聚会,看到众开发者共聚一堂,在新产业和技术新实践下擦出不一样的火花。 文章目录 报名与到场互动展区展区A展区B展区C展区D 高峰论坛/专题论坛训练营和挑战赛扫地僧见面会集齐印章召唤“神龙”鱼过留痕后记附官方美图地址: 报名与到场 早在6月14日,金鱼哥就收到官方的邮件,知道大会将在7月7日-9日在东莞举行,而在广州的金鱼哥离东莞会场不用2小时的车程,真的是一个天赐的机会,又怎能错过这个机会呢? 由于金鱼哥7月7日还在项目组进行工作,因此错过了主题演讲,但周末两天举行的高峰论坛/专题论坛和各种展区的展示和讲解肯定能弥补这个损失。7月8日一早,金鱼哥按着参会指引来到华为溪流背坡村F区6号门会场进行签到并领取我的专属胸卡。 在签到处到进入会场前就看到各种指引和会场的介绍,还有很多工作人员为我们进行答疑,他们的活力和耐心真的是大会又一道风景。遥想第一天的时候,金鱼哥并不熟悉会场,也不熟悉各项活动的情况,但只要看到会场工作人员就可以进行咨询,她们都会耐心指引和解答,而且工作人员遍布各处,能抗住“并发”。 互动展区 展区A 大会总共有4个展区,每个展区都有不同技术产品或者方案的展示,以下为参会指南里的指引: 从签到处一路走进会场,看到的就是A展区,而展区门口就是华为云盘古大模型,展示着各种模型下的产品,其中金鱼哥对那个自动拍照机器人很感兴趣,突然在想,日后是不是摄影师职业也会面临淘汰呢? A展区会场中央有着开放式主题演讲,不同时段有不同的主题,刚进会场就遇到了主题《携手华为云aPaaS开启企业数字化应用智能时代》的开讲,马上“搬凳子”感受一下现今数字化的发展趋势。 金鱼哥工作在运维领域,因此当然先去与自己工作领域相关的主题去"调侃"😁,两天下来,实行“有杀错,不放过”😎,能调侃的,都去调侃,能加群的,都去加群,首先要进入该技术领域的圈子,找到组织才可以有更好的后续😂。 展区B 展区B在华为云生态解决方案联创中心里面,当时第一天去的时候,不知道这个是一个展区,看到方案中心顿感高大上,就马上进去溜达了😂。 金鱼哥在展区B呆的时间也是很长的,因为里面有很多在用的产品,也有未曾关注过的服务和解决方案,真的眼前一亮。 来到华为云开源展示位置,真的再次感受到华为云开源的强大,众多开源的产品已经在各行各业得到运用。金鱼哥前段时间在写有关Kuasar的文章,在感受开源产品强大的同时,也看出华为云在不断汇聚开源力量,这样能吸引众多开源组织,也能进行适配。 展区B进门处,还可以看到有趣的展示,而且那是个人开发者都可以玩的东西: 然而,金鱼哥看到这个的时候,我是对那个机器手臂的各个部件感兴趣,而不是那主机😂,因为金鱼哥改行前所从事的行业是机械设计🤣,真的很怀念。 展区C 展区C和D都在H区里面,分别在H区馆的1楼和2楼。专题论坛就在展区楼层的各个房间。 一走进展区,同样是人山人海,都在各自感兴趣的展示摊位中进行咨询和了解。 金鱼哥也不例外,都是会先从自己工作领域去关注,然后有时间再去关注其余产品情况。 金鱼哥在展区C可是逗留了很久,也和各个摊位老师进行了不少交流,了解到不少华为云技术的发展历程和现状,获益匪浅。也在一些摊位中了解到一些自己未曾接触过的技术产品,例如Workspace,可直接将需要用的应用封装到镜像中,我们可以直接拉取自定义镜像来下发ECS进行使用。时代真的在不断发展,不去关注真的很多东西都不知道,能在大会中看到各种介绍,真的是一次开眼界的机会。 展区D 在展区D,金鱼哥聊得最久,也最好奇的,就是这个开发者圈层摊位,了解到又一开发者圈子的情况,而且还见到了专家小助手真人😁。因为金鱼哥是在博客社区,因此是和华为云博客小助手沟通和交流,未曾涉及到专家圈子层,来到这里,发现了这个新大陆,还拍了一张专家小助手的相片,不过就不发出来了😎。 突然在想,金鱼哥是否也可以申请加入专家计划呢?虽然自问未到专家的程度,但也在运维领域深耕了一定年限,也混过不少项目,也有有一定的经验,但自问离专家的程度还有一段距离,不过,以此为目标,继续在自己擅长的领域里深耕,相信也能走出一条不一样的道路。 高峰论坛/专题论坛 高峰论坛在J区,专题论坛在H区,涉及的主题和内容都非常丰富,每个时间段都有不同主题的老师在进行演讲和介绍,因此所有主题都进行参与是不可能的了,所以只能挑选自己感兴趣的来,错过了的就等大会后续的回访视频。第一天金鱼哥就找工作人员拍下了整个时间段的论坛分布,这样能更好的进行规划。 去参与专题论坛可以感受到现场的氛围,有些专题真的是爆满的,例如云原生专题领域,如果不提前进场,就只能像金鱼哥那样,站在最后的区域感受现场了😂。 拍了很多照片,就不一一都展示了,后面在交流群还发现了官方的图片公众号,之后会在文末提及。 最后,上传一张美女老师讲课的照片😎。 训练营和挑战赛 有两个地方,对于运维领域的金鱼哥是没有进去的,那就是CodeLabs训练营和极客挑战赛,因为要去coding的,现阶段的金鱼哥没开发语言基础,所以只能止步于场馆外了。感兴趣的小伙伴,日后可以参与看看,这个需要在网页里进行预约参加的。据说还有礼品之类😍。 扫地僧见面会 一看名字,就想起《天龙八部》中武功最厉害的那人物,就是少林寺那位深不可测的扫地僧,他功力深厚,身怀十八般绝技。所以能用上这名号的,一定是各领域顶尖且优秀的技术专家。可惜的是,这个当金鱼哥去到现场时,才发现,这是需要预约的,而且早已经预约满了,所以错过了该环节,只能在展厅外围感受一下。 如果能早点知道是这样性质的话,肯定会去预约一个位置,因为与“扫地僧”面对面交流,真的是一个很难得的机会,无论是解答技术实践、能力提升、还是职业生涯发展等等疑惑都可以进行咨询,这样的思维碰撞不是看分享文章所能比拟的。 此处附官方图片: 如果有下次此类活动,看到金鱼哥此篇文章的小伙伴,记得提前就去“霸”个好位置,快进行预约。这个真的是手快有,手慢就没的了😂。 集齐印章召唤“神龙” 金鱼哥第一天不知道场馆配备设施,所以一早就用保温杯冲好菊花茶,但后面进到会场才发现,矿泉水、可乐、雪碧、芬达管够,因此第二天的金鱼哥就轻装出门😁还有很多区域都放上冰块来加料😉。中午时分还可以凭餐券在4家餐厅选择自己喜欢吃的饭菜,还有水果和饮料提供,能量满满。 第一天刚进会场的时候,看到很多人在咨询台那里盖章,那刻才发现原来会场还有云游打卡,只要参加论坛、问答互动、会场签到都可以盖印章😁,然后集满一定数量的印章就可以兑换特定的奖品。金鱼哥了解到规则和体验过后,除了参加各种论坛和参观展厅外,就是要集满印章去召唤奖品😁。 虽然两天都集满印章,但金鱼哥两天都与华为手机没缘分😂,眼睁睁的看着别人带走😂。 虽然与华为手机无缘,但还是收获了4杯好喝的咖啡、1个富光水杯和1个倍思插板,还有在问答环节中收获了一张Workspace的超长鼠标垫😉。弱弱说一句,三个奖品都已经在用,很实用的奖品😁。 鱼过留痕 华为溪流背坡村真的是很美的地方,只可惜金鱼哥醉翁之意不在酒,心思都在各种技术交流上😂。中途见到很多情侣在各种拍照,留下美好的回忆。金鱼哥没拍几张风景照片,拍照技术也堪忧🤣,但可从官方图片的公众号里进行欣赏,先放几张图片看看,例如我们各区之间穿梭的小火车,各区的美景,还有第一天晚上的音乐嘉年华,金鱼哥是当天来回,所以错过了嘉年华,也只能从图片中去欣赏。 既然来到如此美景,在大会中也收获满满,必须要和云宝留个合照,证明金鱼哥是来过的😁。 后记 时光荏苒,两天的华为开发者大会(HDC.Cloud)就这样结束了,然而在大会里学到的东西非常丰富,还需要后续的不断消化,还好在参会的过程中有加入相应的交流群,能让我们快速找到对应的圈子。 正所谓“取乎其上,得乎其中;取乎其中,得乎其下;取乎其下,则无所得矣”,志存高远,并为之努力奋斗,才会有可能登峰造极,而华为正是这样的企业,而我们开发者也可从大会中感受到这样的氛围。 未来的路上,金鱼哥虽然不知道自己能走多远,但无论怎样,未来可期,努力向前,让自己增值。 绳锯木断,水滴石穿,相信日复一日的努力,终会迎来厚积薄发的一天。 金鱼哥,加油! 附官方美图地址: F区美图:https://live.photoplus.cn/live/50172383?accessFrom=qrcode H区美图:https://live.photoplus.cn/live/97652805?accessFrom=qrcode#/list J区美图:https://live.photoplus.cn/live/11703122?accessFrom=qrcode#/list

数学 {驻点}

数学 {驻点} 驻点 Stationary point 定义 #驻点(稳定点) Stationary point 若 f ′ ( x 0 ) = 0 f'(x_0) = 0 f′(x0​)=0, 则称 x 0 x_0 x0​为函数 f f f的一个驻点; 错误 驻点 不一定是 极值点; x 3 x^3 x3在 x = 0 x=0 x=0处 导数为0, 因此为驻点, 但不是极值; 极值点 不一定是 驻点; ∣ x ∣ |x| ∣x∣在 x = 0 x=0 x=0是极值, 但不可导;

科研绘图中的图片格式问题

本文分析了所有主流图片格式的优缺点。 科研绘图中的图片格式问题 科研论文投稿需要根据期刊的要求上传符合要求的图片,以下为科研绘图中相关格式问题汇总。 1 位图和矢量图的区别 位图(Bitmap) 又称栅格图(Raster graphics)或点阵图,是使用像素阵列(Pixel-array/Dot-matrix点阵)来表示的图像。位图是由一个一个像素点产生,当放大图像时,像素点也放大了,但每个像素点表示的颜色是单一的,所以在位图放大后就会出现马赛克状。处理位图时,输出图像的质量决定于处理过程开始时设置的分辨率高低。简而言之,位图是由小的色块组成,不能支持无限放大。因此分辨率就是需要考虑的一个问题了。 位图的文件类型很多,如*.bmp、*.pcx、*.gif、*.jpg、*.tif、*photoshop的*.psd等。 矢量图(Vetorgram) 也称为面向对象的图像或绘图图像,在数学上定义为一系列由线连接的点。矢量文件中的图形元素称为对象。每个对象都是一个自成一体的实体,它具有颜色、形状、轮廓、大小和屏幕位置等属性。矢量图是根据几何特性来绘制图形,矢量可以是一个点或一条线,矢量图只能靠软件生成。 矢量图文件容量较小,却可以缩放到任意大小和以任意分辨率在输出设备上打印出来。缺点是难以表现色彩层次丰富的逼真图像效果。 矢量图形格式也很多,如Adobe illustrator的*.ai、*.eps和*.svg、Auto CAD的*.dwg和*.dxf、Corel DRAW的*.cdr等。 位图和矢量图的区别:位图和矢量图之间的显示效果不同,原理不同,绘制工具也不同。 显示效果不同:位图放大后会有边缘模糊、失真现象。矢量图与分辨率无关,可以将它缩放到任意大小和以任意分辨率在输出设备上打印出来,都不会影响清晰度;原理不同:位图是一张图片原始大小的矩形区域,各种颜色的像素组成的像素点阵。矢量图是用数学方程式表达形状、然后在所表达的形状区域内填充像素;绘制的工具不同:位图可以由许多摄影摄像、电子处理等设备制作产生。在PS软件中,绘制位图的工具通常是选区工具。矢量图多在AI、cdr、ps等软件处理图像的过程中,能存储的格式为EPS及图像处理软件的原文件。在PS软件中,绘制位图的工具是形状工具;占用空间不同:矢量图表现的图像颜色比较单一,所以所占用的空间会很小。位图表现的色彩比较丰富,所以占用的空间会很大,颜色信息越多,占用空间越大,图像越清晰,占用空间越大。 经过软件矢量图可以很轻松的转化为位图,而位图要想转换为矢量图必须经过复杂而庞大的数据处理,而且生成的矢量图质量也会有很大的出入。 2 图片格式 2.1 JPG/JPEG格式(位图) ​ JPEG是JPG的全名、正式扩展名。但因DOS、Windows 95等早期系统采用的8.3命名规则只支持最长3字符的扩展名,为了兼容采用了.jpg。JPEG格式,缺点保存后图片失真比较大,存储的图像会丢失一部分细节,优点是它的压缩率是相当高的。JPEG是一种压缩比比较大的图片格式,图片以JPEG格式保存以后,会损失掉不少图片信息,但其好处就是图片体积小,放在电脑里,可以占用较小的空间,在网上传播,速度比较快,所以,JPEG和GIF又称为WEB格式。 优点: 它支持极高的压缩率,因此JPEG图像的下载速度大大加快;它能够轻松地处理16.8M颜色,可以很好地再现全彩色的图像;在对图像的压缩处理过程中,该图像格式可以允许自由地在最小文件尺寸(最低图像质量)和最大文件尺寸(最高图像质量)之间选择;该格式的文件尺寸相对较小,下载速度快,有利于在带宽并不“富裕”的情况下传输。 缺点: 并非所有的浏览器都支持将各种JPEG图像插入网页;压缩时,可能使图像的质量受到损失,因此不适宜用该格式来显示高清晰度的图像。 使用场景:JPEG格式的压缩率是目前各种图像文件格式中最高的。它用有损压缩的方式去除图像的冗余数据,但存在着一定的失真。由于其高效的压缩效率和标准化要求,目前已广泛用于彩色传真、静止图像、电话会议、印刷及新闻图片的传送。由于各种浏览器都支持JPEG这种图像格式,因此它也被广泛用于图像预览和制作HTM网页。 2.2 PNG格式(位图) ​ “可移植网络图形格式“,是图像文件存储格式,其设计目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。对于图片本身质量的减损非常低。因其能够支持压缩不失真、透明背景、渐变图像的制作要求,PNG格式也是各大制图软件例如PS、InDesign输出或编辑的原始格式。PNG文件非常适合在互联网上使用。但它也不足以用作专业印刷。优点:能够相容半透明 / 透明图像,缺点:档案比 JPEG 大,不能用于印刷PNG。 ​ PNG格式有8位、24位、32位三种形式,其中8位PNG支持两种不同的透明形式(索引透明和alpha透明),24位PNG不支持透明,32位PNG在24位基础上增加了8位透明通道,因此可展现256级透明程度。PNG8和PNG24后面的数字则是代表这种PNG格式最多可以索引和存储的颜色值。8代表2的8次方也就是256色,而24则代表2的24次方大概有1600多万色。 优点: 体积小:网络通讯中因受带宽制约,在保证图片清晰、逼真的前提下,网页中不可能大范围的使用文件较大的bmp格式文件;无损压缩:PNG文件采用LZ77算法的派生算法进行压缩,其结果是获得高的压缩比,不损失数据。它利用特殊的编码方法标记重复出现的数据,因而对图像的颜色没有影响,也不可能产生颜色的损失,这样就可以重复保存而不降低图像质量;索引彩色模式:PNG-8格式与GIF图像类似,同样采用8位调色板将RGB彩色图像转换为索引彩色图像。图像中保存的不再是各个像素的彩色信息,而是从图像中挑选出来的具有代表性的颜色编号,每一编号对应一种颜色,图像的数据量也因此减少,这对彩色图像的传播非常有利。更优化的网络传输显示 PNG图像在浏览器上采用流式浏览,即使经过交错处理的图像会在完全下载之前提供浏览者一个基本的图像内容,然后再逐渐清晰起来。它允许连续读出和写入图像数据,这个特性很适合于在通信过程中显示和生成图像;支持透明效果:PNG可以为原图像定义256个透明层次,使得彩色图像的边缘能与任何背景平滑地融合,从而彻底地消除锯齿边缘。这种功能是GIF和JPEG没有的。PNG同时还支持真彩和灰度级图像的Alpha通道透明度;其他:最高支持24位真彩色图像以及8位灰度图像。支持Alpha通道的透明/半透明特性。支持图像亮度的Gamma校准信息。支持存储附加文本信息,以保留图像名称、作者、版权、创作时间、注释等信息。 缺点: 较旧的浏览器和程序可能不支持PNG文件。作为Internet文件格式;与JPEG的有损耗压缩相比,PNG提供的压缩量较少;作为Internet文件格式,PNG对多图像文件或动画文件不提供任何支持。GIF格式支持多图像文件和动画文件; 使用场景:PNG的开发目标是改善并取代GIF作为适合网络传输的格式而不需专利许可,所以被广泛应用于互联网及其他方面上。 格式对比: PNG与 GIF 1、一般情况下将静态GIF图像无损转换为PNG后可以压缩率会略为提高(前提是同样采用8位索引模式); 2、PNG可提供更大颜色深度的支持,包括24位(8位3通道)和48位(16位3通道)真彩色。加入α通道后可进一步支持每像素64位的表示; 3、超过8位色深的PNG图像转换为GIF时,图像质量会由于分色(颜色数减少)而下降; 4、GIF原生支持动态图像,PNG只能通过非标准实现,在PNG的基础上另有发展出支持动画的APNG和MNG格式,但普及度不高。PNG在IE6等旧浏览器上的支持较差。 PNG 与JPEG 1、JPEG可以对照片(或类似)图像生成更小的文件,这是由于JPEG采用了一种针对照片图像的特定有损编码方法,这种编码适用于低对比,图像颜色过渡平滑,噪声多,且结构不规则的情况下。如果在这种情况下用PNG代替JPEG,文件尺寸增大很多,而图像质量的提高有限。相应的,如果保存文本,线条或类似的边缘清晰,有大块相同颜色区域的图像,PNG格式的压缩效果就要比JPEG好很多,并且不会出现JPEG那样的高对比度区域的图像有损。如果图像既有清晰边缘,又有照片图像的特点,就在在这两种格式之间权衡一下了。JPEG不支持透明度; 2、由于JPEG是有损压缩,会产生迭代有损,在重复压缩和解码的过程中会不断丢失信息使图像质量下降。由于PNG是无损的,保存将要被编辑的图像来说更加合适。虽然PNG压缩照片图像也有效,但有专门针对照片图像设计的无损压缩格式,比如无损JPEG2000,Adobe DNG等。总的来说这些格式都不能做到适用所有图像。对于将要发布的图像可以保存成JPEG,用JPEG编码一次不会造成明显的图像有损。 PNG vs JPEG-LS JPEG-LS是一个“几乎”无损压缩格式,相对于上面提到的有损JPEG压缩,它的知名度不高。它可以直接和PNG相比较,使用一组标准的测试图像。在Waterloo Repertoire ColorSet(一组标准测试图像)下,JPEG-LS通常表现要比PNG好10%-15%,但其中有一些图像PNG表现明显更好一些,大约50%-75%。所以,如果这两种格式都支持而且对图像文件大小很敏感的话,可以用这两种格式都试试,和图像数据本身有比较大关系。 PNG与TIFF 1、TIFF是一个相当多方案结合的格式。它被广泛用作专业图像编辑软件之间图像交换的中间格式,因此它不断支持更多应用程序所需的功能,而对应用程序不关心的图像操作部分支持不多。这也意味着许多应用程序只能识别TIFF的一个子集,而产生更多的潜在混淆之处; 2、TIFF使用的最通用的无损压缩算法是LZW。这种算法–GIF中也在使用,直到2003年一直在专利保护之中。有一种TIFF变种使用与PNG相同的压缩算法,但是没有被许多专利程序所支持。TIFF也提供了一种特殊的无损压缩算法,类似CCITTGroup IV,可以对二值图像(比如传真或黑白文本)比PNG有更好的压缩效果。 PNG只支持非自左乘α,而TIFF也支持联合(自左乘)α。PNG规范中不包含嵌入式EXIF(可交换图像文件格式)图像数据的标准,比如数码像机拍得的图像。而TIFF,JPEG 2000, DNG都支持EXIF;

踩坑!使用wifi后调用wx.miniProgram.postMessage失败

如果在连接 Wi-Fi 后无法调用 wx.miniProgram.postMessage,可能是由于您的 Wi-Fi 阻止了跨域请求导致的。在这种情况下,您可以尝试在小程序的 app.json 文件中设置 setting 字段下的 crossDomainAccess 字段为 true,以允许小程序进行跨域请求。 { "pages": [ "pages/index/index", "pages/about/about" ], "window": { "navigationBarTitleText": "Demo" }, "setting": { "urlCheck": true, "es6": true, "postMessage": true, "webviewDomain": "wxapp.com", "crossDomainAccess": true // 添加这一行 } }

【UE5】动画系统

最近接触的项目涉及到动捕和动画,以前接触的范围主要是GamePlay以及C++和蓝图的交互,很少接触动画,借此机会学习一下UE5的动画系统。 首先把整个动画系统的框架了解一下。 参考博客:奶帆、骨架资源、骨架树、papalqi、郭袁、Stefan Perales 一、动画系统的框架 AimOffset BlendSpace AnimationMontage AnimationCompostie PhysicsAsset SkeletalMesh AnimationSequence Skeleton AnimationBlueprint AnimInstance PoseAsset ControlRig Animation State Machie 我们自上而下,从左往右看: 1.AimOffset AimOffset在UE4中的直译是目标偏移,用于对主体动画的混合叠加,多用于射击瞄准,如在吃鸡游戏中人物持枪瞄准时根据视角不同可以向上瞄准和对地瞄准和左右侧身瞄准。Epic不愧是做射击游戏起家的,AimOffset在UE中使用的图标都是一个人持枪的样子。 2.AnimationMotage AnimationMotage直译为动画蒙太奇,Motage在影视剪辑中是一种剪辑手法,通过将一系列视点不同的镜头组合起来的一种手法,感觉UE也是沿用这种解释,将不同而又有关联的多个动画组合起来构成一个完整的动画,这个完整的动画就是AnimationMotage。如一个攻击技能动画可以由拔刀动画+向上跳起动画+向目标砸下动画+收刀动画组成。这几个动画就可以由一个AnimationMotage组合在一起。AnimationMotage可以便于AnimationBlueprint更好的控制动画。 3.PhysicsAsset PhysicsAsset—物理资产,官方给的定义是 物理资产用于定义骨架网格体使用的物理和碰撞。它们包含一组刚体和约束,这些构成一个布偶,而布偶并不 局限于人形布偶。它们可以用于任何使用形体和约束的物理模拟。因为一个骨架网格体只允许一个物理资产, 所以可以为许多骨架网格体打开或关闭它们。 我们在打开动画相关的资产的时候一般都能看到物理资产。 4.BlendSpace BlendSpace—混合空间,BlendSpace是用于根据输入的float值在两个动画进行融合采样然后输出融合后的动画的工具,如两个动画一个是向前走一个是向左走,两个动画就可以通过输入的float值在混合空间进行混合,然后输出从前到左这个扇形方向任何一个方向运行的动画。 5.AnimationCompostie AnimationCompostie—动画合成,按照官方的解释就是 动画合成作为一种将多个动画组合在一起将它们作为单个单元进行处理的方法。在某些情况下,你可能会遇到这样的情况:你需要将多个动画序列拼接在一起,这样就可以将它们当作一个序列而不是多个序列来使用。这正是 动画合成 的目的。动画合成是一种动画资产,专门设计用于允许你将多个动画组合在一起以作为单个单元进行处理。但是,请注意合成只是追加动画;它不提供任何混合能力。 6.SkeletalMesh SkeletalMesh—骨骼模型,绑定了骨骼之后的网格体,也是角色实际应用mesh。 7.AnimationSequence AnimationSequence—动画序列,帧动画的一种,官方给的定义是 动画序列(AnimationSequence) 是一个可以在骨架网格体上播放的独立的动画资源。它们包含了一些关键帧,这些关键帧可以及时地指出某个特定点处的一个骨骼的位置、旋转度及缩放比例。通过回放序列中的这些关键帧,并在将它们互相混合,使得骨架网格体可以产生平滑的动画效果。 每个 动画序列 资源指向一个特定的骨架,且仅可以在那个骨架上进行播放。这意味着,为了在多个骨架网格物体间共享动画,所有网格物体都必须使用同样的骨架资源。 8.Skeleton Skeleton—骨骼,骨骼是整个动画的系统的基础,任何动画都要在骨骼的基础上进行创作,只要人物应用的骨骼保持一致,同一个动画就可以在不同的人物上应用。 官方定义是 如果您熟悉数字内容创建,那么对"骨架"的概念应该有所了解。 在多数3D应用程序中,骨架通常是一个数字层级架构,用于定义角色中的骨骼或关节,并以诸多方式模仿真实的生物骨架。 在虚幻引擎4中,一个重要的区别是骨架资源将 关联动画数据,而并非只是骨架网格体中的骨骼层级。 在UE4中,骨架资源将把骨骼(关节)数据关联到动画轨迹,从而驱动动画。 9.AnimationBlueprint AnimationBlueprint—动画蓝图,动画蓝图是UE专门用来控制动画的专用蓝图,用于将各种动画的混合,叠加,控制,更新以及状态等进行程序化控制,然后输出最终的动画到角色身上。 10.各个资产之间的关系 我们以一个发球动作为例。 可以把整个骨骼(Skeleton)是整个动画系统的基础,存储着一些最基础的数据,决定了一个角色可以做什么样的动作; 骨骼模型(SkeletalMesh)是依附于骨骼之上的血肉,决定角色动画的外型形象;物理资产(PhysicsAsset)是依附于骨骼之上的物理碰撞体,是动画之间物理碰撞; 动画序列(AnimationSequence)是一段一段的动作片段,如起步做东,冲刺动作,抬脚动作、踢出动作; 混合空间(BlendSpace)和目标偏移(AimOffset)都是为动作片段优化动作的,混合空间为各个动画片段添加变化,如踢出动作可以混合出偏内侧踢和偏外侧踢,目标偏移为指定动画增加优化动作,如起步动作的屈膝优化; 动画融合(AnimationCompostie)是对整体动作的优化,可以将一个一个的动画片段进行截取组合,组合成一个完整的新动作,如一个个动作片段可能会有一些多余的小动作,动画融合就可以把这些小动作清理掉并把截取出来的动作并接成一个简洁的动作,可以将整个发球动作融合成助跑和射球两个动画融合,也可以直接融合成一整个完整的发球动作; 动画蒙太奇(AniamtionMotage)则是对整个动画的整合控制,可以直接整合一个个的动画片段,也可以整合组合过的动画融合,让后对整个动画提供参数控制,相当于给骨骼肌肉发送动作指令的神经系统; 动画蓝图(AnimationBlueprint)为整个动画系统提供程序逻辑控制的能力,是整个动作控制的大脑,控制着动作的一举一动,当然在一个做动作的过程中动画蓝图不是必须,就如我们做一些动作是可以直接通过肌肉记忆做出动作而无需过大脑。 二、骨骼 骨骼存储着一些最基础的信息,如: 骨骼层级信息;参考姿势信息;骨骼的名称;插槽信息;曲线信息;动画通知信息;插槽数据;虚拟骨骼信息;骨骼映射表;重定位信息;各个骨骼之间的约束信息。 1.

手把手带你阅读chatgpt接口

我们大多数人使用chatgpt,一般是直接使用网页版本的gpt对话框。但是实际上,openai提供了chatgpt开放平台的调用方式,这个方式,反而是我们目前碰到的各种应用中,最常用的方式。 我们可以使用http api的方式来调用chatgpt。这篇文章,我们就来详细解析一下通过api来调用openai的开放平台的调用。并且最后通过对api的理解,来解构下目前最火的autogpt的实现原理。 接口地址 首先我们明确下范围,openai提供了非常多的模型,不同模型在开放平台可能有不同调用方式,而openai目前最流行的模型就是chatgpt,专注于聊天对话的大模型。我们这里研究的接口,就是chatgpt提供的开放平台的接口。 chatgpt的接口是一个标准的http请求,请求的url为 POST https://api.openai.com/v1/chat/completions 官方的接口文档地址为:https://platform.openai.com/docs/api-reference/chat/create 我们可以在这个文档中看到所有的参数说明和示例,但是官方文档虽然非常权威,但是却是非常简陋的。要将里面的每个参数理解透,却并不是那么容易。这里我结合最近的研究,来手把手带你理解下chatgpt的api接口的每个参数含义。 请求 model model参数代表请求接口要使用什么模型。这个模型仅限于GPT模型,目前openai的GPT模型开放的只有GPT-4 和GPT-3.5。 在这里,model参数我们可以选择的有: gpt-4 gpt-4-0314 gpt-4-32k gpt-4-32k-0314 gpt-3.5-turbo gpt-3.5-turbo-0301 首先我们理解下为什么有这么多种模型的分类呢?为什么不能只有GPT-4和GPT-3.5呢? 每个模型分类代表了不同的AI算法和训练方法。这里的各种分类我们可以理解为git的不同分支,openai的工程师在不同时期尝试使用不同的方法和数据集来训练模型,以达到解决不同问题的目的。 gpt-4 是 OpenAI 最新的大型多模态模型,可以接受图像和文本输入,输出文本。它在各种专业和学术的基准测试中表现出了人类水平的性能,例如在模拟律师考试中得分位于前 10%。 而gpt-4-0314 是 gpt-4 模型的一个快照,它是在 2023 年 3 月 14 日发布的。它与最新的 gpt-4 模型相比,可能存在一些差异和缺陷。 gpt-4-32k是 gpt-4 模型的一个扩展版本,它提供了 32,000 个 token 的上下文长度,而标准的 gpt-4 模型只提供了 8,000 个 token 的上下文长度。这意味着 gpt-4-32k 可以处理更长的输入和输出,适用于一些需要更多细节和信息的任务。 gpt-3.5-turbo 是 OpenAI 在 2022 年发布的一个大型单模态模型,只接受文本输入,输出文本。它是在 GPT-3.5 的基础上进行了一些优化和改进,提高了性能和稳定性。 简要来说,不同模型在相同问题上,会有不同表现,这种表现不仅仅是回答问题的不同,也包括反应速度,准确度等。由于不同的人会有不同的使用场景,所以openai就干脆把所有模型分类都提供给大家,让大家按需选择。 这里再深入思考一个扩展知识点:token是什么?token上下文长度大和小有什么区别呢? 我们需要知道,每个文本都是由不同的单词组成,不同单词组合起来,就代表一个句子。而GPT模型在进行句子分析计算的时候,是以token为最小单元,也就是计算机的“单词”。比如一句话“我是中国人”在计算机中是会被分成几个token: 我,是,中国,人。 而自然而然在一个对话中,我们的token长度允许越长,我们就能传输越多的内容,提供越多的能力。且理论上回答一个问题需要的时间就会越长。 比如现在比较流行直接将一个pdf文件传输给GPT,让GPT总结pdf的内容。那么一个pdf的token数就非常多,如果使用普通的GPT-4,可能就没有办法理解一个完整的pdf文件内容。这时候模型就需要选择GPT-4-32k。

解决WARN: Establishing SSL connection without server‘s identity verification is not recommended. Accor

次从数据库中进行查询或者其他操作控制台都会出现以下警告 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification. 解决方法 1 :在配置文件中的连接数据库的URL后面添加 useSSL=false

判断变量的数据类型(常见四种方法及解析)

判断变量的数据类型 判断数据类型的方法大概有四种: typeof、instanceof、 constructor、 prototype(最好用) 1.使用typeof操作符。 对一个值使用 typeof 操作符可能返回下列某个字符串,返回的类型都是字符串形式。 (1) undefined:如果这个值未定义 (2) boolean:如果这个值是布尔值 (3) string:如果这个值是字符串 (4) number:如果这个值是数值 (5) object:如果这个值是对象或null (6) function:如果这个值是函数 需要注意:用typeof检测构造函数创建的Number,String,Boolean都返回object 基本数据类型中:null 。引用数据类型中的:Array,Object,Date,RegExp。不可以用typeof检测。都会返回小写的object (1)typeof方法封装; function getTypeUsingTypeof(variable) { return typeof variable; } 示例: console.log(getTypeUsingTypeof(42)); // "number" console.log(getTypeUsingTypeof("Hello")); // "string" console.log(getTypeUsingTypeof(true)); // "boolean" ++console.log(getTypeUsingTypeof([])); // "object" ++console.log(getTypeUsingTypeof({})); // "object" ++console.log(getTypeUsingTypeof(null)); // "object" console.log(getTypeUsingTypeof(undefined)); // "undefined" console.log(getTypeUsingTypeof(function() {})); // "function" 2. instanceof instanceof 运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上。需要区分大小写。 简单的来说,instanceof 用于判断一个变量是否某个对象的实例。 需要注意,instanceof只能用来判断对象和函数,不能用来判断字符串和数字等。判断它是否为字符串和数字时,只会返回false。 null和undefined都返回了false,这是因为它们的类型就是自己本身,并不是Object创建出来它们,所以返回了false。 (2)instanceof方法封装 function getTypeUsingInstanceof(variable) { if (variable instanceof Array) { return "

K8S应用安全检测(调用分析 容器健康 审计日志)

应用安全检测 1 应用安全检测1.1 调用分析1.1.1 sysdig基础1.1.2 命令实践 1.2 容器监控1.2.1 CAdvisor1.2.2 Falco基础1.2.3 Falco实践1.2.4 进阶实践1.2.5 可视化实践 1.3 审计日志1.3.1 日志解读1.3.2 审计日志 1 应用安全检测 1.1 调用分析 1.1.1 sysdig基础 学习目标 这一节,我们从 基础知识、简单实践、小结 三个方面来学习。 基础知识 简介 Sysdig 是一个开源系统(System)发掘(dig)工具,它汇聚了 strace、tcpdump、htop、iftop、lsof等工具的能力。常用于系统级别的监控、分析和故障排查等场景,可以把它看作一系列Linux系统工具的组合。 strace:追踪某个进程产生和接收的系统调用。 tcpdump:分析网络数据,监控原始网络通信。 lsof: list opened files, 列出打开的文件。 top:监控系统性能工具。 htop :交互式的进程浏览器,可以用来替换 top 命令。 iftop :主要用来显示本机网络流量情况及各相互通信的流量集合。 lua:一种嵌入式的脚本语言,从而为应用程序提供灵活的扩展和定制功能。 功能 Sysdig除了能够获取系统资源利用率、进程、网络连接、系统调用等信息,还具备了非常强的分析能力。Sysdig 不仅能分析Linux 系统的“现场”状态,也能将该状态保存为转储文件以供离线分析检查。同时还可以自定义 Sysdig 的行为,通过内建的名为chisel的小脚本增强其功能。 通过 Sysdig 可以挖掘非常多的系统信息:用户能够很方便地查看到主机上所有应用程序的cpu、文件 i/o、网络访问状况;Sysdig可以快速进行系统数据的收集和分析;提供了容器级别的信息采集命令,支持查看指定容器之间的网络流量、查看特定容器的 CPU使用情况。 项目代码: https://github.com/draios/sysdig 项目介绍: https://github.com/draios/sysdig/wiki 伴随着容器技术的大力普及和实践落地,针对容器场景的检测工具也应运而生,Sysdig就属于这里面比较典型的一套开源工具。它不仅仅能够针对传统主机进行检测,更能根据Docker软件在宿主机上落地的方式,自动发现容器内的进程,从而实现容器环境信息的采集和分析,这让我们能够即时了解客户在生产中运行云原生服务的解决方案,这也直接促使sysdig成为适用于服务器和容器的“故障定位和排除工具”。 原理解析 sysdig通过在内核的驱动模块注册系统调用的hook,这样当系统调用发生和完成的时候,它会把系统调用信息拷贝到特定的buffer,然后通过用户态组件对数据信息处理(解压、解析、过滤等),并最终通过sysdig命令行和用户进行交互。 简单实践 Centos环境部署 导入软件源 rpm --import https://download.

K8S应用流程安全(镜像安全 配置管理 访问安全)

应用流程安全 1 应用流程安全1.1 镜像安全1.1.1 构建原则1.1.2 Dockerfile实践1.1.3 构建进阶1.1.4 镜像检测1.1.5 仓库升级1.1.6 高可用仓库1.1.7 镜像策略 1.2 配置管理1.2.1 配置基础1.2.2 YAML安全1.2.3 kustomize1.2.4 基础实践1.2.5 功能复用1.2.6 配置定制1.2.7 补丁实践 1.3 访问安全1.3.1 安全检测1.3.3 简单实践1.3.3 虚拟主机1.3.4 四层实践1.3.5 策略实践 1 应用流程安全 1.1 镜像安全 1.1.1 构建原则 学习目标 这一节,我们从 基础知识、原则解读、小结 三个方面来学习。 基础知识 k8s平台使用业务环境 生产中使用k8s操作业务环境的基本原则 1 保证容器应用是正常运行的 2 创建专属的资源对象文件 3 基于资源对象文件创建业务环境 4 测试业务环境,如果不满足则进行后续动作,否则不做任何改变 - 调整容器的镜像文件 - 重新调整资源对象文件 - 基于新资源对象文件创建并测试新的环境 需求 镜像是容器运行的基础,容器引擎服务可使用不同的镜像启动相应的容器。在容器出现错误后,能迅速通过 删除容器、启动新的容器来恢复服务,这都需要以容器镜像作为支撑技术。 而Kubernetes作为一种容器任务编排平台,它对于应用的管理都是基于镜像文件创建出来的。 镜像的使用流程 Docker镜像加载 对于Docker镜像文件整体来说,它是一个只读的文件,但是根据我们对构建过程的理解,我们发现,对于Docker镜像还有很多更深层的东西: 1 镜像文件是基于分层机制实现的 - Docker 镜像的最底层是 bootfs(boot file system), bootfs主要包含 bootloader 和 Kernel , bootloader加载kernel信息到内存中,然后内存使用权交给内核,接着内核卸载bootfs。 - 在 bootfs之上是rootfs(root file system),它包含了不同Linux发行版(Ubuntu|Centos)文件系统中的标准目录和文件,比如/dev,/proc,/bin,/etc等。它由内核挂载为只读模式,而后通过"

K8S应用服务安全(最小特权 策略方案 资源限制 调用限制 沙箱)

应用服务安全 1 应用服务安全1.1 最小特权1.1.1 基础知识1.1.2 安全上下文1.1.3 资源实践1.1.4 特权基础1.1.5 特权实践1.1.5 PSP实践 1.2 策略方案1.2.1 OPA简介1.2.2 特权策略1.2.3 策略进阶 1.3 资源限制1.3.1 AppArmor简介1.3.2 基础知识1.3.2 应用实践 1.4 调用限制1.4.1 Seccomp1.4.2 应用实践 1.5 应用沙箱1.5.1 gVisor应用1.5.2 环境集成1.5.3 Containerd集成1.5.4 k8s集成 1 应用服务安全 1.1 最小特权 1.1.1 基础知识 学习目标 这一节,我们从 场景解读、细节解读、小结 三个方面来学习。 场景解读 应用安全攻击 随着基于容器部署方式的改变,软件的交付速度越来越快,而为了体现应用的价值快速变现,在软件研发模式、软件架构模式、软件交付模式、软件部署模式都做了相应的调整。 虽然应用交付越来越快,但是业务受到的危害也越来越多,根据OWASP组织针对2021年全球互联网的网络安全攻击事件的统计分析,针对用户行为的攻击形式占据1/5的比例,而针对服务端软件结构漏洞的攻击占据了4/5,越来越多的攻击着重于用户数据、企业数据、相关数据的二次使用,基于这些数据进行大量的安全攻击,尤其是针对企业软件项目的安全攻击事件,很大程度上从用户的管理行为、数据泄露行为、安全管理制度漏洞等方面入手导致的安全攻击。 特点解读 我们会发现,越来越多的安全攻击事件,很大程度上是由于程序自己设计时候出现的漏洞、数据校验不合理、内部配置失误、安全体系建设等方面的不合理导致的,说白了,该进行信息紧密校验的地方我们没有做,或者说该缩小权限限制的地方我们没有加固。 方案思路 在很多项目的大部分实际的工作中,当一个开发人员或者其他相关人员请求开通访问权限时,系统管理员等负责权限的人员因为多种因素盲目的提供了访问权限,这导致了在组织内部有很多的漏洞,极有可能会造成重大安全风险。所以,目前行业中提出了一套所谓的最小特权原则(Understanding Principle of Least Privilage)来解决该问题。它的核心点是 将用户的项目操作权限限制到一个最小范围,然后从服务端入手,最大化减少安全攻击的机率 细节解读 最小特权原则 最小权限原则最早由 Saltzer 和 Schroeder 提出来的,它是指每个程序和系统用户都应该具有完成任务所必需的最小权限集合。它要求计算环境中的特定抽象层的每个模块只能访问当下所必需的信息或者资源。 最小权限的生活场景理解: 使用方面 - 一个用户应该只能访问履行他的相关职责所需访问的数据和硬件。 安全层面 - 每个合法动作最小权限,保护数据及功能,避免遭受恶意破坏的机率。 linux最小化原则示例 最小化原则对Linux系统安全来说非常重要,一般包括如下几个方面: 1.

【MySQL 】MySQL 创建数据库, MySQL 删除数据库,MySQL 选择数据库

作者简介: 辭七七,目前大一,正在学习C/C++,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: 七七的闲谈 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖 显示命令 MySQL 创建数据库使用 mysqladmin 创建数据库使用 PHP脚本 创建数据库 MySQL 删除数据库drop 命令删除数据库使用 mysqladmin 删除数据库使用PHP脚本删除数据库 MySQL 选择数据库从命令提示窗口中选择MySQL数据库使用PHP脚本选择MySQL数据库 实例七七赠书活动 MySQL 创建数据库 我们可以在登陆 MySQL 服务后,使用 create 命令创建数据库,语法如下: CREATE DATABASE 数据库名; 以下命令简单的演示了创建数据库的过程,数据名为 RUNOOB: [root@host]# mysql -u root -p Enter password:****** # 登录后进入终端 mysql> create DATABASE RUNOOB; 使用 mysqladmin 创建数据库 使用普通用户,你可能需要特定的权限来创建或者删除 MySQL 数据库。 所以我们这边使用root用户登录,root用户拥有最高权限,可以使用 mysql mysqladmin 命令来创建数据库。 以下命令简单的演示了创建数据库的过程,数据名为 RUNOOB: [root@host]# mysqladmin -u root -p create RUNOOB Enter password:****** 以上命令执行成功后会创建 MySQL 数据库 RUNOOB。

用Python爬取Twitter数据的挑战与解决方案

你是一个数据分析师,你想用Python爬取Twitter上的一些数据,比如用户的昵称、头像、发言、点赞、转发等等。你觉得这应该是一件很简单的事情,只要用requests库和BeautifulSoup库就可以轻松搞定。但是,当你真正开始写代码的时候,你发现事情并没有那么顺利。你遇到了以下几个问题: Twitter的网页是动态加载的,你无法直接通过requests库获取到完整的HTML源码,你需要用selenium库或者其他方法来模拟浏览器的行为。Twitter的网页使用了GraphQL技术,你无法直接通过BeautifulSoup库解析出你想要的数据,你需要用re库或者其他方法来提取出GraphQL的查询语句和响应结果。Twitter的网页有反爬虫机制,你可能会被封IP或者被要求输入验证码,你需要用代理服务器或者其他方法来绕过这些限制。 这些问题让你感到很头疼,你想放弃这个项目。但是,别急,我在这里给你提供一个简单有效的解决方案,让你可以用Python爬取Twitter的数据,不重复不遗漏。 第一步:获取Twitter的GraphQL查询语句 首先,我们需要获取Twitter的GraphQL查询语句。这是一个很关键的步骤,因为Twitter的数据都是通过GraphQL来传输的。如果我们能够获取到正确的查询语句,我们就可以直接向Twitter发送请求,而不需要模拟浏览器的行为。 那么,如何获取Twitter的GraphQL查询语句呢?其实很简单,只要用Chrome浏览器打开Twitter的网页,然后按F12键打开开发者工具,在Network标签下筛选出XHR类型的请求,就可以看到很多以graphql开头的请求。这些请求就是我们要找的GraphQL查询语句。 例如,如果我们想爬取某个用户(比如@elonmusk)的最近10条推文,我们就可以找到以下这样的请求: { "operationName": "UserByScreenName", "variables": { "screen_name": "elonmusk", "withHighlightedLabel": true, "withTweetQuoteCount": true, "includePromotedContent": true, "withTweetResult": false, "withReactions": false, "withUserResults": false, "withVoice": false, "withNonLegacyCard": true }, "extensions": { "persistedQuery": { "version": 1, "sha256Hash": "a9b1fc9a4d2b1d945d144e9e0f8ec705665bba908e6de7f0c8f8ea9c8f25a000" } } } 这个请求中包含了三个部分:operationName, variables和extensions。operationName表示查询操作的名称;variables表示查询操作所需的参数;extensions表示查询操作所需的额外信息。我们可以看到,在variables中有一个screen_name参数,它的值就是我们想要爬取的用户昵称@elonmusk。 如果我们把这个请求发送给Twitter,并且在Headers标签下添加一个名为x-twitter-client-language的字段,并且把它的值设为en(表示英文),我们就可以得到以下这样的响应结果: { "data": { "user": { "rest_id": "44196397", "legacy": { "id_str": "44196397", "name": "Elon Musk", "screen_name": "elonmusk", "location": "", "description": "", "url": null, "entities": { "

JS中key-value存取

var map = {}; map['key1'] = 1; map['key2@'] = 2; console.log(map['key1']);//结果是1. console.log(map['key2@']);//结果是2. //如果遍历map for(var prop in map){ if(map.hasOwnProperty(prop)){ console.log('key is ' + prop +' and value is' + map[prop]); } }

大模型微调样本构造的trick

来自:包包算法笔记 进NLP群—>加入NLP交流群 开局一道面试题。 面试官:大模型微调如何组织训练样本? 你:大模型训练一问一答,一指令一输出,问题和指令可以作为prompt输入,答案作为输出,计算loss的部分要屏蔽掉pad token。 面试官:多轮对话如何组织训练样本呢? 你:假设多轮为Q1A1/Q2A2/Q3A3,那么可以转化成 Q1—>A1, Q1A1Q2->A2, Q1A1Q2A2Q3->A3三条训练样本。 面试官:这样的话一个session变成了三条数据,并且上文有依次重复的情况,这样会不会有啥问题? 你:数据中大部分都是pad token,训练数据利用效率低下。另外会有数据重复膨胀的问题,训练数据重复膨胀为 session数量*平均轮次数,且上文有重复部分,训练效率也会低下。 面试官:你也意识到了,有什么改进的方法吗? 你:有没有办法能一次性构造一个session作为训练样本呢?(思索) 面试官:提示你下,限制在decoder-only系列的模型上,利用模型特性,改进样本组织形式。 对于这个问题,我们思考下decoder-only模型有啥特点,第一点很关键的是其attention形式是casual的,casual简单理解就是三角阵,单个token只能看到其上文的信息。 如图所示: 其二是postion_id是只有token次序含义而无需特定指代信息,(区别于GLM模型需要postion_id来标识生成span的位置等特殊的要求)。 有了这两点我们就可以设想,如果构造多轮对话样本的input为 Q1 A1 <eos> Q2 A2 <eos> Q3 A3 <eos>,在计算loss的时候,只需要计算 A1 <eos> A2 <eos> 和 A3 <eos>部分,岂不是就可以进行session级别的训练了? 嗯为什么原来的chatglm不能用这种形式呢,虽然prefix attention可以推广为适应多轮训练的prefix attention形式,如图: 但是由于其postition id 无法简单按次序推广,故不能高效训练,这也是chatglm初代的很大的一个问题,导致后续微调的效果都比较一般。 现在chatglm2的代码针对这两个问题已经进行了改善,可以认为他就是典型的decoder-only模型了,具体表现为推断时候attention 是casual attention的形式,position id也退化为token次序增长。 那么好了,万事具备,只欠东风。我们据此实现了chatglm2-6b的代码微调。其核心代码逻辑为处理样本组织的逻辑,其他的就是大模型微调,大同小异了。 conversation = '' input_ids = [] labels = [] eos_id = tokenizer.eos_token_id turn_idx = 0 for sentence in examples[prompt_column][i]: sentence_from = sentence["

Windows PCL点云库不同版本的切换,以及不同版本计算结果不一致的阐述

因时代机遇,我首次使用的版本组合是VS2019+PCL1.11.1+cmake3.18.5; 因发展需要,当前最新的版本组合是VS2022+PCL1.13.1+cmake3.26.4; 一、首先,为啥要切换版本呢? (1)不同版本的PCL库的API可能不同,导致代码编译就报错; (2)不同版本的PCL库的计算结果可能不一致,导致结果的不可复现性; 二、那么,我们平时应该用哪个版本呢? 平时应该用的版本是业务代码使用的版本,比如我的业务代码基本是VS2019+PCL1.11.1编译运行的,那么即使换了新电脑,在验证代码结果时,也应该以这个版本组合为主; 而新的版本组合VS2022+PCL1.13.1,则可以等到业务代码环境都升级到该版本时再使用,目前研究一下版本切换,就是想机器有多个版本的情况下,我想用哪个版本就用哪个; 三、正题,切换版本之前的软件安装工作 安装VS2019、VS2022、cmake3.18.5、cmake3.26.4、PCL1.11.1、PCL1.13.1之后; 版本切换的工作主要是系统环境变量的修改: 以下以_ALL结尾的环境变量基本不起作用,只是我列举的枚举,以PCL_ROOT和PCL_ROOT_ALL为例,PCL_ROOT_ALL放置了所有PCL_ROOT值的枚举,在我需要用某个特定版本时,我就可以复制其中一个值给到PCL_ROOT; 第三张图时Path的值,当需要用到哪个版本时,应当将对应版本的路径值上移至其他版本之前; 注意!!! 例子:在运行时,即使你编译时使用的是PCL1.13.1,但是运行时系统的环境改变成了PCL1.11.1,那么因为两个版本的库的名称都是一样的(库的名称并没有带版本),因此不会报没有DLL的错误而是直接成功运行,但是最终运行的结果是当前系统环境对应的PCL1.11.1版本的结果。 四、不同版本计算结果不一致的阐述: VS2019(MSVC16)+PCL1.11.1+cmake3.18.5的组合VS2022(MSVC17)+PCL1.13.1+cmake3.26.4在运行某些函数时结果不一致,原因未知,需要查看源码是否改动或者Github询问函数是否改动,已经在Github问了,见GitHub - PointCloudLibrary/pcl: Point Cloud Library (PCL)https://github.com/PointCloudLibrary/pcl/issues/5760,但是没有更明确的结论,好奇的大家可能试试下列代码: #include <iostream> #include <Eigen/Core> #include <opencv2/opencv.hpp> #include <pcl/common/angles.h> #include <pcl/common/impl/pca.hpp> #include <pcl/common/common.h> // for getMinMax3D() #include <pcl/common/eigen.h> #include <pcl/common/centroid.h> #include <pcl/common/geometry.h> #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/io/ply_io.h> #include <pcl/io/obj_io.h> #include <pcl/segmentation/sac_segmentation.h> //基于采样一致性分割的类的头文件 int main() { using namespace std; using namespace cv; cout << "begin" << endl; string obj_path = R"

Chrony与NTP对比

一、Chrony简述 chrony是网络时间协议(NTP)的另一种实现,与网络时间协议后台程序(ntpd)不同,它可以更快地且更准确地同步系统时钟,请注意,ntpd仍然包含其中以供需要运行NTP服务的客户使用。 两个主要程序:chronyd和chronyc chronyd:后台运行的守护进程,用于调整内核中运行的系统时钟和时钟服务器同步。它确定计算机增减时间的比率,并对此进行补偿 chronyc:命令行用户工具,用于监控性能并进行多样化的配置。它可以在chronyd实例控制的计算机上工作,也可在一台不同的远程计算机上工作 服务unit文件: /usr/lib/systemd/system/chronyd.service 监听端口: 323/udp,123/udp 配置文件: /etc/chrony.conf 二、环境配置: 1、关闭firewalld防火墙 2、关闭SELinux 3、chrony与ntp都是时间同步软件,两个软件不能够同时开启,会出现时间冲突 三、NTP/Chrony对比: 使用chronyd服务平滑同步时间的方式要优于crontab + ntpdate,因为ntpdate同步时间会造成时间的跳跃,对一些依赖时间的程序和服务会造成影响,例如:sleep、timer等,且chronyd服务可以在修正时间的过程中同时修正CPU tick。 chrony的优势包括以下几点: 1.更快的同步只需要数分钟而非数小时时间,从而最大程度减少时间和频率误差,这对于并非全天24小时的运行的台式计算机或系统而言非常有用; 2.能够更好地响应时钟频率的快速变化,这对于具备不稳定时钟的虚拟机或导致赛事中频率发生比变化的节能技术; 3.在初始同步后,它不会停止时钟,以防对需要系统时间保持单调的应用程序造成影响; 4.在应对临时非对称延迟时(例如大规模下载造成链接饱和等情况)提供了更好的稳定性; 5.无需对时间服务器进行定期轮询,因此具备间歇性网络连接(如网络不稳定的场景)的系统仍然可以快速同步时钟。 ntp能做,chrony做不到的: ntp支持RFC 5905的所有操作模式,包括广播、多播和manycast服务器/客户端。然而,广播和多播模式本质上不如普通的服务器/客户机模式准确和安全(即使有身份验证),通常应该避免。 ntp支持自动密钥协议(RFC 5906)来使用公钥加密对服务器进行身份验证。请注意,该协议已被证明是不安全的,并且已被NTS(RFC 8915)淘汰。 ntp已经被移植到更多的操作系统中。 ntp包含大量用于各种硬件参考时钟的驱动程序。chrony需要其他程序(如gpsd或ntp refclock)通过SHM或SOCK接口提供参考时间。 chrony可以比ntp做得更好: chrony可以在访问时间参考是断断续续的环境中有效地执行。ntp需要定期对引用进行轮询才能正常工作。 chrony通常可以更快地同步时钟,并具有更好的时间精度。 chrony快速适应时钟速率的突然变化(例如,由于晶体振荡器的温度变化)。ntp可能需要很长时间才能重新安定下来。 chrony即使在网络拥塞时间较长的情况下也能表现良好。 默认配置中的chrony从不占用时间来不打乱其他正在运行的程序。ntp也可以配置为从不步进时间,但是在这种情况下,它必须使用不同的方法来调整时钟(daemon循环而不是内核规程),这可能会对时钟的准确性产生负面影响。 chrony可以在更大的范围内调整时钟的速率,这使得它甚至可以在时钟中断或不稳定的机器上运行(例如在某些虚拟机中)。 chrony更小,占用的内存更少,只有在需要时才会唤醒CPU,这样更省电。 chrony可以做ntp做不到的事情: chrony支持网络时间安全(NTS)认证机制。 chrony在Linux上支持硬件时间戳,这允许在本地网络中进行非常稳定和准确的同步。 chrony为独立网络提供支持,无论时间校正的唯一方法是手动输入(例如,由管理员查看时钟)。chrony可以查看在不同更新时更正的错误,计算出计算机获得或丢失时间的速率,并使用此估计值来随后调整计算机时钟。 chrony支持计算实时时钟的增益或丢失率,即在计算机关闭时保持时间的时钟。当系统引导时,它可以使用这些数据从实时时钟的修正版本设置系统时间。到目前为止,这些实时时钟工具仅在Linux上可用。 四、chrony服务安装的文件: # rpm -ql chrony /etc/NetworkManager/dispatcher.d/20-chrony /etc/chrony.conf #chrony的主配置文件 /etc/chrony.keys /etc/dhcp/dhclient.d/chrony.sh /etc/logrotate.d/chrony /etc/sysconfig/chronyd /usr/bin/chronyc #chronyc是一个命令行交互式接口程序,可用于监视chronyd的性能,并在运行时更改各种操作参数。 /usr/lib/systemd/ntp-units.d/50-chronyd.list /usr/lib/systemd/system/chrony-dnssrv@.service /usr/lib/systemd/system/chrony-dnssrv@.timer /usr/lib/systemd/system/chrony-wait.service /usr/lib/systemd/system/chronyd.service #CentOS 7.x版本对应的unit file /usr/libexec/chrony-helper /usr/sbin/chronyd #chronyd是一个可以在启动时启动的守护程序,它既可以充当服务端进程也可以充当服务端进程 /usr/share/doc/chrony-3.

抓包看TCP协议

抓包看TCP协议 前言一、三次握手1.1 为什么需要握手?1.2 为什么需要三次握手? 二、四次挥手2.1 为何需要挥手?2.2 为何需要四次挥手? 三、抓个包看看 后记参考 前言 在计算机的世界中,通信双方的交互一般要通过网络这个中间媒介。而这个中间体在为不同的通信实体之间进行信息传递之时,可能会采用不同的通信协议,为的就是更好,更清晰、更有效率的协调双方信息传递。 在众多的通信协议中,有一些协议在实际的应用中被使用的越来越多,比如说我们今天要说的TCP协议。 学计算机网络时,TCP协议作为一个大头部可难倒了不少的同学。一部分可能是因为其确实不简单(握手过程、挥手过程,序列号,ack、封包拆包巴拉巴拉的),另一个可能是因为我们在业务上层使用的大都是应用层协议(或者框架给我们封装好了的网络库), 不太能接触TCP的实现细节。但是如果想要理解这个协议,更好的为上层业务做支撑,从底层细节来窥探协议过程不得不说是一个好的方式。 这里就以网络抓包的方式来总结TCP协议的一些重点内容,记录在此,希望可以便人便己。 关于TCP协议,在我看来其主要包括两个主要方面: 一个是保证协议的正确性。即在不可靠的网络传输之上如何保证协议能够正常工作。这里面主要涉及ACK、校验和、重传、和序列号等机制。二是保证通信(和网络)的效率和性能。主要是尽可能在提高发送数据速率以及防止网络拥塞之间达到一个平衡。这里面这里面主要有选择重传、滑动窗口、拥塞控制等重点内容。 这里主要谈谈保证协议正确的中的建立连接(三次握手)和断开连接的过程(四次挥手)。 一、三次握手 1.1 为什么需要握手? 握手的过程是一个协商的过程。可靠通信的双方总要确定对方是否存在,是否准备好接受数据,对吧(UDP那种不管对方的状态怎么样,直接甩过去一堆数据的不是可靠老实的TCP的风格)。同时,由于可能会遇到不可靠的快递员(下层的通信网络)弄丢包裹(发送的数据报文段)的情况,因此时不时的tcp得重新发送上丢失的报文。这时候维护一个序列号seq,很正常吧(否则,上帝也不知道该重传哪一个报文吧)。 因此,可靠的通信需要一个握手协商的过程,合作嘛,对方的底细或多或少总的了解些吧。 1.2 为什么需要三次握手? 一言以蔽之,为了防止C端连接的重复初始化。因为有可能C端的第一次握手会发送多次(比如说以前的第一次握手的报文在中间的时候丢失了或者阻塞了,那么在超时之后就会重复发送第一段握手)。所以S端也可能收到好多个建立连接的请求(第一次握手的报文),服务端没有充足的信息来判断哪个连接才是真正的。所以很无奈,S端只能全部ACK,把皮球提给客户端。 客户端由于保存了最新请求的序列号,它知道哪一个请求才是最新的,因此它会给最新的那个ACK,其他过期的直接RST掉。 这个过程也就是必须的第三次握手的过程。 先盗一张图。 还可以从序列号建立的角度来看三次握手。 因为TCP是全双工协议,通信的双方可以同时发送数据给对方。因此协商的过程是双向的,而且必须得到ACK确认。 不明白? 好,解释细点。 第一次握手是C端(客户端)发起请求,准备建立连接。同时提供C端的初始序列号Seq1。( hello, 我想问你几个问题,这是我的起始问题编号,你看看有没有问题?)第二次握手是S端(服务端)对C端的请求进行回复ACK;同时,S端为了向C端发送数据,也会提供一个S段的初始序列号Seq2。(enen,我收到了你的Seq1,ok,已经记录下来了;我也有几个问题想问你,这是我的起始序列号。你确认一下?)第三次握手是C端对S端协商参数的确认(enne,好,我这边也准备好了)。同时,C端也可以在这次握手的时候发送一部分请求的数据。 上面两个握手只保证了S端对C端的确认,保证了C端可以向S端发送数据。但是无法保证S端的协商参数还没有得到C端的确认(在不可靠的下层网络中,谁也不知道第二次握手会会不会丢失)。因此还必须有第三次过程。只有经历过第三次握手,服务端才能确认客户端准备好接受数据了。当然,由于前两次握手已经说明S端准备好接受数据了,因此C端可以在第三次握手的时候夹带些私货(真正需要发送的数据)。 二、四次挥手 2.1 为何需要挥手? 既然相见时协商建立了连接,那么分离时,贸然离去总不是一个好的选择,毕竟对方还一直在傻傻等待(而且还维持了一些资源)。 所以,在断开连接时,tcp协议中规定了要有断开连接,即挥手的过程。 2.2 为何需要四次挥手? 那么为何需要四次挥手才能把连接正确的断开呢。 因为,tcp是全双工的通信协议,任何时刻对方都有可能在发送数据。因此,在断开连接时要告知对方(并尽量得到对方的ack确认)。 通信双方都可以首先进行断开连接。这里以客户端断开连接为例进行介绍。 在tcp包中打上FIN标志,就是向对方申明,自己这端不会再发送数据了。然后进入到FIN_WAIT_1状态 。服务端接收到客户端的请求之后,向对方发送一个ACK,然后进入到CLOSE_WAIT的状态。(客户端接受到这个ACK之后进入到FIN_WAIT_2状态) 需要注意的是这个时候服务端依旧可以发送数据,因为服务端还没表明自己已经没有数据需要发送了 当服务端把应用层的数据发送完毕之后,也会发送一个FIN标志的tcp包来表明自己已经把所有的数据发送完毕了。这个时候服务端进入LAST_ACK状态,准备接收客户端的ACK。客户端接收到服务端发送的FIN请求之后,会回一个ACK包。然后进入到最后的TIME_WAIT状态,等待 2MSL时间,进入最终的CLOSE状态。 以上是四次挥手的过程,两个FIN,两个ACK, 匹配的相当对称完美。 这里有几个问题需要阐明一下,当客户端返回最后一个ACK之后,与它相关的四次握手都已经结束,为什么还要在等待一个2MSL的时间呢? 两个原因: 一个是为了优雅的关闭整个连接,即如果客户端的第四次ACK握手丢失了,服务端会重传第三次握手,客户端处于TIME_WAIT状态(还没有关闭连接)可以继续响应ACK。让本次连接中的所有报文在网络中都消息(有可能有延时的报文)。比如说,如果有一个阻塞在哪儿的SYN报文一直没到,在挥手过程中姗姗来迟了,服务端接收到这个请求后还以为是个新的连接呢(服务端会放弃目前的挥手阶段,进入到新建连接的阶段,但是这个SYN请求是过期的,不会得到客户端的响应)? 更详细的分析可以参见【4】 三、抓个包看看 上面讲的是理论部分,下面我们用tcpdump和wireshark抓包看一下。关于tcpdump和wireshark软件教程网上有一大堆,这里就不赘述了。 上简单的实验代码: 客户端程序: #!/usr/bin/env python3 import socket HOST = '9.134.149.248' # 服务器的主机名或者 IP 地址 PORT = 9998 # 服务器使用的端口 with socket.

【杂波仿真】基于matlab实现瑞利杂波仿真

✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 ⛄ 内容介绍 瑞利杂波(Rayleigh fading)是无线通信中常见的信道衰落模型,其特点是信号经过多径传播引起的幅度衰落呈瑞利分布。下面将介绍瑞利杂波的仿真方法。 生成复高斯随机信道:首先生成复高斯随机变量,表示信道的复数增益,它包括实部和虚部。复高斯随机变量服从零均值、单位方差的高斯分布。生成瑞利幅度:根据生成的复高斯随机变量,计算其幅度,即信道增益的模值。生成瑞利相位:根据生成的复高斯随机变量,计算其相位,即信道增益的辐角。模拟多径传播:通过引入多个独立且服从高斯分布的复高斯随机变量,模拟多径传播效应,每个复高斯随机变量代表一个路径上的衰落。合并多径信号:将各个路径上的信号进行叠加,得到最终的瑞利衰落信号。分析和评估:对生成的瑞利衰落信号进行分析和评估,如计算信号的均值、方差、功率谱密度等指标,以了解瑞利衰落对信号的影响。 ⛄ 部分代码 clear all;close all; azi_num=2000; %取2000个点 fr=1000; %雷达重复频率 lamda0=0.05; %杂波波长 sigmav=1.0; %杂波方差 sigmaf=2*sigmav/lamda0; rand('state',sum(100*clock)); %产生服从U(0,1)分布的随机序列 d1=rand(1,azi_num); rand('state',7*sum(100*clock)+3); d2=rand(1,azi_num); xi=2*sqrt(-2*log(d1)).*cos(2*pi*d2); %正交且独立的高斯序列N(0,1) xq=2*sqrt(-2*log(d1)).*sin(2*pi*d2); %形成滤波器频率响应 coe_num=12; %求滤波器系数,用傅里叶级数展开法 for n=0:coe_num coeff(n+1)=2*sigmaf*sqrt(pi)*exp(-4*sigmaf^2*pi^2*n^2/fr^2)/fr; end xlabel('幅度');ylabel('概率密度'); signal=ydata; signal=signal-mean(signal); %求功率谱密度,先去掉直流分量 figure;M=256; %用burg法估计功率谱密度 psd_dat=pburg(real(signal),32,M,fr); psd_dat=psd_dat/(max(psd_dat)); %归一化处理 freqx=0:0.5*M; freqx=freqx*fr/M; plot(freqx,psd_dat);title('杂波频谱'); xlabel('频率/HZ');ylabel('功率谱密度'); %做出理想高斯谱曲线 powerf=exp(-freqx.^2/(2*sigmaf.^2)); hold on;plot(freqx,powerf,'r:'); ⛄ 运行结果 ⛄ 参考文献 [1] 王思思,王立军.基于Matlab的航海雷达噪声与杂波仿真研究[J].科技信息, 2008(6):2.DOI:10.3969/j.issn.1001-9960.2008.06.055. ⛳️ 代码获取关注我 ❤️部分理论引用网络文献,若有侵权联系博主删除 ❤️ 关注我领取海量matlab电子书和数学建模资料 🍅 仿真咨询 1.卷积神经网络(CNN)、LSTM、支持向量机(SVM)、最小二乘支持向量机(LSSVM)、极限学习机(ELM)、核极限学习机(KELM)、BP、RBF、宽度学习、DBN、RF、RBF、DELM实现风电预测、光伏预测、电池寿命预测、辐射源识别、交通流预测、负荷预测、股价预测、PM2.5浓度预测、电池健康状态预测、水体光学参数反演、NLOS信号识别、地铁停车精准预测、变压器故障诊断 2.

图像分割常见指标 Iou,dice,accuracy,recall,sensitivity,precision,F1-score,specificity 图解以及计算代码

图像分割常见指标计算 指标解释IOU,Jaccard indexDice coefficient,F1-scoreAccuracyPrecisionRecall,SensitivitySpecificity 代码计算 指标解释 开始之前需要了解混淆矩阵的知识。另外我还在公式中添加了1e-7作为分子。原因为了避免代码中出现分子为0的情况。本次介绍时,直接写到公式里面。 混淆矩阵如图,如何看呢?在进行图像分割时 比如某个像素点,我们预测为类别P ,真实情况是类别P。那么这个像素点的情况就是“一个预测正确的P”,记为TP (True Positive) 比如某个像素点,我们预测为类别P ,真实情况是类别N。那么这个像素点的情况就是“一个预测错误的P”,记为FP (False Positive) 其他(FN,TN)同理。 将混淆矩阵放到真实图像中,就是这样的情况。 如图是一张图片的情况,GT就是我们数据集图片标注的区域,predict就是我们模型预测出的区域。 predict与GT一定存在差异,这些差异需要依靠评价指标来衡量。不同的评价指标对不同方向的差异有不同侧重点。 下面介绍评价指标: IOU,Jaccard index IOU(Intersection over Union)即交并比,顾名思义,即交集与并集的比值。在图像分割中,我们就计算 GT,Predict的交集与并集的比值。 很多论文还会说的杰卡德指数(Jaccard index),其实就是交并比。 混淆矩阵公式公式图解 Dice coefficient,F1-score 网上有很多关于这两个指标的计算,其实就是同一个计算(不服请推导)。 F1-score是为了能够评价不同算法的优劣,在Precision和Recall的基础上提出了F1值的概念,来对Precision和Recall进行整体评价。F1-score(均衡平均数)是综合考虑了模型查准率和查全率的计算结果,取值更偏向于取值较小的那个指标。F1的定义如下: Dice 系数,也称为 F1 分数,是两个集合之间重叠的度量,范围为 0 到 1。值为 1 表示完全重叠,而 0 表示没有重叠。 dice损失,和dice系数(dice coefficient)的关系是:dice loss = 1-dice coefficient。 这个指标很常见,用的频次比 IOU 还多,主要有: Dice 系数广泛用于评估图像分割模型的性能,因此使用 Dice 损失有助于优化该指标的模型 Dice 损失可以处理类别不平衡,这通常是医学图像分割中的一个问题,其中某些类别可能比其他类别更普遍。 Dice 损失是可微的,这使得它可以与基于梯度的优化算法结合使用。 混淆矩阵公式公式图解 Accuracy accuracy指的是正确预测的样本数占总预测样本数的比值,它不考虑预测的样本是正例还是负例。如果在代码中只考虑正样本,可以在公式中去掉分子tn。 混淆矩阵公式公式图解 Precision precision指的是所有预测为正样本数中正确预测的正样本数占的比值。 混淆矩阵公式公式图解 Recall,Sensitivity recall又叫召回率,指的是正确预测的正样本数占真实正样本总数的比值。Sensitivity,我们常说“敏感性”,sensitivity的值越大,说明“有病的被判断为有病的”越大,“漏检”(FN)越小。这两个指标公式是一致的。

【SVM分类】基于支持向量机的数据分类预测(libsvm)附matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 ⛄ 内容介绍 基于支持向量机(Support Vector Machine,SVM)的数据分类预测是一种常用的机器学习方法,用于将数据划分为不同的类别。在这里,我将介绍基于libsvm库实现SVM分类的基本步骤。 数据准备:首先,准备用于训练和测试的数据集。数据集应包含已标记的样本,每个样本都有一组特征和对应的类别标签。特征提取与选择:根据问题的需求,从原始数据中提取出适当的特征作为输入。特征选择可以帮助提高分类性能,减少不必要的维度。数据预处理:对数据进行预处理操作,如特征缩放、标准化、归一化等,以确保不同特征之间具有相似的尺度。建立模型:使用libsvm库,选择适当的核函数和参数配置来建立SVM分类模型。常用的核函数包括线性核、多项式核和高斯径向基函数(RBF)核。训练模型:将准备好的训练数据输入到libsvm库中,根据选择的核函数和参数进行模型训练。训练过程将找到最优的超平面,以最大化不同类别之间的间隔。模型评估:使用测试数据集对训练好的模型进行评估,计算分类准确率、精确率、召回率、F1值等指标,以评估模型的性能。模型优化:根据评估结果和需求,调整SVM模型的参数配置,如核函数的参数、正则化参数等,以进一步优化分类性能。预测分类:使用训练好的SVM模型对新的未知样本进行分类预测。将样本的特征输入到模型中,根据模型的判定边界将其分为不同的类别。 libsvm是一个常用的SVM库,提供了多种编程语言的接口,如C++, Java, Python等。通过调用相应的接口函数,可以方便地实现SVM分类任务,并进行模型训练和预测。 ⛄ 部分代码 %% 清空环境变量 warning off % 关闭报警信息 close all % 关闭开启的图窗 clear % 清空变量 clc % 清空命令行 %% 导入数据 res = xlsread('数据集.xlsx'); %% 划分训练集和测试集 temp = randperm(357); P_train = res(temp(1: 240), 1: 12)'; T_train = res(temp(1: 240), 13)'; M = size(P_train, 2); P_test = res(temp(241: end), 1: 12)'; T_test = res(temp(241: end), 13)'; N = size(P_test, 2); %% 数据归一化 [p_train, ps_input] = mapminmax(P_train, 0, 1); p_test = mapminmax('apply', P_test, ps_input ); t_train = T_train; t_test = T_test ; %% 转置以适应模型 p_train = p_train'; p_test = p_test'; t_train = t_train'; t_test = t_test'; %% 创建模型 c = 10.

植物大战僵尸源码1.0版

基本上是rock老师讲的代码复现,有部分改动,较大改动文末附~ 【程序员Rock】C语言项目:完整版植物大战僵尸!可能是B站最好的植物大战僵尸教程了!零基础手把手游戏开发_哔哩哔哩_bilibili 小蒟蒻一枚~如有佬指正,不胜感激! #include <stdio.h> #include <conio.h> #include <graphics.h> //easyx #include <iostream> //c++ #include <time.h> //rand() #include <mmsystem.h> //play music #include <math.h> //贝塞尔函数 #include "vector2.h" #pragma comment(lib, "winmm.lib") #define WIN_WIDTH 900 #define WIN_HEIGHT 600 #define ZM_MAX 10 using namespace std; enum {wan_dou, xiang_ri_kui, zhi_wu_count}; enum {GOING, WIN, FAIL}; int killed_zm_count; int zm_appear_count; int game_status; IMAGE img_bg; IMAGE img_bar; IMAGE img_cards[zhi_wu_count]; IMAGE* img_plants[zhi_wu_count][32]; int curplant; // 0:没有选中;1:选择第一种植物 int curx, cury; typedef struct plant { int type; // 0:没有植物;1:第一种植物 int frame_index; //序列帧的序号 bool catched; int deadtime; int x, y; int timer; int shoot_time; }plant; plant map[9][10]; typedef struct sunshineball { int x, y; int frame_index; int dest_y; bool used; int timer; float xoff; float yoff; float t;//贝塞尔曲线时间 vector2 p1, p2, p3, p4; vector2 pcur;//当前阳光位置 float speed; int status; }sunshineball; sunshineball balls[10]; IMAGE img_sunshineball[30]; int sunshine; enum {sunshine_down, sunshine_ground, sunshine_collect, sunshine_product}; typedef struct zm{ int x, y; int frame_index; bool used; int speed; int row; int blood; bool dead; bool eating; }zm; zm zms[10]; IMAGE img_zm[22]; IMAGE img_zm_dead1[10]; IMAGE img_zm_dead2[10]; IMAGE img_zm_eat[21]; IMAGE img_zm_stand[11]; typedef struct bullet { int x, y; bool used; int speed; int row; bool blast; //是否爆炸 int frame_index; }bullet; bullet bullets[50]; IMAGE img_bullet_normal; IMAGE img_bullet_blast[4]; IMAGE img_fail; IMAGE img_win; #pragma comment( lib, "