React - Initial Rendering(初始化渲染)

React - Initial Rendering(初始化渲染) 以下内容均从源码角度分析,UI更新本质上是数据更改(props或者state) = render(state)。React提供了一种直接且直观的方法,所有移动部分都以**状态(states)**的形式聚合,那么问题来了?React究竟是如何渲染的了?内部的渲染原理是什么样的?接下来我们一步一步的分析。 标题内容JSXJSX是如何生效的?React.createElementReact.createElement工作原理ReactDOM.renderReacrDOM.render工作原理 JSX JSX: 一种在JavaScript代码中交织HTML标签的语法。 create-react-app创建的应用中的App.js或者可以下载,这就是JSX的写法案例。 import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <header className="App-header"> <img scr={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to React</h1> </header> <p className="App-intro"> To get started, edit <code>src/App.js</code> and save to reload. </p> </div> ); } } export default App; 这段代码能够在浏览器中直接运行生效吗?答案是否定的,那么JSX是如何生效的了,现在开始解答。在编译时,JSX中定义的组件会被Babel编译成React.createElement()带有适当参数的函数形式。Babel的配置: { "

CRT常用设置

shift + insert(跟鼠标右键一个效果) 使用SecureCRT的常用配置 1. Session Options --> Terminal 中将Anti-idle下的 Sending String选项打钩,并且在后面输入框中随意输入几个空格。用处是防止你在停止操作几分钟后操作会被断开,设置之后,每隔五分钟客户端会自动向服务器端发送几个空格,从而保活连接。 2. Session Options --> Terminal --> Emulation界面中,将Emulation下的Terminal下拉条选为Linux,并且勾选ANSI color,会让你的文件和文件夹显示Linux支持的各种颜色,很容易分辨 3. Session Options --> Terminal --> Appearance中,将Fonts下的Normal Font调整为Consolas 14pt, 下面的Character Encoding设置为UTF-8,防止出现中文乱码。 设置快捷键: 即设置映射键。 ctrl + tab: 标签切换 双击克隆会话

crt颜色设置

Options => Sessions options => Terminal => Emulation,在 Terminal下拉列表下选择 Xterm 或者 Linux,勾选 ANSI Color,个人更喜欢 Xterm, vim 颜色不刺眼。 默认的 ANSI Color 的背景颜色是黑色,感觉看久了很不舒服,可以修改背景颜色。 options -> global options ->Terminal ->Apperance -> ANSI Color, Default, 点击黑色的那项, 修改为下面的颜色比较舒服,颜色是:H, S, L = 128,240,25 设置字体颜色 白色字体看上去也不舒服,同样可以修改:颜色是:H, S, L = 124,20,132 设置目录颜色 颜色是:H, S, L = 160,240,180 设置压缩文件颜色 颜色是:H, S, L = 40,240,60 设置字体 Options => Global Options=>General=> default session=> Edit default => Appearance =>Font。 Consolas 或者 Courier New 这两种字体都不错.

linux 时间函数

文章目录 gettimeofday(取得目前的时间)clock_gettime(获取不同要求的精确时间)clock()time_tStrftime函数 gettimeofday(取得目前的时间) 有时候需要打印代码执行到某处的时间,或者需要计算程序执行的时间差。这时会用到gettimeofday函数,它可以返回自1970-01-01 00:00:00到现在经历的秒数, 函数说明: #include <sys/time.h> int gettimeofday ( struct timeval * tv , struct timezone * tz ) 参数都是出参 struct timeval { time_t tv_sec; //秒 suseconds_t tv_usec; //微秒 }; struct timezone { int tz_minuteswest; //和Greenwich 时间差了多少分钟 int tz_dsttime; //日光节约时间的状态 }; 返回值 成功则返回0, 失败返回-1,错误代码存于errno。 timeval中的tv_sec是time_t类型的,即long的类型。 在32位下为4个字节,能够表示的最大正整数是2147483647,而这个表示的时间最大能到2038-01-19 03:14:07,超过了之后就变为-2147483648,这就是linux2038年的问题。 而64位系统下的time_t类型即long类型长度为8个字节,可以用到几千亿年,这么长的时间完全不用担心溢出的问题。 tz_dsttime 所代表的状态如下 DST_NONE /*不使用*/ DST_USA /*美国*/ DST_AUST /*澳洲*/ DST_WET /*西欧*/ DST_MET /*中欧*/ DST_EET /*东欧*/ DST_CAN /*加拿大*/ DST_GB /*大不列颠*/ DST_RUM /*罗马尼亚*/ DST_TUR /*土耳其*/ DST_AUSTALT /*澳洲(1986年以后)*/ 我们很可能会用到精确到毫秒的时间,这样可以这样写,

3D骨架(细化)提取算法C++

网上的细化算法大部分都是对2D图像进行提取,对3D图像进行细化代码介绍太少了。目前比较流行的有两个版本。 matlat版本 Skeleton3D。 ITK版本 itkBinaryThinningImageFilter3D.h。 ITK版本比较麻烦,需要将数据转成ITK的格式,读取很不方便。所以我将ITK版本的细化算法使用C++写了一遍。使用的是VS2019版本,输入的是3维的二进制数据。链接是ThinningAlgo3D。

java反射机制

java中的反射 什么是反射? 反射是java中非常强大的一个技术,甚至很多博客中称其为java中最强大的技术。 java的反射机制其实是java提供给开发者的一种动态获取信息,动态调用对象的机制,简单来说就是在运行状态中,对于任意一个类,都能知道这个类所有的属性和方法,对于任意一个对象,都能调用它任意一个方法和属性。 一个例子 上面这样说还是比较抽象,举一个简单的例子,当我们需要为某个需求定制接口供app调用时,比如说需要在android.os路径下新增一个HapticPlay类,这个类中实现了一个start方法,那么当我们在framework中添加好接口,编译通过之后,AndroidStudio一定是调用不到的,因为AndroidStudio中只有谷歌官方的接口,但是system.img中确实有了我们新增的接口,这个时候,我们就可以用反射来调用。 具体用法 反射的基本用法很简单,仍然以HapticPlayer类为例 要调用一个类中的方法,首先需要获取到这个类,使用反射机制时,我们只需要知道包路径和包名即 可,根据上面的描述,包路径为android.os,包名为HapticPlayer,那么获取类只 需要一行代码 Class<?> clz = Class.forName("android.os.HapticPlayer"); Class类型大致可以按照C语言中的void *理解,如果这行代码没有抛异常的话,此时clz就代表我们的HapticPlayer类。 获取到类之后需要获取类中我们想调用的方法 Method startMethod = clz.getMethod("start",int.class); 入口参数中,start代表要调用的方法名,int.class代表方法的入参为int类型,也就是说,我们要调用的方法为start(int a)。 接着就需要实例化这个类, Constructor<?> hapticPlayerCon = clz.getDeclaredConstructor()); getDeclaredConstructor相当于调用HapticPlayer的构造函数,当构造函数有参时,比如int类型调用的方法就是getDeclaredConstructor(int.class),如果是参数类型是自定义数据结构,那么就是getDeclaredConstructor(Class.forName("xxx")),比如我这里的参数是android.os.DynamicEffect(新增的类),我就需要写成getDeclaredConstructor(Class.forName("android.os.DynamicEffect"))。此时,如果没有抛出异常,那么hapticPlayerCon相当于HapticPlayer类中入参为android.os.DynamicEffect的构造函数。 这时,我们就可以利用构造函数实例化这个类, Object hapticObj = hapticPlayerCon.newInstance(); 此时,如果没有抛出异常,那么hapticObj相当于HapticPlayer类的一个实例,利用这个实例,我们就可以调用start方法。 这时,我们调用 startMethod.invoke(hapticObj, var); 就可以正常调用到start方法,invoke函数中,第一个参数是start方法所在的对象,第二个参数是start方法需要的参数,我这里是一个int。 所以,整个函数是这样的 public static void start (int loop) throws IllegalArgumentException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { @SuppressLint("PrivateApi") Class<?> clz = Class.forName("android.os.HapticPlayer"); Method startMethod = clz.getMethod("start",int.class); @SuppressLint("PrivateApi") Constructor<?> hapticPlayerCon = clz.getDeclaredConstructor(Class.forName("android.os.DynamicEffect")); @SuppressLint("

2021年10月30日 axios请求的端口号与设置的端口号不同

Vue+SpringBoot项目 axios请求地址错误 全部都是404 请求了错误的网址 正确的那个请求也是axios,不过是写在.vue中的请求 getXianCha() { this.$http({ method: "post", url: "/der/milkTea/queryByXianCha", }).then( (res) => { // this.$message.warning(JSON.stringify(res.data)); this.result = res.data; }, (error) => { console.log(" request error : " + error.response.status); } ); }, 返回的状态码是200 是正确的 错误的请求是写在store/index.js里的 state: { materialsState: [ { index: 1, value: "pearl", text: "珍珠", }, ], sugerStates: [ { index: 1, value: "normal", text: "正常糖", }, ], temperatureState: [ { index: 4, value: "hot", text: "

求定制闲鱼爬虫获取最新发布商品

闲鱼采集及监控下单软件开发 1,点击宝贝右键打开网页 2,点击宝贝右键拉黑卖家 3,点击宝贝右键清空列表 4,点击宝贝左键显示二维码和主图 5,软件页面显示宝贝二维码 6,软件页面显示宝贝主图 7,软件页面显示检测搜索词及下单宝贝 8,每次获取的宝贝数量可以修改数量 9,关键词匹配《开启标题描述中含有关键词过滤》 10,关键词匹配《开启详情描述中含有关键词过滤》 11,排序方式,最新发布 12,搜索页数,可以调整 13,发布天数,可以调整 14,声音提示,搜索出现的宝贝有声音提示 15,显示浏览量,搜索出现的宝贝可以调整浏览量 16,显示我想要,搜索出现的宝贝可以调整我想要 18,添加或者删减搜索词 19,清除缓存 20,显示过滤卖家,过滤标题词,过滤详情词 21,实时监控最新发布数据,搜索词速度间隔没有太高要求! 能做的私聊!十分感谢

带https证书的blazorserver的docker部署

准备工作 $ dotnet --version 5.0.400 IDE: Visual Studio for mac 2019 项目实施 新建项目:App->Blazor Server App->.Net 5.0+individual Authentication+Configure for Https->Create a project directory within the solution direction 添加docker支持:选择项目->add docker support,会自动添加docker部署需要的文件 ├── TestBlazorHTTPS │ ├── App.razor │ ├── Areas │ ├── Data │ ├── Dockerfile //add │ ├── Pages │ ├── Program.cs │ ├── Properties │ ├── Shared │ ├── Startup.cs │ ├── TestBlazorHTTPS.csproj │ ├── _Imports.razor │ ├── app.db │ ├── appsettings.

快速使用ABP+Zorro

ABP前台操作流程 下载 前往ASP.NET Boilerplate Startup Templates下载例子下载完成后按照流程Startup-Template-Angular操作,或直接用angular前端部分衔接已有的后台(以下操作衔接南海项目现有API) 配置 到项目目录下安装包npm i或者npm install或yarn add cd XXX npm i 安装好后需更新NSwag生成的客户端调用代码 更新nswag的后台api地址nswag路径nswag/service.config.nswag(注意,这个与本地的.net core版本有关) "documentGenerator": { "fromDocument": { "url": "http://salt1.gzwanlink.com.cn:8096/swagger/v1/swagger.json", "output": null } }, 更新完配置后运行refresh.bat,可见src/shared/service-proxies/service-proxies.ts已经更新 更新配置中app运行的后台地址,位置src/assets/appconfig.json, { "remoteServiceBaseUrl": "http://salt1.gzwanlink.com.cn:8096", "appBaseUrl": "http://localhost:4200", "localeMappings": [ { "from": "pt-BR", "to": "pt" }, { "from": "zh-CN", "to": "zh" }, { "from": "he-IL", "to": "he" } ] } 运行npm start,可成功打开登录界面 添加ng-zorro 为了不破坏ABP前端框架,选择手动添加ng-zorro,执行npm install ng-zorro-antd --save,参考https://ng.ant.design/docs/getting-started/zh 在core.less中引入@import "~ng-zorro-antd/ng-zorro-antd.min.css" 新建模块文件ng-zorro-antd.module.ts 在需要用到zorro的组件所在的模块中引入DemoNgZorroAntdModule @NgModule({ imports: [ DemoNgZorroAntdModule, ], 添加完成后如果报错Uncaught (in promise): ReferenceError: ImportNgZorroAntdModule is not defined,可重新npm start

报错:io.minio.MinioClient.putObject(Ljava/lang/String;Ljava/lang/String;Ljava/io/InputStream;JLjava/la

2021-10-29 10:20:21.537 ERROR 10732 --- [nio-8720-exec-4] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: io.minio.MinioClient.putObject(Ljava/lang/String;Ljava/lang/String;Ljava/io/InputStream;JLjava/lang/String;)V] with root cause java.lang.NoSuchMethodError: io.minio.MinioClient.putObject(Ljava/lang/String;Ljava/lang/String;Ljava/io/InputStream;JLjava/lang/String;)V 原因: 两个子项目引用的包不一致 改成一致的,重新启动程序

Symantex Endpoint Protection赛门铁克杀毒软件安装

一、交付邮件 目前软件交付基本都是通过邮件进行。杀毒软件交付邮件中附件包含序列号以及购买产品信息。 二、官网软件下载 在右键中点击“Download Today”跳转下载页面(吐槽:交互很差劲) 登录网站:https://support.broadcom.com/ 搜索下载产品后点击下载(1.86g) 三、杀毒服务端安装 点击Symantec_Endpoint_Protection_14.3_RU1_MP1_Full_Installation_CS.exe进行安装 安装服务端教程 安装教程视频服务端+客户端 安装过程中设置好账户密码,请记录好。 安装过程如果端口冲突会自动调整 安装过程会自动安装slq server 2017,请确保服务器补丁重大更新完成安装。 4、服务端配置 1、激活许可证 在“管理员”-》“许可证”-》“激活许可证” 2、管理员修改 此处可以对管理员账号进行设置,包括账号密码事限以及通知邮箱等信息。 5、客户端安装 1、原程推送安装 见视频 2、手动安装 安装包导出

C++初始化双层vector(vector<vector<double>>)出现Expression: vector subscript out of range错误解决方法

报错代码块为: vector<vector<double>> dist;//distance list for (i = 0; i < n; i++) {//init distance list for (j = 0; j < n; j++) { dist[i].push_back(0.1); } } 分析原因后觉得应该是vector<vector<double>> dist中一个vector<double>向量都没有,所以在循环中会报越界错误,修改成以下形式就不报错了: for (i = 0; i < n; i++) {//init distance list vector<double> v; dist.push_back(v); for (j = 0; j < n; j++) { dist[i].push_back(0.1); } }

华为LACP链路聚合配置

华为LACP链路聚合配置 链路聚合原理:链路聚合的原理是将一组相同属性的物理接口捆绑在一起为一个逻辑接口来增加带宽和可靠性的一种方法。有以下优势: 增加带宽、提高冗余(提高可靠性)、负载分担、节省成本、配置量小 1.增加带宽:链路聚合接口的最大带宽可以达到各个成员接口带宽之和。 2提高冗余:当某条路线出现故障的时候,流量可以切到其他可用的成员链路上。流量会切到其他可用链路上,从而提高链路聚合接口的冗余性。并不会影响数据的传输,相对来说也具有稳定性。 3负载分担:在一个链路聚合组内,可以实现在各成员活动链路上的负载分担。 4节省成本:管理员不需要升级链路速度,对已有的接口进行捆绑。 5配置量小:大部分的配置在组Eth-Trunk下完成。 主要的优势是能增加带宽、提高可靠性和负载分担。 LACP模式名词解释 系统LACP优先级 系统LACP优先级是为了区分两端设备优先级的高低而配置的参数。LACP模式下,两端设备所选择的活动接口必须保持一致,否则链路聚合组就无法建立。此时可以使其中一端具有更高的优先级,另一端根据高优先级的一端来选择活动接口即可。系统LACP优先级值越小优先级越高。 接口LACP优先级 接口LACP优先级是为了区别同一个Eth-Trunk中的不同接口被选为活动接口的优先程度,优先级高的接口将优先被选为活动接口。接口LACP优先级值越小,优先级越高。 成员接口间M:N备份 LACP模式链路聚合由LACP确定聚合组中的活动和非活动链路,又称为M:N模式,即M条活动链路与N条备份链路的模式。这种模式提供了更高的链路可靠性,并且可以在M条链路中实现不同方式的负载均衡。 如上图所示,两台设备间有M+N条链路,在聚合链路上转发流量时在M条链路上分担负载,即活动链路,不在另外的N条链路转发流量,这N条链路提供备份功能,即备份链路。此时链路的实际带宽为M条链路的总和,但是能提供的最大带宽为M+N条链路的总和。 当M条链路中有一条链路故障时,LACP会从N条备份链路中找出一条优先级高的可用链路替换故障链路。此时链路的实际带宽还是M条链路的总和,但是能提供的最大带宽就变为M+N-1条链路的总和。 配置 LSW1配置 [LSW1]lacp priority 500 #设置优先级,LSW1为主动端 interface Eth-Trunk10 #创建聚合组10 mode lacp-static #选择链路聚合模式为LACP模式,一定要先打模式命令再添加接口,不然默认为手动两路聚合 trunkport GigabitEthernet 0/0/2 to 0/0/4 #把接口2到接口4加入聚合组 max active-linknumber 2 #设置活动端口为两个 LSW2配置 interface Eth-Trunk10 #创建聚合组10 mode lacp-static #选择链路聚合模式为LACP模式 trunkport GigabitEthernet 0/0/2 to 0/0/4 #把接口2到接口4加入聚合组 输入命令display eth-trunk 10查看配置: 从配置截图可以看到,该交换机的优先级为500,默认的优先级是32768,越小越优先。LSW1的优先级是我们改的。接口是UP状态,同时有两个活动端口,也是手动设置的。下面三个接口随机两个端口是活动端口,活动端口可以修改,我们把接口4改为活动端口。 由于交换机LSW1 是主动端口,所以需要在改交换机上修改。 [LSW1-Eth-Trunk10]lacp preempt enable #在聚合组内开启抢占 [LSW1-Eth-Trunk10]lacp preempt delay 10 #抢占延迟10S [LSW1-GigabitEthernet0/0/4]lacp priority 500#在接口4配置优先级

Gradle download:kotlin-compiler-embeddable下载慢

1、进入Maven仓库地址 2、进行下面的操作 3、先让AndroidStudio下载一会,然后取消,这样它在磁盘中会生成一个文件夹, 4、结果应该是这样的 5、再重新打开AndroidStudio同步一下即可

PDP

A Perceptual Distinguishability Predictor For JND-Noise-Contaminated Images 摘要:恰察觉失真(JND)模型被广泛用于图像和视频中的感知冗余估计。测量JND模型精度的常用方法是在基于JND模型的图像中注入随机噪声,并检查JND噪声污染的图像在感知上是否可与原始图像区分开。此外,当比较两种不同的JND模型的精度时,在相同的噪声能量水平下产生具有更好质量的JND噪声污染图像的模型是更好的模型。但是在这两种情况下,主观测试都是必要的,这是非常耗时和昂贵的。在这篇文章中,作者提出了一个全参考度量称为PDP(感知可区分性预测),它可以用来确定一个给定的JND噪声污染的图像对比参考图像是否感知可区分的。所提出的度量采用稀疏编码的概念,并从给定的图像对中提取特征向量。然后将特征向量输入多层神经网络进行分类。为了训练网络,作者建立了一个999幅自然图像的公共数据库,这些自然图像具有从大量主观实验中获得的四种不同JND模型的分辨率阈值。结果表明,PDP达到了97.1%的高分类精度。所提出的方法可用于客观地比较各种JND模型,而无需进行任何主观测试。它还可以用来获得适当的比例因子,以提高由任意JND模型估计的JND阈值。 主要工作 提出一个JND噪声污染图像的感知可区分预测器(PDP);为四种不同的JND模型提出了一个具有图像级可区分阈值的数据库;提出了一种基于图像内容为任意JND模型选择比例因子的系统方法,用于更精确地估计JND阈值,比较各种JND模型; 感知可区分预测器(PDP) 上图描述了PDP的流程图。该方法包括两个主要部分:1)学习感知特征检测器,2)感知区分度测量。第二部分本身由以下三个步骤组成:a)特征提取,b)特征相似性度量,c)分类。 学习特征检测器 使用独立成分分析(ICA)来实现,x表示矢量化的图像块,假设x可以用字典中一些基向量的线性叠加来表示,即 两边同时乘以字典的逆,可得稀疏特征向量 字典的逆通过对一组自然图像块应用稀疏编码方法获得 学习特征检测器的作用,就是通过将它应用于给定的图像块x,可以获得稀疏特征向量c。 x的选取 从9张图像中随机提取大小为8×8的P(20000)个块,对图像块进行矢量化,生成大小为64 × 20000的数据矩阵X 稀疏编码 应用主成分分析(PCA)来降低数据矩阵维数,实验发现K = 50时,可以获得最好的结果。然后使用pca的对角矩阵和C的k个最大特征值 得到白化矩阵w,白化数据Z。最后使用FastICA稀疏编码方法进行特征的学习 最后一步是为了将获得的特征检测器从白化空间变换到原始空间,最终得到的50个基向量 感知区分度度量 特征提取:R为参考灰度图像,J为JND噪声污染图像。使用学习特征检测器为R和J提取稀疏特征向量 1)将R和J都划分为8×8不重叠的块,将获得的块矢量化及中心化,得到两个64 × Q的矩阵 2)将使用MS-SSIM计算J中每个块的感知质量分数,保留质量差的块,矩阵大小为64 × G 3) 4)计算稀疏特征向量的功率,丢弃功率低的向量,矩阵大小为K × H 特征相似性度量 度量所计算的特征矩阵之间的相似性,就不概述 最终特征向量h的长度将为2K,因为它是通过h1和h2的连接获得的。因为,在实验中,K = 50,h的长度将是100。 分类:多层感知器 网络的输入和输出神经元的数量分别等于100和1,第一至第三隐藏层的神经元数目分别为128、64和16,Sigmoid函数作为输出层的激活函数。网络的输出是二进制值(0或1),它决定了输入的噪声图像在感知上是否可与参考图像区分开。 数据库 为了训练分类器,文章建立一个图像数据库,其中每个图像有四个与四个不同的JND模型相关的可分辨阈值 1 )采用MIT中的999张1024 × 768彩色图像 2) 采用四个JND模型:Wu2017 、Liu2010 、Wu2013 和Yang2005 3)可区分阈值:一个合适的s值,来衡量所采用的JND模型在该参考图像的JND阈值,999 × 4 = 3996个可分辨阈值 可区分阈值测量实验 1)定义一个心理测量函数,该函数将JND噪声污染图像中的噪声能量与相应的感觉(两幅图像之间的可分辨性)联系起来 2)求取初始可区分阈值 3)使用Psi方法自适应地估计可区分阈值和函数斜率 实验结果 PDP的交叉验证精度 基于PDP的多种JND模型比较 基于PDP的多种JND模型比较(非数据库模型) 比较步骤

ES导出数据的方法

第一种方法 (使用elasticdump) 这是一个nodejs的插件,安装方式直接使用 npm即可 导出索引的格式 #格式:elasticdump --input {protocol}://{host}:{port}/{index} --output ./test_index.json #例子:将ES中的test_index 中的索引导出 #导出当前索引的mapping结构 $ elasticdump --input http://192.168.56.104:9200/test_index --output ./test_index_mapping.json --type=mapping #导出当前索引下的所有真实数据 $ elasticdump --input http://192.168.56.104:9200/test_index --output ./test_index.json --type=data 向新的es服务导入索引 # 创建索引 $ curl -XPUT http:192.168.56.104:9200/test_index #因为导入的是mapping,所以设置type为mapping $ elasticdump --input ./test_index_mapping.json --output http://192.168.56.105:9200/ --type=mapping #因为导入的是data(真实数据)所以设置type为data $ elasticdump --input ./test_index.json --output http://192.168.56.105:9200/ --type=data

基于暗通道优先算法的去雾应用(Matlab/C++)

基于暗通道优先的单幅图像去雾算法(Matlab/C++) 算法原理: 参见论文:Single Image Haze Removal Using Dark Channel Prior [1] ① 暗通道定义 何恺明 通过对大量在户外拍摄的自然景物图片进行统计分析得出一个结论:在绝大多数非天空的局部区域里,某一些像素总会(至少一个颜色通道)具有很低的值。换言之,该区域光强度的最小值是个很小的数(趋于0)。 基于上述结论,我们定义暗通道,用公式描述,对于一幅图像J有如下式子: 也就是说以像素点x为中心,分别取三个通道内窗口Ω内的最小值,然后再取三个通道的最小值作为像素点x的暗通道的值,如下图所示: Jc代表J的某一个颜色通道,而Ω(x)是以x为中心的一块方形区域。我们观察得出,除了天空方位,Jdark的强度总是很低并且趋近于0。如果J是户外的无雾图像,我们把Jdark称为J的暗原色,并且把以上观察得出的经验性规律称为暗原色先验。 ②大气物理模型 要想从物理模型角度对有雾图像进行清晰化处理,就要了解有雾图像的物理成因,那么就要了解雾天的大气散射模型。 大气散射物理模型包含两部分,第一部分称为直接衰减项(Direct Attenuation)也称直接传播,第二部分称为大气光照(Airlight) 用公式表示如下: I是观测到的有雾图像,J是景物反射光强度(也就是清晰的无雾图像),A是全局大气光照强度,t用来描述光线通过介质透射到成像设备过程中没有被散射的部分,去雾的目标就是从I中复原J。那么也就是要通过I求A和t。 方程右边的第一项J(x)t(x) 叫做直接衰减项,第二项A(1-t(x))则是大气光照。直接衰减项描述的是景物光线在透射媒介中经衰减后的部分,而大气光则是由前方散射引起的,会导致景物颜色的偏移。因为大气层可看成各向同性的,透射率t可表示为: β为大气的散射系数,该式表明景物光线是随着景物深度d按指数衰减的。 ③求解透射率t 在论文[1]中,作者给出了推导过程,这里就不再重复,其最后得到透射率t的公式如下: Ic为输入的有雾图像,对其除以全局大气光照Ac后在利用暗通道定义公式进行求解暗通道。w(0<w<1)是雾的保留系数通常取0.95。 这里需要值得注意的是,求得的t是粗透射率图,并不能直接带入大气模型公式求解,所以需要进行细化后再处理。细化过程见⑤,Ac为全局大气光照,其求法见④。 ④求解全局大气光照Ac 论文[1]中作者给出求解全局大气光照的过程如下: 1.首先对输入的有雾图像I求解其暗通道图像Jdark。 2.选择暗通道Jdark内图像总像素点个数(N_imagesize)千分之一(N=N_imagesize/1000)个最亮的像素点,并记录这些像素点(x,y)坐标。 3.再根据这些点的坐标分别在原图像I的三个通道(r,g,b)内找到这些像素点并加和得到(sum_r,sum_g,sum_b). 4.Ac=[Ar,Ag,Ab]. 其中Ar=sum_r/N; Ag=sum_g/N; Ab=sum_b/N. ⑤细化透射率t 作者在论文[1]中使用了软抠图(soft matting)的方法,详见论文如下: A Closed-Form Solution to Natural Image Matting[2], 作者:Anat Levin 使用软抠图法对得到的粗透射率t~进行细化。由于这个方法时间和内存花费比较大,后来作者又使用指导性滤波器进行细化粗透射图。效果上指导性滤波要稍差于软抠图法,但在时间和内存花费上具有明显优势,因此这里我们使用指导性滤波器进行细化粗透射率t~。(注:Matlab代码中也附带软抠图法细化透射率的代码。内容见文件包) 关与指导性滤波的详细内容见论文:Guided Image Filtering [3] 作者:何恺明 ⑥求解最后清晰图像 现在,我们得到了A和t,那么带入大气模型公式: 这里,t0参数用来限定透射率t的下限值,其作用也就是在输入图像的浓雾区域保留一定的雾。 附录: ReadMe.txt: 感谢论文Single Image Haze Removal Using Dark Channel Prior作者何凯明。 基于暗通道优先去雾算法的Matlab /C++ 源码为免费开源。只供研究学习使用,如果引用请注明原开发者,及出处。 Matlab版中指导性滤波的源码为原作者何凯明提供。 开发者:赵常凯(不包括Matlab版中 指导性滤波的源码) 时间:2013.

代码分割(Code Splitting)

代码分割(Code Splitting) 为什么要分割代码?代码分割有什么作用呢? 答:两个方面。 1、项目包含第三方依赖库以及自己写的代码,打包出的文件会比较大,在用户访问系统的时候,由于请求的资源比较大,所以会响应的比较慢,造成页面渲染缓慢,影响用户体验。 代码分割以后,chunk会相应的变小,用户访问时,只需返回此页面相关chunk,再加上浏览器的并行请求策略,从而加快系统响应速度,优化用户体验。 2、由于将第三方依赖库和自己写的代码打包到了一起,一旦我们修改了其中的一部分代码,整个chunk(包括第三方依赖库,即使它没有发生任何变化)都会重新打包,生成带有新的hash值的chunk。原本在浏览器已经缓存了的chunk,会因为hash的变更,不会再使用之前缓存的chunk,而重新请求新的chunk。简言之,一处代码变更,要重新请求所有资源,缓存效果差。 代码分割以后,就可以将比较大的第三方依赖库分离到单独的chunk中,以后即使用户修改业务代码,只要不改变此库的版本或库代码,在浏览器端的此chunk的缓存会一直有效。剩余的比较小的第三方依赖库打包到同一个chunk中,将依赖库与业务代码彻底分离。由于更改依赖库的版本的概率比较小,所以可以有效利用缓存,提升响应速度。 一、SplitChunksPlugin 将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。 项目代码中第三方依赖库变动较少,只有在变更第三方依赖库版本的时候才会产生变化。所以我们有必要将比较大的第三方依赖库分离到独立的chunk中,当用户首次请求资源时,会将资源缓存,以后再次访问此资源时,就可以直接使用缓存,提升响应速度。 如果此chunk内容发生变更,打包后它的文件名hash值会发生变化,用户访问网页时,会首先返回html,html中包含了访问此网页需要的新的资源地址,从而请求新的chunk,然后将新的chunk缓存。 配置: 请参考 官方文档. 示例: // vue.config.js chainWebpack config.optimization.splitChunks({ chunks: 'all', cacheGroups: { libs: { name: 'chunk-libs', test: /[\\/]node_modules[\\/]/, priority: 10, chunks: 'initial', enforce: true }, lodash: { name: 'chunk-lodash', priority: 11, test: /[\\/]node_modules[\\/]lodash[\\/]/ }, elementUI: { name: 'chunk-elementUI', priority: 12, test: /[\\/]node_modules[\\/]_?element-ui(.*)[\\/]/ } } }) 二、组件按组分块 有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中,只需要使用 命名 chunk (opens new window),一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.