今天是加入CSDN的第1549天,我已经3年没发贴了

最初是因为查一个课本上没有的知识点,我来到了CSDN,一开始我以为这是一个论坛,技术宅可以发帖记录自己的工作,学习中遇到的难点,让以后的人少踩坑。 来#CSDN做什么# 大部分人应该跟我一样,在安装软件或者程序报错的时候会上百度或者谷歌查报错,一大堆错误栈贴到搜索引擎框里,只能根据前几个错误信息匹配到对应的错误,在国外有个很好用的网站stackflow记录着各种各样的错误,在这里你可以找到不同版本,不同系统报的各种各样的错误,并找到对应的解决办法,CSDN也是如此。 #关于记录学习历程# 来到CSDN的第二年,我在准备本科毕业论文,在这个过程中,发现在论坛上或者网络上有些学长或者学姐总结下的学习大法,好家伙,怎么这么棒呢,所以我也做了一件事情,做一个合格的搬运工吧!收集,整理,给自己看。也可以就给后人学习,正所谓前任栽树后人乘凉凉,所以我整理了关于无人机,关于机器学习,关于音乐生成各个我学习历程的心得体会。 #关于找实习找工作# 实习工作也来这里,看题解,我自己也写题解,记录自己的工作量,有时候发完一个帖子,无论好坏,又没人看,都觉得有一件事完成之后的快感! #为什么我不发了# 工作,感情,生活,当你的工作快乐,感情幸福(也会各种各样的心事),生活充实的时候就不想发了,说白话就是太懒了,周末时间要好好玩,休息,哪有那么多时间过来写贴,就算是锻炼身体也并不是每周一次,而是想起来了,而且空了时间,才回去,或许这么就是长大了吧! 大家呢!你来这里是因为什么呢,请在评论区告诉我!

Node REPL

REPL(Read Eval Print Loop,交互式解释器)是一个处理 Node.js 表达式的交互式 shell,类似 Window 系统的终端或 Unix/Linux shell,我们可以在终端中输入命令,并接收系统的响应。 REPL 与 Node.js 安装捆绑在一起,并执行以下所需的任务: Read − 读取用户输入的 JavaScript 代码Eval − 解释代码行的结果Print− 将结果打印给用户Loop − 循环执行上述操作,直到用户发出退出信号(按下两次 Ctrl + C)。 基本用法 安装完 Node,您就拥有了 REPL,在命令行输入 node 进入 REPL: node 您可以计算一些简单的表达式: > 'Hello' + ' Node' 'Hello Node' > console.log('Hi') Hi > 10 * 2 20 > var x = 10 undefined > var y = 20 undefined > x + y 30 下面重点介绍一下,它的几个重要的命令。

C++数据结构之线性表——顺序表的应用(多余元素删除 求最大子段和递归+动态规划)

一、介绍 顺序表作为一种基于连续存储空间的数据结构可以有多种应用,本文就以将非纯表转纯表以及求最大子段和的两种方法(递归和动态规划)进行介绍和讲解。 在阅读本文之前建议先了解顺序表的实现,因为顺序表的应用基本是依托顺序表已经实现的部分功能才能实现的,具体可看我的另一篇文章:C++数据结构之线性表——顺序表https://blog.csdn.net/m0_56398315/article/details/126748495?spm=1001.2014.3001.5501 为了方便后续的代码读的明白,下图是顺序表中已经实现的函数: void init();//创建顺序表 void destroy();//销毁顺序表 void clear();//清空顺序表 bool empty();//检测是否为空 int getlength();//获取顺序表的长度 int get(int index);//获取下标为index的元素 int locate(int ele);//查找元素ele所在位置的下标 int prior(int index);//取下标为index的元素的前驱元素 int next(int index);//取下标为index的元素的后继元素 void insert(int ele,int index);//在下标为index的元素位置插入元素ele,原位置的元素依次后移一位 void remove(int index);//删除下标为index的元素,下标index后的元素依次向前移动一位 void traverse();//遍历表 void print();//打印表 void push(int ele);//从表尾插入元素 void batchpush();//批量压入数据 二、多余元素删除 概念 1.非纯表 非纯表指的是存在多个相同元素的表,如下图所示就是一个非纯表,其中存在两个相同的元素57 2.纯表 纯表指的是不存在多个相同元素的表,如下图所示就是一个纯表,其中无法找到两个相同的元素 实现 要想实现多余元素的删除我们有多种实现方法,有移位删除法和建新表删除法,下面对这两种方法进行一一介绍。 1.移位删除法 算法思想 1.我们以第1个元素为标准,依次对其后面n-1个元素进行比较 2.若发现有和第一个元素相同的元素,那么我们就删除他 3.直到后面n-1个元素检查完毕 4.我们以第2个元素为标准,依次对其后面n-2个元素进行比较 5.若发现有和第二个元素相同的元素,那么我们就删除他 6.直到后面n-2个元素检查完毕 7.以此类推,直到算法执行完毕 算法实现 void sqlist::shiftremove() { for (int i = 0; i < length; i++) { for (int j = i+1; j < length; j++) { if (element[i]==element[j]) { remove(j); j--; } } } } 2.

SpringMVC依赖Servlet坐标无法导入问题(Tomcat10版本)

在我们先前学习完JavaWeb中的Serlvet中,我们可以会下载Tomcat10的版本,并且为了能够应用Tomcat10这个服务器版本,我们会下载IDEA2021年以上的版本。 这时候当我们学习到SpringMVC中第一步就是在pom.xml中导入Servlet的坐标,但如果未经思考导入了以下就会报错。 在服务器为Tomcat10以后的版本,就不再使用javax包下的依赖了,而是应该改成Jakarta。 先前我们所称呼的JavaEE,现在已经该称呼为JakartaEE了。所有我们应该导入以下的Servlet坐标。 <dependencies> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>5.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.19</version> </dependency> 并不需要我们降低Tomcat版本。

Windows + Nexus + Maven 搭建,一键部署服务,远离焦头烂额,手忙脚乱,舒坦呀

第一步:下载 Nexus,附上连接地址 Nexus Repository OSS - Software Component Management | Sonatypehttps://www.sonatype.com/products/repository-oss 请下载windows版本的,下面以window版本讲解 下载完成并解压后,CMD进入BIN目录,安装成服务 命令 nexus.exe /install 如需要修改服务端口的,回退到上一级目录 修改 nexus-default.properties ## DO NOT EDIT - CUSTOMIZATIONS BELONG IN $data-dir/etc/nexus.properties ## # Jetty section application-port=8087 application-host=0.0.0.0 nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-http.xml,${jetty.etc}/jetty-requestlog.xml nexus-context-path=/ # Nexus section nexus-edition=nexus-pro-edition nexus-features=\ nexus-pro-feature nexus.hazelcast.discovery.isEnabled=true 如需修改nexus工作目录的 直接配置环境变量 JENKINS_HOME 到指定目录,重新初始化jenkins即可,以免C盘爆盘 完成后启动nexus 1、权限管理 新建角色DEV 给予上诉连个权限就可以了 2、新建仓库 将常用的公共库都创建,请选择 maven2(proxy) 这里我们使用maven-public 统一管理各种公共资源 如果需要上传本地包 选择maven-releases上传即可 到此 nexus 私有仓库配置完成 下面讲下 maven setting.xml 配置使用私有仓库 <?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.

C++数据结构之线性表——顺序表

一、线性表 概念 1.线性表是最简单的一类线性数据结构 2.线性表是由n个数据元素组成的有限序列,相邻数据元素之间存在着序偶关系,可以写成: (a1, a2,…ai-1, ai, ai+1,…an-1, an) 其中,ai是表中元素,i表示元素ai的位置,n是表的长度 特性 线性表中的元素具有相同的特性,属于同一数据对象,如: 1.26个字母的字母表: (A,B,C,D,…,Z) 2.近期每天的平均温度:(30℃, 28℃, 29℃,…) ADT定义 ADT List { 数据对象:数据元素同属一个集合 数据关系:序偶关系 基本操作: Init创建、Destroy销毁、 Clear清空、Empty是否为空、 Length取表长度、Get取表元素、Locate查找元素 Prior取元素前驱、Next取元素后继 Insert插入元素、Delete删除元素 Traverse遍历表 } 二、顺序表 概念 i.顺序表的构成 1.顺序表是线性表的顺序存储表示 2.顺序表采用一组地址连续的存储单元依次存储线性表的数据元素 ii.顺序表的元素位置 顺序表数据元素的位置: location(a_i) = location( a_(i-1) ) + l location(a_i) = location(a_1)+(i-1)*l ( l表示元素占用的内存单元数 ) 举例: 一个线性表第一个元素的存储地址是100,每个元素的长度为2,则第5个元素的地址是( ) (A)110 (B)108(C)100 (D)120 根据上面的元素位置公式我们可以知道第五个元素的位置location(a_5)=100+(5-1)*2=108,故选B 实现 顺序表类 #define initsize 100//初始化表的存储容量 #define sizeincrease 10//单次增加容量的大小 class sqlist { public: int length;//顺序表的当前长度 int listsize;//为顺序表分配的储存空间大小 int *element;//指向顺序表的第一个元素(即存储空间基址) int initelement[initsize];//顺序用于表初始化后的各个存储单元的初始值 void init();//创建顺序表 void destroy();//销毁顺序表 void clear();//清空顺序表 bool empty();//检测是否为空 int getlength();//获取顺序表的长度 int get(int index);//获取下标为index的元素 int locate(int ele);//查找元素ele所在位置的下标 int prior(int index);//取下标为index的元素的前驱元素 int next(int index);//取下标为index的元素的后继元素 void insert(int ele,int index);//在下标为index的元素位置插入元素ele,原位置的元素依次后移一位 void remove(int index);//删除下标为index的元素,下标index后的元素依次向前移动一位 void traverse();//遍历表 void print();//打印表 void push(int ele);//从表尾插入元素 void batchpush();//批量压入数据 }; 初始化顺序表 void sqlist::init() { element=(int*)malloc(initsize*sizeof(int));//分配内存大小为initsize的空间 for (int i = 0; i < initsize; i++)//将各存储单元的初始值赋值给initelement[] { initelement[i]=element[i]; } if (!

TCP&UDP

TCP:面向连接的服务,可靠的进程到进程的通信协议。(因为TCP里面封装了端口号,端口号就意味着一个服务,进程);应用场景:如:文件传输;HTTP应用层协议 UDP:无连接服务、不可靠的传输协议; 应用场景:广播;早期的QQ,视频传输等, ACK:标识确认序号是否有效;TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送报文的 ACK 必须为1.SYN:请求建立连接,含有 SYN 标识的报文称为同步报文段。当 SYN = 1,ACK = 1时则表示对方同意连接。FIN:当FIN = 1时,表明结束报文段的发送方不再发送数据,请求释放单向连接。SYN-SENT:同步已发送状态SYN-RCVD:同步收到序列号:TCP 将每个字节的数据都进行了编号, 即为序列号确认序列号:每一个 ACK 都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据;下一次你要从哪里开始发。FIN-WAIT-1:终止等待1;FIN-WAIT-2:终止等待2;TIME-WAIT状态:TCP 协议规定,主动关闭连接的一方要处于 TIME-WAIT 状态,等待 2*MSL 的时候后才能回到 CLOSE 状态。LAST-ACK:最后确认状态;CLOSE-WAIT:关闭等待状态; 三次握手: 客户端发送连接请求报文给服务端,SYN = 1,seq = x(初始序列号),发送后客户端进入SYN - SENT(同步发送)状态。TCP规定, SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。服务器收到请求报文后,若同意则发出确认报文。确认报文 ACK = 1,SYN = 1,确认序号为x+1,同时初始化序列号 seq=y,之后服务器进入 SYN-RCVD(同步收到)状态。客户端接收到报文后,发送确认报文,其中ACK=1,确认序列号:ack=y+1。自己的序列号:seq:x+1 发送完客户端进入ESTABLISHED状态,服务端接收到报文后,进入ESTABLISHED状态。到此,连接建立完成。 ?问:为什么不是2次握手? 为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤 如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认 四次挥手 客户端进程发出断开连接报文,并停止发送数据。其中:FIN = 1,序列号为 seq = u (等于之前已经传送的数据序号+1),此时客户端进去 FIN - WAIT-1(终止等待1)状态。TCP 规定,FIN 报文段即使不带数据,也要消耗一个序号。 服务器收到连接释放报文,发出确认报文,ACK =1,确认序号ack=u+1,自己序列号:seq=v。服务器->CLOSE-WAIT(关闭等待)状态。这个时间段,客户端没有数据发送了,若服务器还有数据,客户端依然要接受,这个状态就是CLOSE-WAIT的时间段。

一文了解如何在window上轻松实现多进程任务

参考 苏神写的parallel_apply link python中multiprocessing文档 link 前言 在之前的工作中,我经常使用的多进程方式是进程池,在看了苏神写的parallel_apply之后,发现多进程使用队列的方式运行,从显示上(tqdm显示运行进度),灵活性上都更加好 经过更深入的使用之后,我发现其实进程池也可以比较灵活的传递参数。然而,在运行时发现多进程在windows上的支持很不友好,于是打算写一篇在windows上容易使用的多进程方法,当然也可以在linux上使用。 使用多进程来提高程序的运行效率是非常重要的,通常可以在数据处理,矩阵运算等方面应用。 进程在windows上使用的注意点 1.必须得保证你要使用多进程处理的程序是可序列化的,即可以转换为可存储或传输的形式,如generator就是不可序列化的形式,因此想要对jieba分词使用多进程就是不可行的 2.多个进程之间是独立的,所以想在多个进程中更新同一个类属性是不可行的,除非是使用multiprocessing中带的Array,List等方法,并将这些变量作为输入传入到进程中去,不过这个方法我并没有尝试过。 3.每个进程使用的函数都是一次性的,因此若是传入的类函数中,初始时赋值了变量,则这个变量在每一次运行时都会执行,若这个赋值变量的运行时间很长,则会导致使用多进程甚至比单独执行更慢,以下是例子: import json class myClass: def __init__(self): with open(file_name, 'r', encoding='utf-8') as f: self.data = json.load(f) def forward(self, idx): return self.data[idx] 上述例子中,初始化__init__函数中,需要载入数据来执行forward函数,这种情况下将foward放入多进程中,会极大的影响效率,甚至比单独执行更慢。 4.在if __name__ == '__main__'或者函数中设定的全局变量无法在多进程中使用,因为如果子进程中的代码尝试访问一个全局变量,它所看到的值(如果有)可能和父进程中执行 Process.start 那一刻的值不一样。例子如下: import json from multiprocessing import Pool def forward(idx): return data[idx] if __name__ == '__main__': global data with open(file_name, 'r', encoding='utf-8') as f: data = json.load(f) with Pool(6) as pool: pool.

uni-app开发时对ios底部安全区域的控制

对于ios来说,底部安全区域 仅App端支持 manifest.json 文件下 源码视图 app-plus添加节点 safearea 设置背景色 "safearea": { "background": "#FFFFFF", //背景色 "bottom": { "offset": "auto" } } 不设置背景色 "safearea": { "bottom": { "offset": "auto" } } 兼容小程序 app.vue文件 page { padding-bottom: constant(safe-area-inset-bottom);/*兼容 IOS<11.2*/ padding-bottom: env(safe-area-inset-bottom); /*兼容 IOS>11.2*/ } 注意:env()和constant()需要同时存在,且顺序不能调换 名称解释: 获取上安全距离: env(safe-area-inset-top) 获取左安全距离:env(safe-area-inset-left) 获取右安全距离:env(safe-area-inset-right) 获取下安全距离:env(safe-area-inset-bottom)

2021CCPC黑龙江省赛题解ADFHIJKL

2021CCPC黑龙江省赛题解ADFHIJKL K. Keep Eating 题意 有 n ( 1 ≤ n ≤ 2 e 5 ) n\ \ (1\leq n\leq 2\mathrm{e}5) n (1≤n≤2e5)块蛋糕,重量分别为 a 1 , ⋯ , a n ( 1 ≤ a i ≤ 1 e 6 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}6) a1​,⋯,an​ (1≤ai​≤1e6).每次某人只能吃不超过当前蛋糕的重量的一半的重量,且他不吃重量小于 k ( 2 ≤ k ≤ 1 e 6 ) k\ \ (2\leq k\leq 1\mathrm{e}6) k (2≤k≤1e6)的蛋糕.此外,他可合并两块蛋糕,合并的蛋糕的重量等于原来两蛋糕的重量之和.求他最多能吃多少蛋糕. 思路 先将所有蛋糕拼在一起,设总重量为 s u m sum sum.

WPF Xaml格式化工具

VStudio首页点击扩展、管理扩展 管理扩展窗口 联机中搜索xaml styler 找到如图中所示的扩展进行下载 关闭软件后会进行安装 点击Modify 安装完成页面 在Xaml代码界面右键选中第一个菜单,即可按照默认选项格式化Xaml 若要对格式化要求进行管理 下载文件:链接:百度网盘 请输入提取码 提取码:u4dv 1.下载解压,把Settings.XamlStyler这个文件放在解决方案同级 2.在VS里面点击 工具->选项->XAML Styler->External configuration file 在这个里面填入Settings.XamlStyler 注意:可以用VS Code打开Settings.XamlStyler这个文件编辑,文件格式选择 JSON with Comments,可以比较好区分注释。 点击纯文本 选择文件格式 打开效果图

解决java与python整合过程的问题-执行python问题报错

import org.python.util.PythonInterpreter; import java.io.DataInputStream; import java.util.Properties; public class a { public static void main(String[] args) throws Exception{ Properties props = new Properties(); props.put("python.home", "D:\\jython2.7.2\\software\\Lib"); props.put("python.console.encoding", "UTF-8"); props.put("python.security.respectJavaAccessibility", "false"); props.put("python.import.site", "false"); Properties properties = System.getProperties(); PythonInterpreter.initialize(properties, props, new String[0]); PythonInterpreter interpreter = new PythonInterpreter(); interpreter.exec("print('hello')"); //当python文件中使用了 import 并调用了第三方库 执行以下命令就会报错 //interpreter.execfile("F:\\graduate\\pro\\src\\main\\java\\p1.py"); fun(); } //此方法解决了python文件含有import 进入第三方库的问题 public static void fun() throws Exception{ String exe = "python"; String command = "F:\\graduate\\pro\\src\\main\\java\\p1.py"; String[] cmdArr = new String[] {exe,command}; Process process = Runtime.

nodeJS中调用exe文件

背景 由于不同语言各有优势,所以有时候会用不同的语言去写不同的脚本,这次写的软件中涉及到爬虫的部分用python写的,主程序用electron+vue的方式写的,所以使用了child_process来调用python打包的exe 方法 node中有一个child_process可以用来创建子进程,这里我就用该功能进行exe的调用,具体方法如下 const cp = require('child_process') let child = cp.spawn('./exename.exe',[param]) child_process有多种调用方法,详情见:node文档的child_process部分 异步进程的创建 在 Windows 上衍生 .bat 和 .cmd 文件 child_process.exec(command[, options][, callback]) child_process.execFile(file[, args][, options][, callback]) child_process.fork(modulePath[, args][, options]) child_process.spawn(command[, args][, options]) options.detached options.stdio 同步进程的创建 child_process.execFileSync(file[, args][, options]) child_process.execSync(command[, options]) child_process.spawnSync(command[, args][, options]) 常用的主要事件如close等,可以直接用on监听如: child.on('close',(res)=>{}) 监听返回值,返回值要进行fromCharCode解码 child.stdout.on('data',(data)=>{ for (var i = 0; i < data.length; i++) { exeMsg += String.fromCharCode(data[i]); } 不过对于从子进程中获取实时返回值,我多次尝试无效,后来只能采用临时文件的方式进行处理,可以在如下的案例中看出 案例 在我的案例中 const cp = require('child_process') let child = cp.

Codeforces Round #775 (Div. 2) ABCDE题解

A-Game 题目大意: 一条直线上有若干个点,每个点有两种情况: land 可以经过water 不能经过 每次只能移动一个距离,如果下一个是land,就可以到下一个land上,花费为0。 最多可以使用一次跳跃,从一个landi跳到另一个landj,花费为j-i+1。 起点为1,输入保证起点和终点都是land,问最小的花费为多少。 思路: 因为只能使用一个跳跃,因此找出左侧和右侧连续land的边界,然后从边界进行跳跃的花费是最小的。 AC代码: #include <bits/stdc++.h> const int N = 1e2 + 5; using namespace std; int loc[N]; void solve() { int n, l, r; cin >> n; l = 1, r = n; for (int i = 1; i <= n; i++) cin >> loc[i]; while (r >= 2) { if (loc[r - 1] == 1) r--; else break; } while (l < r) { if (loc[l + 1] == 1) l++; else break; } cout << r - l << "

在 HTML canvas 绘制文本

绘制文本有两种方式: fillText(text, x, y)strokeText(text, x, y) 下面,我们来看看如何在 canvas 上绘制文本。 我们先创建一个 canvas 标签,并设置基本的宽高: <canvas width="200" height="400"></canvas> 首先,获取对画布的引用: const canvas = document.querySelector('canvas') 并从中创建一个上下文对象: const ctx = canvas.getContext('2d') getContext() 方法根据作为参数传递的类型返回画布上的绘图上下文。 有效值为: 2d 二维渲染上下文 webgl 使用 WebGL 版本 1 webgl2 使用 WebGL 版本 2与 ImageBitmap 一起使用的 bitmaprenderer 点击此处查看详细内容。 现在我们可以调用 ctx 对象的 fillText() 方法: ctx.fillText('Hello, Canvas!', 100, 100) fillText 方法的后两个参数分别为 x 和 y 的坐标。 在调用 fillText() 之前,还可以传递其他属性来自定义外观,例如: ctx.font = 'bold 20pt Menlo' ctx.fillStyle = '#ccc' ctx.

各种卷积方式的最全讲解

文章目录 一:卷积的定义二:标准卷积1.1D卷积Ⅰ:一维Full卷积Ⅱ:一维Same卷积Ⅲ:一维Valid卷积Ⅳ:三种一维卷积的相互关系 2.2D卷积3.3D卷积 三:转置卷积四:Separable卷积五:Depthwise卷积六:Pointwise卷积七:扩张/空洞(Dilated/Atrous)卷积 一:卷积的定义 首先,我们首先回顾一下卷积相关的基本概念,定义一个卷积层需要的几个参数。 卷积核大小(Kernel Size):卷积核大小定义了卷积的视野。2维中的常见选择是3 - 即3x3像素矩阵。 步长(Stride):步长定义遍历图像时卷积核的移动的步长。虽然它的默认值通常为1,但我们可以使用值为2的步长来对类似于MaxPooling的图像进行下采样。 填充(Padding):填充定义如何处理样本的边界。Padding的目的是保持卷积操作的输出尺寸等于输入尺寸,因为如果卷积核大于1,则不加Padding会导致卷积操作的输出尺寸小于输入尺寸。 输入和输出通道(Channels):卷积层通常需要一定数量的输入通道(I),并计算一定数量的输出通道(O)。可以通过I * O * K来计算所需的参数,其中K等于卷积核中参数的数量,即卷积核大小。 二:标准卷积 1.1D卷积 一维卷积通常有三种类型:full卷积、same卷积和valid卷积,下面以一个长度为5的一维张量I和长度为3的一维张量K(卷积核)为例,介绍这三种卷积的计算过程。 Ⅰ:一维Full卷积 Full卷积的计算过程是:K沿着I顺序移动,每移动到一个固定位置,对应位置的值相乘再求和,计算过程如下: Ⅱ:一维Same卷积 Same卷积核K都有一个锚点,然后将锚点顺序移动到张量I的每一个位置处,对应位置相乘再求和,计算过程如下: Ⅲ:一维Valid卷积 valid卷积只考虑I能完全覆盖K的情况,即K在I的内部移动的情况,计算过程如下: Ⅳ:三种一维卷积的相互关系 2.2D卷积 2D卷积是最常见的卷积,在计算机视觉中大量使用,在此不再赘述。如下图所示: 3.3D卷积 在3D卷积中,kernel可以在3个方向上移动,因此获得的输出也是3D。 三:转置卷积 有些场景下使用deconvolution,这中说法其实不太合适,因为它不是一个deconvolution,真正的deconvolution应该是卷积操作的逆过程。虽然deconvolution确实存在,但它们在深度学习领域并不常见。想象一下,将图像输入到单个卷积层。现在获得输出,把输出扔到一个黑盒子里,再恢复成的原始输入图像。这个黑盒子才叫做deconvolution。Deconvolution是卷积计算过程的逆计算过程。 转置卷积则比较贴切,因为转置会产生相同的空间分辨率。然而,真实执行的数学运算则稍有不同的。转置卷积层一方面会执行常规卷积,同时也会恢复其空间变换。在执行转置卷积上采样的操作时,要注意棋盘效应 有关转置卷积的讲解,可以看这篇文章 四:Separable卷积 其实就是将filter的K×K×Channel中的Channel(等于输入特征图深度)变为了自己随意设定(当然要小于等于Channel)。 五:Depthwise卷积 它的意思就是拓展Separable convolution而来,我们可以让卷积核的channel维度等于1啊,这样就是深度卷积,意为在每一个channel上做卷积。 六:Pointwise卷积 其实就是点积,就是卷积核大小是1*1的,那为啥起名点积呢?就是因为这和向量中的点积运算很类似。 七:扩张/空洞(Dilated/Atrous)卷积 空洞卷积是解决pixel-wise输出模型的一种常用的卷积方式。一种普遍的认识是,pooling下采样操作导致的信息丢失是不可逆的,通常的分类识别模型,只需要预测每一类的概率,所以我们不需要考虑pooling会导致损失图像细节信息的问题,但是做像素级的预测时(譬如语义分割),就要考虑到这个问题了。那么空洞卷积可以用下图来说明: (a)图对应3x3的1-dilated convolution,就是典型的卷积(b)图对应3x3的2-dilated convolution,实际的卷积kernel size还是3x3,但是空洞为1,相当于kernel的size为7x7,图中只有红色点的权重不为0,其余都为0,把3*3的感受野增大到了7*7。(c)图是4-dilated convolution,能达到15x15的感受野。 总之,空洞卷积是卷积运算的一种方式,在于增大了感受野却不丢失语义信息。 至此我对深度学习中不同的卷积类型进行了简单讲解,希望对大家有所帮助,有不懂的地方或者建议,欢迎大家在下方留言评论。 我是努力在CV泥潭中摸爬滚打的江南咸鱼,我们一起努力,不留遗憾!

matplotlib隐藏坐标轴

matplotlib隐藏坐标轴 # 法一: plt.gca().get_xaxis().set_visible(False) plt.gca().get_yaxis().set_visible(False) # 法二: plt.xticks([]) plt.yticks([]) # 法三: plt.axis('off') 不隐藏坐标轴图示如下: 第一二个方法效果相同,图示如下: 法三图示如下:

Flutter简易弹窗

高温限电,疫情防控,一波未平,一波又起。 学习是不可能学习的,只能在居家摸鱼才能勉强维持生活这样子。 Flutter中有集成的弹窗方法,大致是这样: void showPopup() { showModalBottomSheet( context: context, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)), builder: (BuildContext context) { return Container( color: Colors.amber, child: Column( children: [ ElevatedButton(onPressed: () {}, child: Text("1")), ElevatedButton(onPressed: () {}, child: Text("2")), ], ), ); }); } 效果大致如下: 就是使用showModalBottomSheet或类似的API,但相对来说可定制的参数较少,比如较为重要的位置是难以控制的,而且也不美观。 当然,不自由的组件很难美观起来。 所以想办法自定义一下。 自定义也简单,看看showModalBottomSheet的源码,依葫芦画瓢改改就行,大多自定义API都可以这么干。 而showModalBottomSheet的源码是这样的: Future<T?> showModalBottomSheet<T>({ required BuildContext context, required WidgetBuilder builder, Color? backgroundColor, double? elevation, ShapeBorder? shape, Clip? clipBehavior, BoxConstraints? constraints, Color? barrierColor, bool isScrollControlled = false, bool useRootNavigator = false, bool isDismissible = true, bool enableDrag = true, RouteSettings?

NDT点云配准

NDT算法介绍 NDT正态分布点云算法,即Normal Distribution Transform,是将参考点云转换成多维变量的正态分布来进行配准。如果变换参数能够使得两幅激光数据匹配得很好,那么变换点在参考点云中对应的概率密度将会很大。因此,要使得两幅激光点云数据匹配最优,只需用优化方法迭代计算使得概率密度之和最大的转换矩阵。 现实中,LiDAR扫描得到的点云可能和参考点云(如高精地图点云)存在细微的区别,此偏差可能来自于测量误差,也有可能是“场景”发生了一下变化(比如说行人,车辆)。NDT配准可以忽略细微变化,因此可用于解决这些细微的偏差问题。同时,NDT相对与ICP,它耗时稳定,跟初值相关不大,初值误差大时,也能很好得纠正过来。计算正态分布是个一次性的工作,因为其在配准中不利用对应点的特征计算和匹配,不需要消耗大量代价计算最邻近点,所以时间较快。 NDT算法流程 NDT公式推导 NDT算法的基本思想是先根据参考数据(reference scan)来构建多维变量的正态分布,如果变换参数能使得两幅激光数据匹配的很好,那么变换点在参考系中的概率密度将会很大。因此,可以考虑用优化的方法求出使得概率密度之和最大的变换参数,此时两幅激光点云数据将匹配的最好。 NDT缺点:格子参数最重要,太大导致精度不高,太小导致内存过高,并且只有两幅图像相差不大的情况才能匹配。 改进: 八叉树建立,格子有大有小 ,迭代,每次使用更精细的格子K聚类,有多少个类就有多少个cell,格子大小不一三线插值 平滑相邻的格子cell导致的不连续,提高精度 NDT代码实战 #ifdef USE_FAST_PCL #include <fast_pcl/registration/ndt.h> #else #include <pcl/registration/ndt.h> #endif #ifdef CUDA_FOUND #include <fast_pcl/ndt_gpu/NormalDistributionsTransform.h> #endif ...........核心算法代码,构建地图使用ndt算法 static std::shared_ptr<gpu::GNormalDistributionsTransform> new_gpu_ndt_ptr = std::make_shared<gpu::GNormalDistributionsTransform>();//创建NDT转换矩阵类 new_gpu_ndt_ptr->setResolution(ndt_res);//网格大小设置 new_gpu_ndt_ptr->setInputTarget(map_ptr);//参考帧 new_gpu_ndt_ptr->setMaximumIterations(max_iter);//迭代最大次数 new_gpu_ndt_ptr->setStepSize(step_size);//牛顿法优化的最大步长 new_gpu_ndt_ptr->setTransformationEpsilon(trans_eps);//连续变换之间允许的最大差值 pcl::PointCloud<pcl::PointXYZ>::Ptr dummy_scan_ptr(new pcl::PointCloud<pcl::PointXYZ>()); pcl::PointXYZ dummy_point; dummy_scan_ptr->push_back(dummy_point);//构建地图map new_gpu_ndt_ptr->setInputSource(dummy_scan_ptr);//当前帧 new_ndt.omp_align(*output_cloud, Eigen::Matrix4f::Identity()); fitness_score = ndt.omp_getFitnessScore(); t = ndt.getFinalTransformation(); // Update localizer_pose localizer_pose.x = t(0, 3); localizer_pose.y = t(1, 3); localizer_pose.z = t(2, 3); .

Codeforces Round #777 (Div. 2) ABCD题解

A-Madoka and Math Dad 题目大意: 一个十进制数字(不含0),各个位上的和为n(n<=1000),且相邻位没有相同的数字,问这个数字最大可以是多少。 思路: 显然要使这个数字最大的话,只能包含1和2。由于最后的数字会非常大,所以只能用字符串来存储。 有两种做法,一种是直接构造,一种是dp。 1.直接构造: 最后的数字形式一定是中间有一大串12,根据n%3的结果决定在开头加2还是在结尾加1或是不加。 2.dp做法: dp[i][j]表示各位和为i,最后一位数字为j时的最大数字,状态转移方程为: dp[i+k][3-j] = max(dp[i][j] + k, dp[i+k][3-j]) dp代码: #include <bits/stdc++.h> const int N = 1e3 + 50; using namespace std; string dp[N][3]; string digit[3] = {"0", "1", "2"}; string smax(string a, string b) //自定义字符串比较函数 { if (a.size() != b.size()) return a.size() > b.size() ? a : b; return max(a, b); } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); for (int i = 0; i <= 1000; i++) { for (int j = 0; j <= 2; j++) { if (j > i) break; for (int k = 1; k <= 2; k++) { if (k == j) continue; dp[i + k][k] = smax(dp[i][j] + digit[k], dp[i + k][k]); } } } int T; cin >> T; while (T--) { int n; string ans; cin >> n; for (int i = 1; i <= 2; i++) ans = smax(ans, dp[n][i]); cout << ans << "