kubernetes 调度器

Predicates and Priorities scheduling Scheduler Extender Multiple Schedulers Scheduling Framework 流程 Framework的调度流程是分为两个阶段: scheduling cycle和binding cycle scheduling cycle是同步执行的,同一个时间只有一个scheduling cycle,是线程安全的binding cycle是异步执行的,同一个时间中可能会有多个binding cycle在运行,是线程不安全的 策略 架构 采样

JS判断是否为素数

function isPrime(num1) { var isSu = true; //表示是否为素数 假设是素数 // 排除1 和 0 if (num1 == 0 || num1 == 1) { isSu = false; } // 判断一个数是否为素数 (又叫质数,在大于1的自然数中,除了1和它本身以外不再有其他因数。即只能被1和它本身整除的数就是素数) for (var i = 2; i < num1; i++) { // 如果能整除说明不是素数 if (num1 % i == 0) { // 通过2以上的数字不断和目标数字求余数,如果能得到0,就表示这是一个合数而不是质数. isSu = false; //改为false break; } } if (isSu == true) { return num1 + '是素数'; } else { return num1 + '不是素数'; } } var num = prompt("

sRGB标准与伽马校正 理解

srgb : 颜色值会以非线性的方式存储 如一个颜色值在线性空间中,rgb=(1,1,1), 在gamma空间中,rgb会变为(1的2.2幂次,1的2.2幂次,1的2.2幂次),颜色值会发生改变,这样方便在显示器中显示的时候,正确显示(因为在显示器中显示时,会使得图像变暗) 如果一个图片的颜色格式为srgb,则说明这张图片存储的颜色值是encode gamma之后的颜色值 在unity中设置为gamma空间时,图片颜色值会在导入时变成非线性的颜色值 srgb标准是图片颜色值固定按照2.2分之一(0.45)次幂的颜色变化 所有显示器硬件在进行颜色值的转换时固定按照2.2次幂来对颜色值进行转换 对渲染的意义 渲染中用到的光照都是在线性空间的。所以所有的计算都需要转换到线性空间计算 下面时参考文章: sRGB标准与伽马校正 sRGB标准 人眼对亮度的感知不是线性的,其对较暗区域的变化更加敏感 参见:Computer Color is Broken 基于人眼该特点,sRGB标准要求图像(各通道为8bits,最多存储256个亮度值)使用编码伽马,把更多地空间用来存储更多暗部区域,来最大化地利用表示亮度的数据位或带宽 伽马校正(Gamma correction) 在早期,阴极射线管(CRT)显示器是唯一的电子显示设备,但它的输入电压和显示出来的亮度关系不是线性的,而是一个类似幂律(pow-law)曲线的关系,使得信号被压暗 巧合地是,sRGB标准的编码伽马是一个将图像变亮的幂率曲线,正好与其形成互补,使得不需要再做调整就可以让sRGB图像在CRT上显示出与现实场景一致的亮度 后来出现的LCD和等离子显示器,为了保证兼容,在硬件上也都选择了和当年CRT一样的非线性特性 类似于sRGB标准的编码伽马(encoding Gamma),由于能校正CRT的显示伽马(display Gamma,标准值 γ = 2.2),因此又被称为伽马校正(Gamma correction) 对渲染的意义 渲染中用到的光照都是在线性空间的。因为在设计光照的时候都是认为1的亮度是0.5的2倍 光照如此,texture又如何呢?渲染中用到的 texture一般有两个来源,一个是照片,一个是artist手工画的 前文提到了,照片是gamma = 1/2.2的。一般图象处理软件也都是在gamma空间工作的,所以artist画的图一般也可以认为是gamma = 1/2.2的 所以,我们在pixel shader常可以见到这样的代码: float4 diff = tex2D(diffuse_texture, uv); return diff * max(0, dot(light_dir, normal)); 这样的代码对吗?不对也对。 说其不对,是因为这里没显式地做gamma校正。做校正的话应该是这样的: float4 diff = pow(tex2D(diffuse_texture, uv), 2.2f); // 对输入的纹理进行display gamma,转到线性空间 return pow(diff * max(0, dot(light_dir, normal)), 1 / 2.

比较两个具有相同属性的对象,判断内容是否相同

今天遇到一个需求,需要将页面传递的值和数据库里的参数进行比较,判断是否进行过修改,因为页面涉及到多个表的数据,字段非常多,if-else非常不合适,所以查找学习了一下 实现的方式: public boolean compareTwoObject(Object class1, Object class2) { // 获取对象class Class<?> clazz1 = class1.getClass(); Class<?> clazz2 = class2.getClass(); // 获取类中所有声明的字段 Field[] fields1 = clazz1.getDeclaredFields(); Field[] fields2 = clazz2.getDeclaredFields(); // 遍历 for (int i=0;i<fields1.length;i++) { for(int j=0;j<fields2.length;j++) { /*简单比较,如果两字段名称一致,就认为是同一个字段 ,默认考虑字段定义的类型一致*/ if(fields1[i].getName().equals(fields2[j].getName())){ // 将字段设置成可通过反射访问 fields1[i].setAccessible(true); fields2[j].setAccessible(true); // 比较内容 if(!compareTwo(fields1[i],fields2[j])) { // 有修改 return false; } // 当前字段名称已经找到,直接终止最内层for循环,开始下一轮字段的匹配 break; } } } } private boolean compareTwo(Object object1, Object object2) { // 如果两字段都为空,也认为相等 if (object1 == null && object2 == null){ return true; } // 视情况而定,正常页面表单没有填写数据,传到后台时是null // 但同一条信息,数据库里应该存的是"

WinEdt 10.3 Registration

Registration Location: 工具栏 Help — Regist WinEdt…Sequence Code: Name: Cracker TeCHiScy Code: 1130140925535334280 走着走着,花就开了,耕耘的年纪,但问耕耘,莫问收获!

【原创-更新完毕】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载1

【原创】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载2_zhuyi8120的博客-CSDN博客 【原创】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载3_zhuyi8120的博客-CSDN博客 【原创】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载4_zhuyi8120的博客-CSDN博客r 【原创】|源码全文-日历拼图游戏的解决方案(C语言-进阶应用)-详解连载5_zhuyi8120的博客-CSDN博客 后续的链接见上。 问题提出: 日历拼图是一款拼图玩具。见图1所示。 图1:日历拼图(未排列之前) 图2:今天(12月6日)的日历拼图 在7×7的方格中,去掉2+4个格子,用8块不同形状的积木进行拼图,再留出2个格子表示月份和日期。因为每天所留下的空格不一样,相当于每天都要拼一次,单纯人工去拼是有一定难度的(也正是有一定难度,才吸引一些爱好者去玩)。 方案运行的结果: 本文使用C语言,运用数组表示格点,使用指针链进行搜寻满足要求的拼法。结果如下图所示(无图形界面)。 图3:求12月6日拼图的运行结果 问题分析: (对于完成一个解决方案,前期对问题进行较完善的分析要比看到一个问题就直接写代码的方式要好很多,这是磨刀不误砍柴功。) 1、拼图底盘(以下简称底盘)有43个点,采用数组表示各节点。这是一种常规的做法,适合于解决当前问题。 2、以'-'表示空节点,这样做,相对于用空格(' ')来表示,效果比较好。因为空格有时候难以辨认。 3、根据8种方块的特点,因为长和宽都没有超过4格的,所以,可采用4×4的方格来表示。 4、注意到对于一个普通的不规则方块来说,是有8种不同的表现形式。分别是每旋转90度就是一种新形式,不翻面就有4种;在翻面之后,又有另外4种。这些会在初始化阶段完成。 5、同时也要注意到,在本游戏的这8个方块里面,其中有4种是有8种变化形式的,有3种是有4种变化,而那个3×2的方块,是只有2种变化形式的。分析到这点,对于减少后期尝试的次数有很大帮助。简化后较不作简化的方式,可以节省15/16的搜寻空间(2×2×4)。 6、在7×7的格子里,按4×4满排来计算,初始坐标为(0,0)的话,可以从(0,0)开始,向(3,3)的4×4个格子里逐个搜寻就可以了。但实际上,我们可以看到,只有一个方块的长边是有4个格子的,其他7个的长边都是只占3个格子。因此针对不同的方块要表示出他们特有的搜寻空间。以最简单的3×2方块来说,横放时的搜索空间为从(0,0)到(4,5),共需搜寻30个格子;竖放时,是从(0,0)到(5,4),虽然也是30个格子,但有几个格子是不一样的。 图4:不同变体的搜寻范围不一样 这就要求对不同的方块的不同变体要做一个标识。 7、每个方块在初始时,都会设置在左上角,这样对搜寻是很有好处的。但我们在进行旋转和翻面时,容易出现不在左上角的情况。 图5:在旋转时,出现不在左上角的情形 当图形不在左上角的时候,对搜寻是会有难度的。主要体现在初始点不容易确定。如图中的右图,以(0,0)为初始搜寻是可能会遗漏的。这就需要进行适合的规整化处理,以便于搜寻的正常进行。 8、判断一个方块是否可以放入,这个比较容易。前面我们提到了用‘-’来表示空格,然后,我们可以用不同的字母来表示(上面两图已经有用不同的字母表示不同的方块)。当底盘的某一格是空格(‘-’)时,而新加入的方块为实体(有字母)时,就表示可以加入;如果新加入的方块中有一个格是有字母的,而底盘原来也已经有字母了,这形成了一个“冲突”,就说明不能加入了,要换另一个地方放这个方块了。 图6:不能再插入方块F的例子 9、把可以加入的方块插入底盘也是比较容易的。就是把底盘的空格(‘-’)更新为字母。 图7:可以插入方块H的例子 10、如何判断一个方块不能插入底盘,这是一个难点。 首先,我们可以分析,如果在搜寻范围里(第6点提到)都搜寻过了,出现了冲突(第8点的情况),那就说明不能插入。 其次,如果简单的用搜寻到最后一个单元格来判断,是没法做到的。因为,可能最后一个就刚好是合适的(比如满足要求的排法最后一个就是合适的)。 所以,要想个合适的方式来进行判断。最后我选择了冲突次数的方式来判断。 11、当能够判断在某一种排法里,所有的可能都已经尝试过了,要进行回调时,如何处理。我一开始是打算用图示的方式来解决的,但我没想到可行的方式(或许有更好的方式可以,但我不知道)。最后,我还是选择了用指针和链表来实现。 附:笔者的尝试: 自2021年11月27日(星期五)开始尝试写代码,到2021年12月4日中午总算完成。这是当时完成的截图(尝试了211万多次)和拼好的拼图。

Vscode插件合集

一、汉化vscode 二、代码格式化 三、光标跳到{}外 四、快速生成一个本地服务器 五、快速生成头部注释(ctrl+alt+i) 六、快速生成函数注释(ctrl+alt+d) 七、自动修改标签(修改前标签名,后标签名自动更改) 八、自动检测代码格式 九、高亮匹配标签 十、快速添加删除console ctrl + alt + l 选中变量之后,使用这个快捷键生成 console.log alt + shift + c 注释所有 console.log alt + shift + u 启用所有 console.log alt + shift + d 删除所有 console.log 十一、快速生成react代码片段 十二、自动引入react 组件 注意: 第一次需要自己引入一次,不然没有提示; 十三、单词拼写检测

ARP-三方欺骗-打挂你舍友的IP

好久好久没发过帖子啦 只皆因有些懒 又但了好久的白嫖党··· Arp欺骗搞协议的可能对这一块比较熟悉 也是用了这个特性做了个Arp欺骗的小工具 Linux可运行哈 分为A B C三者 A作为本机 B作为C者的“白名单” (想不到形容词了) C作为A发起欺骗的目标 作用 1、可突破A者白名单限制 2、可将B者踢下线 只是个demo 大家也可以完善一下哈 比如增加收包 A回应B的请求 做一个协议的截断等等等 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/ioctl.h> #include <net/if.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #include <net/ethernet.h> #include <unistd.h> //获取本机MAC地址,存入mac数组中,要求传入网卡名字 int getMacAddr(unsigned char mac[], const char name[]) { struct ifreq ethinfo; int sock_fd; if (name == NULL || mac == NULL) { return -1; } if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("

用matplotlib.pyplot绘图

import matplotlib.pyplot as plt import numpy as np # x = [4 * np.pi * i / 100 for i in range(100)] # y = [math.cos(i) for i in x] x = np.arange(0, 4 * np.pi, 0.1) y = np.cos(x) plt.figure("tk") # 命名绘图窗口 plt.xlabel("x") plt.ylabel("y") plt.plot(x, y) plt.text(4, 1, "y=cos(x)") # 在(4, 1)的位置添加注解 plt.show() import numpy as np import matplotlib.pyplot as plt def f(t): return np.exp(-t) * np.sin(2 * np.

C++基础(C++Primer学习)

C++基础(四) C++的类(接上部分) 思考:之前写的代码风格不好。按照习惯来说,应该把类函数地声明放在类地内部,但是定义放在cpp文件当中,而类地声明则放在头文件当中,这样使得代码看起来更加整齐,结构清晰。 从这一节笔记开始,已经从C++Primer转战C++PrimerPlus了😁。 一、创建一个新的类 1、在头文件中创建一个新的类 class Stock { private: std::string company; long shares; double share_val; double total_val; void set_total() { total_val = shares * share_val; } public: void acquire(std::string& co, long n, double price); void buy(long num, double price); void sell(long num, double price); void update(double price); void show(); }; 另外,虽然public与private并没有先后顺序要求,但是感觉先写private更好一点,private内部成员代表了类的一些基本属性,这样写可以先从底部结构开始,接口public放在后面。 这里接口成员函数仅仅声明,并不在这里定义。笔记:public成员在类外部的其他代码也能访问,但是private成员仅仅允许类内部成员函数访问或者操作。数据项通常作为私有成员放在private部分 2、在类外部文件定义类成员函数 在类外部定义类成员函数的时候,需要在函数名前使用域解析运算符(::)来标识所属的类: void Stock::acquire(std::string& co, long n, double price) { ; } 下面再一个stock.cpp文件当中对类成员函数进行定义,注意文件要包含类的头文件。 #include<iostream> #include"Stock.h" using namespace std; void Stock::acquire(const std::string& co, long n, double price) { company = co; if (n < 0) { std::cout << "

算法之二分查找(python&java版)

二分查找 基本原理 二分查找用于在一组排序好的数据中,查找某一个数据 我们以 [2,7,11,15,16,18,20]为例 具体做法是:比如我们要查找7 首先把7与中间索引的值作比较,7<15,然后把最大索引移到中间索引-1的位置上,也就是11上,这样中间位置的索引就变成了7的位置上 然后我们就行将7与中间索引位置的值比较,7=7,这样就得到了7,然后我们输出7所在位置的索引值即可 当然,如果我们要查找的数是16 那我们就把15与16比较,15<16,我们就把最小索引移到中间索引+1的位置上,也就是16上,这样中间位置的索引就变成了18的位置上 然后我们再将要查找的16与中间索引的值比较,16<18,我们就把最大索引移到中间索引-1的位置上,也就是16上,这样中间索引也变成了16的位置那里 这样最小索引等于了最大索引,我们就得到了我们要查找的值,当然,在编程中,如果数组的个数是偶数个的,那中间位置的索引就会在取整的那个数上,比如有6个数,[1,2,3,4,5,6],那中间索引的位置就会在3上面 编程实验 java篇 public static void main(String[] args) { int[] nums = {2,7,11,15,16,18,20}; int num = 11; //要查找的数 int minIndex = 0; //最小索引 int maxIndex = nums.length-1; //最大索引 int centerIndex = (minIndex+maxIndex)/2; //中间索引 while(true) { //二分查找 if (num > nums[centerIndex]) { //如果要查找的数大于中间索引位置的值 minIndex = centerIndex + 1; //将最小索引移动到中间索引位置+1 } else if (num < nums[centerIndex]) { //如果要查找的数小于中间索引位置的值 maxIndex = centerIndex - 1; //将最大索引移动到中间索引位置-1 } else{ //如果要查找的数就等于中间索引位置的数直接输出中间索引 System.

蛇形矩阵

蛇形矩阵用偏移量来控制蛇的方向,同时也是每次移动的步长 把数组想象成一个平面坐标系 用dx和dy来表示偏移量 dx[]={-1,0,1,0},dy[]={0,1,0,-1};//x,y的偏移量 有些人可能会想为什么不是 dx[]={0,1,0,-1} dy[]={1,0,-1,0} 刚开始写的时候,本人也是这么想的,之后想了一下,因为数组是是从最上面开始,就相当于把数学坐标系倒过来了,当你把数学的坐标系倒过了之后就可以想明白了偏移量的变化了。 x和y就代表相应的坐标 然后就在用x和y加上相应的偏移量就可以实现蛇的移动,还有蛇的方向的问题。 蛇在移动的时候,有可能出现两种问题: 1.蛇可能跑出界 2。蛇可能出现之前出现过的位置。 if(a<0||a>=n||b<0||b>=m||q[a][b]){ //判断是否出界 和出现重复的位置 如果蛇出现以上的问题,我们就要将坐标重置 d=(d+1)%4;//因为偏移量代表四个方向,同时也代表了每次移动的多少 a=x+dx[d],b=y+dy[d]; //将重置的方向和偏移量重新给蛇的坐标 坐标重置了之后,蛇就会按相应的位置去走。 直到走完。 #include<iostream> #include<cstdio> using namespace std; const int N=110; int n,m; int q[N][N]; int main() { cin >> n >> m; int dx[]={-1,0,1,0},dy[]={0,1,0,-1};//x,y的偏移量 int x=0,y=0,d=1; //初始坐标,d为偏移量 for(int i=1;i<=n*m;i++){ q[x][y]=i; int a=x+dx[d],b=y+dy[d]; //下一个位置是什么 if(a<0||a>=n||b<0||b>=m||q[a][b]){ //判断是否出界 d=(d+1)%4; a=x+dx[d],b=y+dy[d]; } x=a,y=b; } for(int i;i<n;i++){ for(int j=0;j<m;j++) printf("%7d",q[i][j]); cout << endl; } return 0; }

面向对象继承练习题(Java)

题目描述: 建立一个Po(点)类,包含数据成员X,Y(坐标点),构造器; 以Po为父类,实现一个Circle(圆)类作为子类,增加数据成员R(半径),构造器、求圆面积方法getArea(),求圆周长方法getCircumference(); 再以Cicle类为父类,实现出一个Cylinder (圆柱体〕子类,增加数据成员H(高),构造器,求圆柱体积方法getVolumn()、求圆柱表面积方法getArea(),请编写程序实现。(圆周率取3.14) 要求: 自定义各个类的toString方法,要求当上面三个类的对象创建完毕后,我们直接打印这个三个对象可以显示这个对象的完整信息。 示例: 如打印Circle类的对象会输出: Circle{X=1,Y=2,R=1,circumference=6.28,area=3.14} 解题思路: 创建父类Po,子类继承时使用extends,创建构造器,get set 方法,对子类对象进行实例化 源代码: 运行结果:

【转载】C++11中的内存模型下篇 - C++11支持的几种内存模型

在本系列的上篇,介绍了内存模型的基本概念,接下来看C++11中支持的几种内存模型。 几种关系术语 在接着继续解释之前,先了解一下几种关系术语。 sequenced-before sequenced-before用于表示单线程之间,两个操作上的先后顺序,这个顺序是非对称、可以进行传递的关系。 它不仅仅表示两个操作之间的先后顺序,还表示了操作结果之间的可见性关系。两个操作A和操作B,如果有A sequenced-before B,除了表示操作A的顺序在B之前,还表示了操作A的结果操作B可见。 happens-before 与sequenced-before不同的是,happens-before关系表示的不同线程之间的操作先后顺序,同样的也是非对称、可传递的关系。 如果A happens-before B,则A的内存状态将在B操作执行之前就可见。在上一篇文章中,某些情况下一个写操作只是简单的写入内存就返回了,其他核心上的操作不一定能马上见到操作的结果,这样的关系是不满足happens-before的。 synchronizes-with synchronizes-with关系强调的是变量被修改之后的传播关系(propagate),即如果一个线程修改某变量的之后的结果能被其它线程可见,那么就是满足synchronizes-with关系的。 显然,满足synchronizes-with关系的操作一定满足happens-before关系了。 C++11中支持的内存模型 从C++11开始,就支持以下几种内存模型: enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst }; 与内存模型相关的枚举类型有以上六种,但是其实分为四类,如下图所示,其中对一致性的要求逐渐减弱,以下来分别讲解。 memory_order_seq_cst 这是默认的内存模型,即上篇文章中分析过的顺序一致性内存模型,由于在上篇中的相关概念已经做过详细的介绍,这里就不再阐述了。仅列出引用自《C++ Concurrency In Action》的示例代码。 #include <atomic> #include <thread> #include <assert.h> std::atomic<bool> x, y; std::atomic<int> z; void write_x() { x.store(true,std::memory_order_seq_cst); } void write_y() { y.store(true,std::memory_order_seq_cst); } void read_x_then_y() { while(!x.load(std::memory_order_seq_cst)); if(y.load(std::memory_order_seq_cst)) { ++z; } } void read_y_then_x() { while(!y.load(std::memory_order_seq_cst)); if(x.load(std::memory_order_seq_cst)) { ++z; } } int main() { x = false; y = false; z = 0; std::thread a(write_x); std::thread b(write_y); std::thread c(read_x_then_y); std::thread d(read_y_then_x); a.

贝叶斯课后习题(五)贝叶斯决策

贝叶斯决策 有x服从 B ( 3 , θ ) B(3,\theta) B(3,θ) 因为先验在例题中提到是 U ( 0 , 0.12 ) U(0,0.12) U(0,0.12),所以假设为 [ 0 , 0.12 ] [0,0.12] [0,0.12]上的均匀分布 π ( θ ) = 1 0.12 , 0 < θ < 0.12 \pi(\theta)=\frac1{0.12},0<\theta<0.12 π(θ)=0.121​,0<θ<0.12 可有x的概率分布函数 p ( x ∣ θ ) = C 3 x θ x ( 1 − θ ) 3 − x p(x|\theta)=C_3^x\theta^x(1-\theta)^{3-x} p(x∣θ)=C3x​θx(1−θ)3−x 可有联合密度函数 h ( x , θ ) = p ( x ∣ θ ) π ( θ ) = 1 0.

贝叶斯课后习题(一)先验分布与后验分布

先验分布与后验分布 先验概率可以写为: π ( θ ) { 0.1 , 0.7 0.2 , 0.3 \pi(\theta)\begin{cases}0.1,0.7\\0.2,0.3\end{cases} π(θ){0.1,0.70.2,0.3​ x服从二项分布 B ( 8 , θ ) B(8,\theta) B(8,θ) 即 p ( x ∣ θ ) = C 8 x θ x ( 1 − θ ) n − x = { C 8 x 0. 1 x ( 1 − 0.1 ) 8 − x C 8 x 0. 2 x ( 1 − 0.

使用codesys control for raspberry pi制作PLC

使用codesys control for raspberry pi制作PLC 准备的材料装机安装CoDeSys及CODESYS Control for Raspberry PI编写PLC和HMI程序创建HMI程序下载效果 codesys control for raspberry pi sl是一个适用于raspberry pi(plc扩展)的codesys控制运行时系统。 准备的材料 1.raspios(树莓派系统) 2.CoDeSys V3.5_SP16 3.CODESYS Control for Raspberry PI 4.0.1.0.package 4.Raspberry Pi4b 装机 1.使用balenaEtcher将raspios(树莓派系统)刷入内存卡中 2.开启SSH服务 3.配置或查看树莓派IP 安装CoDeSys及CODESYS Control for Raspberry PI 1.电脑上安装CoDeSys V3.5_SP16 2.运行安装CODESYS Control for Raspberry PI 4.0.1.0.package 1)双击 CODESYS Control for Raspberry PI 4.0.1.0.package,勾选“本人已阅读……”,然后点击“Next”。 2)选择“完整安装”,然后一直按“Next”,最后“Finish”。 3.完成安装后打开CoDeSys,在“工具”->“包管理器”中可以看到刚才安装的软件包。 4.打开“Update Raspberry PI”,选择Package的版本,点击“Scan”,自动查找Raspberry PI设备(要求Raspberry PI和Windows PC在一个局域网里)。 5.选择查找到的设备,然“OK”,输入Raspberry PI的用户名和密码,然后“Install”。 6.选择Runtime的模式 7.消息提示框显示最新的版本表示成功安装 8.在Windows PC上用Telnet命令测试这个软件包是否在树莓派上安装成功。(要求Windows PC 开启了Telnet服务)。

基于正样本的表面缺陷检测

表面缺陷检测在工业生产中起着非常重要的作用,基于机器视觉的表面缺陷检测可以极大的提升工业生产的效率。随着近年来深度学习在计算机视觉领域的发展,卷积神经网络在诸多图像任务上都取得了显著的效果,然而这些方法往往是需要大量标注数据的有监督学习。在实际的工业场景中,缺陷样本往往是难以收集的,而且标注的成本也十分巨大。针对上述有监督学习在实际应用中存在的问题,本文提出了一种仅基于正样本训练的缺陷检测方法。训练过程中只需要提供足够的正样本,无需缺陷数据和手动标注,也可以取得较好的缺陷检测效果,具有较高的应用价值。 1 介 绍 机器视觉表面缺陷检测在工业生产中扮演着重要的角色。传统都是直接人工肉眼鉴别是否存在表面缺陷,不仅耗费人力且不能准确识别缺陷。 机器视觉可以替代人眼进行检测,但在实际应用中仍面临很多挑战,尤其是近几年的传统图像算法解决方案基于经验手工设计,算法存在精度较低且不够鲁棒的问题,特别是在诸如打光、形变、失真和遮挡等复杂的场景中。现今深度学习在特征提取方面有着亮眼的表现,在诸多有监督的任务上都取得了优质的表现,例如分类、目标检测和图像分割。 同时,近年来也涌现了不少用卷积神经网络来进行缺陷检测的方案,其中最常见的是直接利用目标检测网络如Faster RCNN或者SSD对缺陷进行定位和分类。也有先用目标检测进行粗定位,然后用FCN进行语义分割得到精确定位的方法,这种方法可以得到缺陷的精准轮廓,但是这些方法都属于有监督的学习,在实际的工业应用中存在以下问题: 缺少缺陷样本:在实际应用中,用于训练的缺陷样本往往是非常稀少且难以获取的。因此在训练过程中正负样本是非常不均衡的,这极大的限制了模型的性能,甚至导致模型完全不可用。在缺陷外观多变的场景下,有监督学习的方法往往无法满足正常的生产需求。 人工标注成本高昂:实际的工业缺陷检测场景中,通常存在许多不同种类的缺陷,检测的标准和质量指标往往也不同。这就需要人为标注大量的训练数据来满足特定需求,这需要付出大量的人力资源。 2 相关工作 2.1基于正样本的修复模型 本文的灵感来自于一系列基于对抗生成网络GAN的检测和修复模型。GAN的基本框架如图1,主要包括生成器G和判别器D两个部分。生成器G接收从一个高斯分布中随机采样的信号来生成图片,判别器D接收真实图片和生成器生成的虚假图片并区分它们。生成器和判别器在训练时不断对抗从而改善生成图片的质量。 之前有学者使用GAN来进行图像修复。首先使用正常的无缺陷图片来训练GAN,然后再修复已知位置的缺陷时,我们优化生成器的输入z,获得最优的z来让重建图片y和缺陷图片的正常部分最大程度的接近。 另外一个基于图像修复的缺陷检测算法的做法是用中间层的重建误差来重建图像而无需知道缺陷的位置,通过重建图片和原始图片的差异来定位缺陷。 2.2 自编码器 Pix2pix 用自编码器和GAN联合解决图像迁移任务。它可以生产清晰而真实的图像。为了获得质量更佳的细节和边缘,pix2pix使用了类似unet的跨层链接。该结构并不利于去除整个缺陷,因此我们的模型没有使用这个结构。一般自编码器用于图像风格迁移等任务,如给黑白图像上色或者将照片转化为简笔画等。我们用自编码器完成图像重建的任务。 在上述工作的基础上本文完成了以下工作: (1) 使用自编码器重建图像。我们通过加入GANloss来让生成的图像更加真实。 (2) 在训练时人工加入缺陷,不依赖大量的真实缺陷数据,也不用人工标注。 (3) 使用LBP算法来对比重建图片和原始图片,从而定位缺陷。 3 方 案 3.1基本框架图 本文提出的模型的基本框架如图2 图2. 网络框架 C(x~|x)是设计的一个人工制造缺陷的模块,在训练阶段,通过该模块将训练集x人为的加上缺陷得到缺陷图片x~。EN为编码器,它将输入的缺陷图片x~映射为一个潜在变量z ,DE为解码器,它将潜在变量z重新建模成图片y。EN和DE共同组成一个自编码器,作为GAN中的生成器,其任务便是让输出的图片y不断接近正常的图片x。判别器D用来判断其输入是来自于真实的训练集还是生成器的输出图片。通过对抗训练,生成器G便拥有了修复缺陷的能力。 在测试阶段,将之前训练好的自编码器G作为修复模块,将测试图片x输入到自编码器G中,获得修复后的图片y。修复图片y和原图作为输入一起用LBP算法来提取特征并对比,从而定位缺陷。 3.2 损失函数 缺陷样本在经过自编码器G重建后应该与原始的正常图片相同,本文参考pix2pix,用L1距离来表征它们的相似程度。 然而在实验中发现,如果仅仅使用L1 loss来作为目标函数,获取的图像边缘会变得模糊而且会丢失细节。本文通过加入判别器D,用GAN loss来改善图像质量,提升重建效果。 因此最终的优化目标如下: 3.3 网络结构细节 本文的网络结构参考了DCGAN。在生成器和判别器中增加batchnorm层。在判别器中使用LeakyRelu激活函数,在生成器中使用Relu激活函数。 在本文的模型中,自编码器只需要将图片修复成最接近的样本图片,并不在乎缺陷的具体形式。在实际训练过程中,人为的随机生成不同位置、大小、灰度和数量的缺陷块到图片中,如图3。 图3. 人工缺陷示意图 数据增强方面,本文在0.5到2之间进行尺度变换,并随机加入-180和180°的旋转以及随机高斯模糊。 3.4定位缺陷 由于重建后的图片和原始图片在细节上存在一些误差,我们不能直接将原始图片和修复图片做差分来得到缺陷位置。本文使用LBP算法来进行特征提取,并匹配每个像素。具体流程如图4。 图4. 定位缺陷的过程 将原始图像x和修复图像y输入到LBP模块,提取出特征图x+和y+。对于x+的所有像素点,在y+中对应位置搜索最匹配的特征点,从而对齐了特征。最后逐个对比匹配点之间的特征值,通过设置一个阈值来筛选,便可以得到缺陷的位置。 4 实验效果 本文在DAGM表面纹理数据集和纺织物数据集上做了实验来检验性能。并与FCN算法进行比较。使用平均精度来作为衡量标准。 4.1表面纹理缺陷 纹理表面有着较好的一致性,所以在训练集中有足够的缺陷样本来学习。 表1. 表面纹理数据集的测试信息 训练集 本文:400张无缺陷图FCN: 85张带缺陷图+400张无缺陷图 测试集 85张带缺陷图 图像尺寸

前端生成二维码(qrcode.js&jquery.qrcode.min.js )使用小结

文章目录 qrcode.js&jquery.qrcode.min.js使用小结1. js文件及说明2. jquery.qrcode.js 使用说明3. qrcode.js 使用说明 qrcode.js&jquery.qrcode.min.js使用小结 1. js文件及说明 qrcode.js : 是一个纯浏览器用于生成二维码图片的插件,生成的 QRcode 无需下载图片,并且不依赖第三方服务,下面插件使用的是压缩版本,大小不超过4K jquery.qrcode.js : 是实现二维码数据计算的核心类 qrcode.js生成的二维码是图片格式 img jqurey.qrcode.js 生成的二维码是canvas或table 传送门–>走你---------------1积分 2. jquery.qrcode.js 使用说明 $('#qrcode').qrcode({ render: "canvas",//设置渲染方式(有两种方式 table和canvas,默认是canvas) text: '内容', width: 100, //二维码宽 height: 100, //二维码长 background: "#ffffff",//背景颜色 foreground: "#000000", //前景颜色 correctLevel :0,//纠错等级 }); 参数说明: render : 生成二维码的格式(canvas和table) – canvas 是画布 – table是表格(每个点是一个td…感觉会是一个很大的表…)text :二维码内容(不支持中文…据说是UTF-16格式的编码,中文的话需要转换下, 要不然是乱码)width : 二维码宽度height : 二维码高度foreground : 前景颜色,也就是常规二维码 “黑点” 的颜色background : 背景颜色, 也就是常规二维码白色部分的颜色correctLevel : 容错等级 0~3