Windows Terminal 尝鲜小记

前言

  Windows Terminal 正式版在两个月之前终于发布了,正好最近找了点时间尝尝鲜,感觉确实可以,Cmder 可以退休了。

前言

  Windows Terminal 正式版在两个月之前终于发布了,正好最近找了点时间尝尝鲜,感觉确实可以,Cmder 可以退休了。

尝鲜篇

  直接在 Microsoft Store 安装,顺便安装好 Powerline,执行以下三个命令:

1
2
3
Install-Module posh-git -Scope CurrentUser
Install-Module oh-my-posh -Scope CurrentUser
Install-Module -Name PSReadLine -Scope CurrentUser -Force -SkipPublisherCheck // 使用 powershell core 则必选

然后执行 notepad $PROFILE ,在弹出的记事本中添加:

1
2
3
Import-Module posh-git
Import-Module oh-my-posh
Set-Theme Paradox

重启 terminal,若出现 “无法加载文件 ***.ps1, 因为此系统上禁止运行脚本”,则需要执行 set-executionpolicy RemoteSigned,使powershell 能顺利执行该脚本。

  由于目前 Windows Terminal 不会自动注册右键快捷菜单,所以需要手动修改注册表,执行 mkdir "%USERPROFILE%\AppData\Local\terminal" 后,在网上找一个终端图标,命名为 wt_32.ico,将该图标复制到 %USERPROFILE%\AppData\Local\terminal 目录中, 新建 wt.reg 文件后直接双击执行,该注册表文件的内容如下:

1
2
3
4
5
6
7
8
9
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\Background\shell\wt]
@="Windows terminal here"
"Icon"="%USERPROFILE%\\AppData\\Local\\terminal\\wt_32.ico"

[HKEY_CLASSES_ROOT\Directory\Background\shell\wt\command]
@="C:\\Users\\[user_name]\\AppData\\Local\\Microsoft\\WindowsApps\\wt.exe"

其中 [user_name] 是使用者电脑的用户名,wt_32.ico 可以是随便找的一张缩略图,也可以直接用 icons - yanglr 中的 wt_32.ico。

  为了简单美化一下 Windows Terminal 界面,需要安装 Cascadia Code GitHub releases page 中 Cascadia Code PL 或 Cascadia Mono PL 字体,Shaun 因为只是尝鲜所以就简单配置了一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
"theme": "dark",
"profiles":
{
"defaults":
{
// Put settings here that you want to apply to all profiles.
},
"list":
[
{
// Make changes here to the powershell.exe profile.
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "powershell.exe",
"hidden": false,
"startingDirectory" : ".",
"acrylicOpacity" : 0.00000001,
"colorScheme" : "Campbell",
"cursorColor" : "#00CCFF",
"fontFace" : "Cascadia Mono PL",
"useAcrylic" : true
},
{
// Make changes here to the cmd.exe profile.
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "命令提示符",
"commandline": "cmd.exe",
"hidden": false
},
{
"guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
"hidden": false,
"name": "Azure Cloud Shell",
"source": "Windows.Terminal.Azure"
}
]
},

  为了在 VSCode 中使用 Windows Terminal ,需要简单设置一下默认终端,首先将设置默认终端 "terminal.integrated.shell.windows" 注释掉或者直接不设置,添加设置:

1
2
"terminal.external.windowsExec": "C:\\Users\\[user_name]\\AppData\\Local\\Microsoft\\WindowsApps\\wt.exe",
"terminal.integrated.fontFamily": "Cascadia Mono PL",

如此可在 VSCode 中集成 Windows Terminal,并将其作为默认终端。

后记

  在这两三天的使用过程中,发现 Windows Terminal 和 Cmder 之间还是存在差距的(如在输入命令过快的时候,tab 键补全跟不上等问题),暂时就两者先并行使用一段时间吧,等后续更新巨硬修复这些问题,相信 Windows Terminal 是能代替 Cmder 成为 Windows 首选终端的。

参考资料

[1] 【避坑】PowerShell:因为在此系统上禁止运行脚本 附原因和解决办法

[2] 新发布的Windows Terminal如何添加到右键菜单?

[3] Setting Windows Terminal as Default External Terminal in Visual Studio Code

快速判断三角形与长方体相交

前言

  一种快速判断空间中三角形与 box 相交的方法,出自论文:Tomas Akenine-Moller. Fast 3D triangle-box overlap testing. A. K. Peters, Ltd. 2002.

前言

  一种快速判断空间中三角形与 box 相交的方法,出自论文:Tomas Akenine-Moller. Fast 3D triangle-box overlap testing. A. K. Peters, Ltd. 2002.

预备篇

  该论文的理论基础来自分离轴理论(separating axis theorem, AST),AST 常用于检测两凸多边形是否相交。一句话描述 AST 即为:若两多边形能用一条直线分隔开,则两多边形不相交。如何判断该直线存在即为 AST 的关键。常用的判断方法为找出两多边形所有边向量(多边形相邻两点构成的向量,顺时针或逆时针都行)的法向量,使用向量点积分别计算两多边形在各法向量上的投影(一般以多边形上的点和原点构成一个向量与法向量做点积),从而得到两个投影集合,判断两集合是否相交(找出两个集合的最大值和最小值,若最小值大于最大值,则不相交),若不相交,则 AST 中的直线存在,即两多边形不相交,若相交,则继续判断在其它法向量上的投影,若所有法向量上的投影都相交,则两凸多边形相交。AST 常用于二维下判断两凸多边形的相交情况,三维下的情况比较复杂。

正文篇

  该论文给定 13 个向量,若 box 的边和三角形的边在这 13 个向量中的投影均相交,则认为 box 与三角形相交。为简化运算,box 直接假定为轴向包围盒(axis-aligned bounding box, AABB),坐标轴原点为 box 中心,由于可以将普通 box 通过旋转平移等一系列变换,变成以原点为中心的 AABB, 所以该假定是有效的。设三角形的顶点为 \(v_0, v_1, v_2\) ,box 的一半长宽高为 \(h_x, h_y, h_z\) ,则这 13 个向量分别为 \(e_0(1, 0, 0), e_1(0, 1, 0), e_2(0, 0, 1)\) ,三角形的法向量 \(n\) (通过三角形两边向量叉乘得到),剩下九个向量分别为 \(a_{ij} = e_i \times f_j , i,j \in \{0, 1, 2\}\) ,其中 \(f\) 为三角形的边向量 \(f_0 = v_1 - v_0, f_1 = v_2 - v_1, f_2 = v_0 - v_2\)\(\times\) 代表向量叉乘。若直接这样一个个的计算投影是否相交,虽然能达到目的,但快速就无法体现了,所以作者根据向量计算方法和一些策略将其中一些需要计算投影的地方极大的简化了,所以加快的计算速度。具体简化过程为:

  1. 首先来看最后九个向量,\(a_{00} = e_0 \times f_0 = (0, -f_{0z}, f_{0y})\) ,三角形三个顶点在在该向量上的投影分别为:

    \(p_0 = a_{00} \cdot v_0 = (0, -f_{0z}, f_{0y}) \cdot v_0 = v_{0z}v_{1y} - v_{0y}v_{1z}\)

    \(p_1 = a_{00} \cdot v_1 = (0, -f_{0z}, f_{0y}) \cdot v_1 = v_{0z}v_{1y} - v_{0y}v_{1z} = p_0\)

    $p_2 = a_{00} v_2 = (0, -f_{0z}, f_{0y}) v_2 = (v_{1y} - v_{0y})v_{2z} - (v_{1z} - v_{0z})v_{2y} $

    由于 \(p_0 == p_1\), 所以在求最大最小值时只需要做一次比较,接着求 box 在该向量上的投影,box 中心在原点,所以投影半径 \(r\) 可以以一种简单的方式求出:

    \(r = h_x|a_{00x}| + h_y|a_{00y}| + h_z|a_{00z}| = h_y|a_{00y}| + h_z|a_{00z}|\)

    计算投影是否重合也很简单:

    \(if(min(p_0, p_2) > r \ || \ max(p_0, p_2) < -r) \quad return \ false\) 否则两者投影相交,继续计算其它向量。

  2. 三个轴向单位向量 e 中的投影是否重合就更好判断了,完全不需要计算投影,只需要计算三角形的最小 AABB,判断两个 AABB 是否相交即可(取两个 AABB 最小的顶点和最大的顶点,从三维上判断最小是否的大于最大的即可,若任意一个维度上最小的比最大的大,则两者不相交),

  3. 至于判断最后一个向量——三角形的法向量上的投影是否重合,相当于判断三角形所在平面是否与 box 相交。判断 box 与平面相交有一种简单快速的方式,即通过公式 \(|d| <= a_1 |n \cdot A^1| + a_2|n \cdot A^2| + a_3 |n \cdot A^3|\) ,其中 \(d\) 为 box 中心到平面的距离(中心点到平面上一点构成的向量与平面法向量做点积),\(n\) 为平面法向量,\(A^1\) 为 box 侧面法向量,对于 AABB 可为 \((1, 0, 0)\)\(a_1\) 为 box 中心到侧面的距离,对于 AABB 可为 \(h_x\),同理 \(A^2\) 为 box 顶面法向量,对于 AABB 可为 \((0, 1, 0)\)\(a_2\) 为 box 中心到顶面距离,对于 AABB 可为 \(h_y\)\(A^3\) 为 box 正面法向量,对于 AABB 可为 \((0, 0, 1)\)\(a_3\) 为 box 中心到正面距离,对于 AABB 可为 \(h_z\),即在 AABB 中,该公式可简化为 \(|d| <= h_x|n_x| + h_y|n_y| + h_z|n_z|\) ,满足该公式,即可判定平面与 AABB 相交。

  如此 13 个向量全部判断完毕,如全都相交,则可认定三角形与长方体相交,若其中一个不相交,则三角形与长方体不相交。三维的都能判断,二维的三角形与矩形相交判断就更简单了,分成两类法向量后,利用向量运算先简化运算量,再计算投影是否相交即可。

附录

  还有一种根据距离判断两个 AABB 是否相交的办法,即先取两个 AABB 的中心 \((x_1, y_1, z_1)\)\((x_2, y_2, z_2)\),然后计算两个中心点之间的三个维度的距离,将 x 维度的距离与两个AABB 的 \(h_x\) 之和比较,若中心点 x 维度的距离较大,则不相交。即:\(if (|x_1 - x_2| > h_{x1} + h_{x2}) \quad return \ false\) ,否则比较 y 维度, z 维度,若所有都小,则两 AABB 相交。这种方式是 Shaun 在一次面试中被问到没答出后在网上找到的答案,其实感觉和比较最小最大顶点也差不多,都是从不相交出发,因为直接判断相交基本不可能,而不相交很容易判断,把所有的不相交情况判断完,那就只剩相交了,可惜面试官只想要这种方案 ╮(╯▽╰)╭。

参考资料

[1] Code by Tomas Akenine-Möller

[2] Simple Intersection Tests For Games

网页菜单纯 css 实现

前言

  最近搞了些前端的工作,本来做菜单栏的时候想直接用 bootstrap 的,但是感觉 bootstrap 太大了,而且依赖有点多,在 webpack 中也不是很好打包(虽然可以绕过去),所以就索性自己在网上找了一些实现方式,改改感觉也还可以。这次主要实现了两种菜单栏,具体如下。

前言

  最近搞了些前端的工作,本来做菜单栏的时候想直接用 bootstrap 的,但是感觉 bootstrap 太大了,而且依赖有点多,在 webpack 中也不是很好打包(虽然可以绕过去),所以就索性自己在网上找了一些实现方式,改改感觉也还可以。这次主要实现了两种菜单栏,具体如下。

鼠标悬停下拉菜单

  鼠标悬停下拉菜单应该是最常见的一种菜单栏了,当鼠标悬停在菜单栏上时,子菜单缓缓下拉,看起来就很舒服,用 flex 布局结合列表也很好实现(不用像以前那种 float 了,舒服)。具体实现方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<style>
.flex-body {
display: flex;
flex-direction: column;
}

header {
z-index: 1;
}

ul,
ul li {
list-style: none;
margin: 0;
padding: 0;
}

.menu {
display: flex;
justify-content: start;
}

ul li {
width: 100px;
height: 50px;
line-height: 50px;
}

.menu li .submenu {
/* display: none; */
background-color: aqua;
}

.submenu li {
height: 0;
line-height: 0;
opacity: 0;
visibility: hidden;
}

.menu li:hover .submenu li {
/* display: block; */
height: 50px;
line-height: 50px;
opacity: 1;
visibility: visible;
transition: all 1s;
}
</style>
<div class="flex-body">
<header>
<ul class="menu">
<li>
<a>menu1</a>
<ul class="submenu">
<li><a>submenu1</a></li>
<li><a>submenu1</a></li>
<li><a>submenu1</a></li>
</ul>
</li>
<li>
<a>menu2</a>
<ul class="submenu">
<li><a>submenu1</a></li>
<li><a>submenu1</a></li>
<li><a>submenu1</a></li>
</ul>
</li>
<li>
<a>menu3</a>
<ul class="submenu">
<li><a>submenu1</a></li>
<li><a>submenu1</a></li>
<li><a>submenu1</a></li>
</ul>
</li>
</ul>
</header>
<main>mainmainmainmainmainmainmainmainmainmain</main>
</div>

  ※注: 实现该菜单栏有两个需要注意的点:1、不能用 display: noneblock 来使子菜单消失或出现,因为这样会造成缓缓下拉的动画失效,transition 并不支持 display,所以只能用 visibilityheight 来共同实现,以达到下拉动画效果;2、因为使用了 flex 布局,所以 z-index 只对同级 flex-item 有效,所以为防止菜单栏下面的内容出现在子菜单之上,即将子菜单栏位于最上层,需要将整个页面的布局都设置为 flex,并使 headerz-index 最大,如此才能保证子菜单的菜单覆盖 main 中的内容,不然就会有重叠干扰现象。

鼠标点击手风琴菜单

  手风琴特效也算是非常常见的了,一般的手风琴是鼠标悬停展开,这种比较好实现,难的是如何保持这种展开状态,focus 可以短暂保持展开状态,但是不能点击其他地方,局限性太大。所以需要引入其它的东西来记录这种展开状态,可以用 checkboxradiochecked 来记录这种状态,从而只用 css 即可实现该菜单,具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<style>
input[data-prop="menu-recorder"] {
display: none;
}

.menu-title {
display: block;
width: 500px;
height: 50px;
line-height: 50px;
border: 1px solid black;
}

.menu-content {
width: 500px;
max-height: 100px;
overflow-y: auto;
}

.menu-content>li {
height: 0;
line-height: 20px;
overflow: auto;
opacity: 0;
visibility: hidden;
transition: all 1s;
}

input[data-prop="menu-recorder"]:checked+.menu-content>li {
height: 20px;
line-height: 20px;
opacity: 1;
visibility: visible;
transition: all 1s;
}
</style>
<div class="accordion-menu">
<section class="menu-item">
<label class="menu-title" for="menu1">menu1</label>
<input id="menu1" type="checkbox" data-prop="menu-recorder">
<div class="menu-content">
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
</div>
</section>
<section class="menu-item">
<label class="menu-title" for="menu2">menu2</label>
<input id="menu2" type="checkbox" data-prop="menu-recorder">
<div class="menu-content">
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
</div>
</section>
<section class="menu-item">
<label class="menu-title" for="menu3">menu3</label>
<input id="menu3" type="checkbox" data-prop="menu-recorder">
<div class="menu-content">
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
</div>
</section>
<section class="menu-item">
<label class="menu-title" for="menu4">menu4</label>
<input id="menu4" type="checkbox" data-prop="menu-recorder">
<div class="menu-content">
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
</div>
</section>
</div>

  这里需要注意一点的就是 height 从 0 到 100% 并不会触发 transition 渐变动画,而是需要确切的高度值变化才能触发,所以上文这里添加了个 <li> 标签,直接在该标签上添加动画,还有一种就是在 .menu-content 上设定确定的 max-height,也能触发动画,但是有个缺点就是前后 max-height 的差距太大时,动画效果就很不理想了,这时可能只能依靠 js 了。上文中 checkbox 也可用 radio 替换,效果略有差异,一个是能全部展开或收起,而另一个则是能且仅能展开一个。

Tab 标签页切换菜单

  这个菜单和上面那个菜单的实现非常相似,先上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<style>
.tab-menu {
display: flex;
position: relative;
width: 500px;
height: 300px;
}

input[data-prop="menu-recorder"] {
display: none;
}

.menu-title {
display: block;
width: 100px;
line-height: 50px;
text-align: center;
border: 1px solid black;
border-right: 0;
box-sizing: border-box;
transition: all 1s;
}

.tab-menu .menu-item:last-child .menu-title {
border-right: 1px solid black;
}

.menu-content {
position: absolute;
left: 0;
top: 51px;
height: calc(100% - 50px);
overflow-y: auto;
width: 100%;
border: 1px solid #000;
box-sizing: border-box;
font-size: 24px;
text-align: center;
opacity: 0;
visibility: hidden;
transition: all 1s;

}

input[data-prop="menu-recorder"]:checked+.menu-content {
opacity: 1;
visibility: visible;
transition: all 1s;
}
</style>
<div class="tab-menu">
<section class="menu-item">
<label class="menu-title" for="menu1">menu1</label>
<input id="menu1" type="radio" name="tab-control" data-prop="menu-recorder">
<div class="menu-content">
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
</div>
</section>
<section class="menu-item">
<label class="menu-title" for="menu2">menu2</label>
<input id="menu2" type="radio" name="tab-control" data-prop="menu-recorder">
<div class="menu-content">
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
</div>
</section>
<section class="menu-item">
<label class="menu-title" for="menu3">menu3</label>
<input id="menu3" type="radio" name="tab-control" data-prop="menu-recorder">
<div class="menu-content">
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
</div>
</section>
<section class="menu-item">
<label class="menu-title" for="menu4">menu4</label>
<input id="menu4" type="radio" name="tab-control" data-prop="menu-recorder">
<div class="menu-content">
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
<li>test<br></li>
</div>
</section>
</div>

  从代码上看关键点就是 .menu-content 的定位方式了,采用了绝对定位,并将整个菜单栏设置为相对定位,以保证所有 tab 标签页内容位置和大小保持一致。当然 tab 标签页肯定是唯一的,所以只能用 radio 记录显示标签页了。其中为了保证 .menu-title.menu-content 的边框不重叠,所以在 .menu-title 中只设置 line-height,而 .menu-contenttop 比其多一个像素。

后记

  这三种菜单应该是最常见也是用的最多的了,纯 css 实现的方式也比较类似,无非就是 flex 布局以及借助 css3 强大的选择器功能(父类选择器不知要到猴年马月了,比较遗憾 😥),就能相对简单的实现了,当然借助一些 js 库或框架可能会更简单一些 ,但能用 css 为何不用呢 😄。

参考资料

[1] 利用flex实现的二级导航栏

[2] CSS3动画下拉菜单(当transition遇到display的坑)

[3] CSS3手风琴下拉菜单

[4] 教你两招用纯CSS写Tab切换

hexo-theme-chi主题更新小记

前言

  Chi 主题的大体结构功能算是写完了,但是还有一些个性化的东西需要添加,所以以后有关于 Chi 主题更新的部分就都写在这里吧。但是由于是 Shaun 个性化定制的一些东西,所以如果不是大 Bug 或大优化的更新,一般就不进 Chi 主题仓库 中了。

前言

  Chi 主题的大体结构功能算是写完了,但是还有一些个性化的东西需要添加,所以以后有关于 Chi 主题更新的部分就都写在这里吧。但是由于是 Shaun 个性化定制的一些东西,所以如果不是大 Bug 或大优化的更新,一般就不进 Chi 主题仓库 中了。

功能篇

1. 脚注提示功能

功能描述: 鼠标悬停在脚注上即可显示对应脚注内容。 Shaun 的脚注由于是采用 pandoc 渲染的,所以也是属于个性化定制,就不将这个功能放进 Chi 主题仓库中了。

解决方案: 还是利用 Bootstrap 的 tooltip 提示插件,具体实现代码如下:

1
2
3
4
5
6
7
$('a.footnote-ref').each(function (index, elem) {
let post_id = $(this).parents('article').attr('id');
let fn_href = $(this).attr('href');
elem.setAttribute('data-toggle', 'tooltip');
elem.setAttribute('data-html', 'true');
elem.setAttribute('title', $("#" + post_id + " " + fn_href).html());
});

遍历脚注,先获取文章 id,再获取对应文章下的对应脚注内容,使用 tooltip 提示。

Bug 篇

1. 图片没居中

问题描述: 上次那篇翻译的文章有几张图片,在放置的时候发现图片没有居中,查看代码后发现居中样式没写,但由于其图片标签 <img> 是放在一个 <figure> 标签中,由于不确定是不是 pandoc 渲染的问题,所以就没将这个修正放进 Chi 主题仓库中了。

解决办法:style.styl 文件中添加样式:

1
2
3
figure {
text-align: center;
}

即可让图片居中。

动画篇

1. 鼠标跟随动画

  其实一直都想把『奥日与黑暗森林』中的鼠标轨迹特效移植过来,但是苦于水平有限,一直没法做到,恰好 19 年 StackOverflow 的愚人节彩蛋中有个鼠标跟随动画很有意思,有好事者还专门将该彩蛋做了个脚本:Will there be an option to permanently keep this year's April Fools design active? 。查看代码,知道实现原理后,发现用 jQuery 和 CSS3 实现一个类似的效果也不算很难,于是 Shaun 就尝试做了一下,并简单的美化了一下,感觉效果还行,就加到自己的个性化主题上了。至于在 Chrome 中的小尾巴和 Firefox 中的卡顿现象,是 Shaun 故意的,因为 Shaun 觉得这个小尾巴很有意思,从这个动画看,Chrome 确实比 Firefox 要流畅一点。最终实现代码如下:

css 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.cursor-trail--item {
display: inline-block;
line-height: 1px;
position: fixed;
pointer-events: none;
touch-action: none;
z-index: 9999999;
will-change: transform;
font-size: 10px;
color: rgba(186, 227, 240, 0.1);
text-shadow: 0 0 2px #6CC2F8;
-webkit-animation: cursorTrail 0.9s ease;
animation: cursorTrail 0.9s ease;
}

@keyframes cursorTrail {
0% {
opacity: 1;
}

20% {
opacity: 0.5;
transform: scale(5);
}

100% {
opacity: 0;
transform: translate3D(0, -20px, 0) scale(1) rotate(90deg);
}
}

js 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$(document).on('mousemove', function (e) {
e.preventDefault();
if (this.time && (Date.now() - this.time) < 16) return;
this.time = Date.now();
let trail_character = '•';
let mouse_x = e.originalEvent.x || e.originalEvent.layerX || 0;
let mouse_y = e.originalEvent.y || e.originalEvent.layerY || 0;
mouse_x = mouse_x + 20;
mouse_y = mouse_y + 26;


$('#cursor-trail').append(
'<span class="cursor-trail--item" style="left:'
+ mouse_x
+ 'px;top:'
+ mouse_y
+ 'px;">'
+ trail_character
+ '</span>'
);

$('.cursor-trail--item').each(function () {
let item = $(this);
setTimeout(function () {
$(item).remove();
}, 900);
});
});

若不要小尾巴,则只需要将移除元素的时间改快一点就行了,除开上面的代码,还需要在 html 页面中添加一个元素 <span id="cursor-trail"></span>

2. 点击波纹

  一次偶然的机会,看到一篇这样的文章:还原一个 Windows 10 Metro 布局 。感觉其中的点击波纹动画很有意思,Shaun 决定把这个动画也放进自己的个性化主题中。至于代码就不贴了,毕竟就是上面文章提供的代码,只是用这个动画的时候发现了 Chrome 的一个问题,就是在进行模糊动画的时候会出现正方形的右边框和下边框,单个模糊不进行动画,不会有边框,进行动画但没模糊也不会有边框,两个同时一起就会出现问题,Firefox 没有这个问题,但 Firefox 存在另一个问题,就是鼠标快速连点的时候,鼠标跟随动画可能会出现问题。浏览器的问题 Shaun 暂时没法解决了,就先这样吧 ╮(╯▽╰)╭。虽然对 Chrome 为啥会出现这样的问题有些猜想,但还是不说出来丢人了,万一不是 Shaun 想的这样就尴尬了 ,,ԾㅂԾ,, 。

后记

有更新再继续更新吧。

[译]为什么深度学习没有取代传统的计算机视觉

前言

  这是一篇译文,译自:Why Deep Learning Has Not Superseded Traditional Computer Vision,原作者为:Zbigatron 。Shaun 水平有限,仅供参考学习,更多内容还请自行查看原文。

至于为什么要翻译这篇文章,算是回答别人的一个问题吧。

前言

  这是一篇译文,译自:Why Deep Learning Has Not Superseded Traditional Computer Vision,原作者为:Zbigatron 。Shaun 水平有限,仅供参考学习,更多内容还请自行查看原文。

至于为什么要翻译这篇文章,算是回答别人的一个问题吧。

为什么深度学习还没有取代传统的计算机视觉?

scale-cv-dl

  编写这篇文章的原因是在论坛中经常有人问:深度学习是否取代了传统的计算机视觉?或者类似的问题:深度学习效果这么好,还有继续研究传统计算机视觉的必要?

  这是个好问题,深度学习(DL)确实彻底改变了计算机视觉(CV)和人工智能,许多曾经看起来不可能解决的问题都解决了,甚至达到了 机器的结果比人类更好 的程度,比如图像分类。正如 我之前讨论的深度学习确实为计算机视觉做了很大的贡献

  但是深度学习只是计算机视觉的一个工具,并不是解决所有问题的万能药,所以,在这篇文章中,我想详细说明一下为什么传统的计算机视觉仍然非常有用,并且应该继续学习。

这篇文章主要有一下几个观点:

  • 深度学习需要大量数据;
  • 深度学习有时大材小用了;
  • 传统的计算机视觉可以辅助深度学习。

  但是在我开始讨论这些观点之前,需要先解释一下什么是传统的计算机视觉,什么是深度学习,以及深度学习为何这么 dio。

背景知识

  在深度学习之前,如果要实现图像分类这样的功能,需要首先进行 特征提取。特征即为图像中的信息块,能代表图像的部分信息,可以通过 边缘检测角点检测物体检测 等技术来提取特征。

  在进行特征提取和图像分类之类的工作时,一个想法是从一类对象(例如椅子,马等)的图像中提取尽可能多的特征,并将这些特征视为对象的一种定义(比如 词袋模型),然后在其他图像中查找这些定义,若另一个图像中的特征和定义的特征很相似,则该图像可能包含该特定的对象(如椅子,马等)。

  在图像分类中,这种特征提取的难点在于每个图像都必须选择哪些特征进行查找,当需要分类的类别开始增加时,比如 10 或 20 种类别,这种方式将变得很麻烦以至于不可能实现。当然也可以考虑角点、边缘和纹理信息,使用不同的特征可以更好的描述不同类别的对象,但是如果选择使用很多特征,则必须处理大量参数,所有这些参数都必须微调。

  深度学习中有一个端到端学习的概念,其含义为告诉机器要针对每个特定类别对象学习需要查找的特征,它为每个对象设计了最具描述性和显著性的特征,换言之,告诉神经网络要发现图像中每个类别的基本模式

  因此,通过端到端学习,不需要再决定使用哪种传统的计算机视觉技术来描述特征,机器自动选择好了,Wired magazine 说过:

如果想教一个神经网络识别一只猫,不需要让它寻找胡须、耳朵、皮毛和眼睛,只需要给它大量猫的图像,它就会自动识别猫,若它将狐狸错认成猫,不需要重写代码,只需要继续训练即可。

下图表示了特征提取(使用传统计算机视觉)和端到端学习之间的差异:

traditional-cv-and-dl

  以上就是需要的背景知识,下面开始深入探讨为什么传统的计算机视觉仍然有存在的必要。

深度学习需要大量数据

  首先,深度学习需要大量的数据,那些著名的图像分类模型就是在海量数据集上训练的,训练数据集中最大的三个是:

  一般的图像分类任务不需要这么多图片,但仍然需要很多,如果没办法获得这么多图片怎么办?我们还是得训练我们所有的数据(有些方法可以增多我们的训练数据,但这些都是人工方法)。但是,没有足够的数据支持,训练出来的模型可能会在训练集之外表现不好,因为机器没有洞察能力,无法对没有的数据进行分类。而且无法直观查看训练好的模型并手动调整里面的数据,因为深度学习模型里面有数百万个参数,并且这些参数在训练时会自动微调,某种程度上,深度学习模型就是一个黑盒子。

  传统的计算机视觉完全透明,可以很清楚的判断自己的解决方案在训练数据之外是否可行,而且可以深入了解算法中存在的问题。如果有没法解决的问题,也可以更容易的找出原因并调整。

深度学习有时大材小用了

  这可能是我支持传统计算机视觉技术研究的最佳理由。

  训练深度神经网络需要很长时间,而且需要专门的硬件(高性能 GPU),如果想在普通的笔记本上训练最先进的图像分类模型,可以去外面玩一个星期,回来之后应该还没训练完 :) 。而且,如果训练好的模型表现不好怎么办?必须调整训练参数并重新开始训练,这个过程有时会重复数百次。

  但有时候使用深度学习是完全没有必要的,因为有时传统的计算机视觉技术可以比深度学习更有效的解决问题并且代码更少。比如,我曾经做过一个项目来检测传送带上每个罐头是否都有红色的勺子,解决这个问题可以训练深度神经网络来检测勺子,也可以针对红色编写一个简单的阈值分割算法(红色的某个范围内的像素点为白色,其它像素点为黑色),然后计算有多少个白色像素点,后者明显简单的多,一个小时就完成了。

  了解传统的计算机视觉有时会节省大量时间和避免不必要的麻烦

传统计算机视觉提高改进深度学习技能

  了解传统的计算机视觉可以帮助我们更好地进行深度学习。

  例如,计算机视觉中使用的最常见的神经网络是卷积神经网络。但什么是卷积?它实际上是一种广泛使用的图像处理技术(例如 Sobel边缘检测)。了解这一点可以帮助我们了解神经网络正在做什么,并因此可以更好的设计和调整神经网络来解决问题。

  深度学习中还可以对图像进行预处理,所谓的预处理是指对训练的数据进行一定的处理(Shaun 注:比如图像增强,图像去噪等),这些预处理操作一般由传统的计算机视觉技术完成,比如:当没有足够的训练数据时,可以使用一种叫数据增强的技术,使用数据增强让图像进行旋转,平移,裁剪等操作,从而增加“新”图像,通过执行这些操作,可以成倍的增加训练数据集。

总结

  在这篇文章中,我解释了为什么深度学习还没有取代传统的计算机视觉技术,因此还需要研究后者。首先我发现了深度学习要想表现的足够好需要大量数据的问题,有时候没法获得大量数据,这时只能用传统计算机视觉技术代替;其次,对于特定的任务,使用深度学习可能大材小用了,传统计算机视觉有时比深度学习更有效且代码量也更少;最后了解传统的计算机视觉可以更好的学习深度学习,因为这可以使我们更好的了解深度学习的内部机制,并且可以使用某些预处理操作来改善深度学习结果。

  简而言之,深度学习只是计算机视觉的一个工具,不是万能药,不要只是因为它现在很流行所以使用它,传统的计算机视觉技术仍然十分有用,了解它可以节省时间和避免许多麻烦。

后记

  翻译这篇文章的原因在于,因为某些原因,Shaun 不得不回答一个 “为什么不用深度学习?” 的问题,虽然这里面有极大的因素是客观原因(设备不够 ╮(╯▽╰)╭),但 Shaun 不能明说,正好在网上看到这篇文章,加上也看到过一个问题(类似于 “既然已经能用深度学习做高层次的工作,为何还要用深度学习做底层的工作?”,比如深度学习能做全景分割(可以说是基本完成了图像理解),为何还要做目标检测,图像分割),预计以后有很大的概率也会被问到,所以就需要借用文中的一些观点来进行回答。至于为啥还要用深度学习做底层的工作,可以这样认为,如果用深度学习做底层工作效果不错的话,应该可以对上层工作进行一些辅助,并且可以为上层工作的做法提供一些新的思路。

hexo-theme-chi主题开发小记

前言

  2019 年 2 月 20 日,Shaun 的站点主题终于完成了,终于能用上自己的主题了,开心 ~( ̄▽ ̄~)。

前言

  2019 年 2 月 20 日,Shaun 的站点主题终于完成了,终于能用上自己的主题了,开心 ~( ̄▽ ̄~)。

  在网上看到的建议都是多写内容少整主题,但强迫症表示受不了,Shaun 就是想要一个自己的主题,自己怎么看着舒服就怎么来,即使没有一个访客,至少也要让自己看着舒服,自己想怎么设计就怎么设计,想用什么技术就用什么技术,想怎么排版就怎么排版,尽量少受写约束,总而言之,Shaun 喜欢自由。

回顾篇

  自己写主题的想法由来已久,应该是从 17 年 12 月份开始的吧,当时就感觉自己魔改的 spfk_x 主题只能勉强符合自己的需求,但是因为已经用的是别人已经完成的框架,大体框架也不好做太多修改(如果要改的话还不如自己重新写一个),而且里面由于经手太多人的修改,里面的代码结构在 Shaun 看起来有点混乱,而且有很多冗余的代码,有些代码甚至完全没有用上,导致修改起来有点麻烦。

  至于为什么不在 17 年寒假期间就开始写,而要拖到 18 年 12 月份才开始动手,一部分原因是 Shaun 的拖延症,一部分原因是还没具体想好该怎么布局,该用什么技术,还有一部分就是外在客观原因了。

  18 年 12 月份开始动手写,是因为这段时间稍显空闲,虽然白天还是一样的忙,但至少没那么多心里负担了,而且此时 Shaun 对于自己想要的大体布局已经十分清楚了(虽然一些具体细节还没不是那么清楚),所以就趁着晚上有时间写写,有时候晚上高兴或没事干就写写,有时候没想法或还没想好具体怎么实现就不写,就这样断断续续的写,总算在 19 年 2 月完成了。

  本来想在 19 年之前完成的,可是由于本人的拖延症和一些客观原因,还是超期了很久,侯世达定律总是存在的( sigh~😔),不过总的开发时间也差不多是一个月吧。感觉花费这一个月的晚上时间还是挺值得的,虽然从中学到的东西不多,但总算也有点自己的东西了。

实现篇

  既然要开始写主题了,首先当然要想一个主题名字,本来最初是直接取原来主题的首尾字母作为名字,但后面想了想感觉有点不对劲,有点骂人的意味在里面 (´ ; ω ; `),后面又想了想,就用尾字母 X 算了,反正站点图标也是那个,后面感觉还是不好,单字母太单一了,后面突然想到希腊字母,就以希腊字母的英语命名了。

  名字想好之后,就要决定用什么技术了,由于 Shaun 只是一个前端小白,无论用什么技术对 Shaun 来说难度都差不多,Shaun 理想的主题是能够支持响应式的,所以为了尽可能简单的支持响应式,CSS 方面的库就采用 Bootstrap4,CSS 预处理器当然是用 Stylus 了, JS 方面最令 Shaun 纠结,到底是采用现代的 Vue 还是传统的 jQuery,最终从相对熟悉程度和相关资料广度方面考虑,Shaun 最终选择了 jQuery3(以后有机会再尝试一下 Vue 吧),接下来要选择的是 Node.js 模板引擎,候选的主要有三个 EJS、Swig 和 Jade(现已更名Pug),Shaun 原来的主题是用 EJS 的,著名的 NexT 主题用的 Swig,而 Pug 的语法目前有点接受不能,所以直接放弃了,而 Swig 早已停止更新,所以也放弃了,所以最终选择的还是相对熟悉的 EJS(而 EJS 最近的一次提交时间为 2018 年 11 月 28 日,看来应该也是要停止更新了,以后有机会试试 Pug 吧)。

  技术决定之后,就要开始写了,最开始写的时候,由于不清楚 hexo 的工作机制,导致完全无法显示页面,后面查阅了几篇关于如何写 hexo 主题的文章,加上自己的慢慢摸索,终于弄懂了,hexo 的最初页面需要有一个 index 文件,在 index 中写入的东西,将会显示在 http://localhost:4000/ 页面中,好了,终于能显示内容了,接下来要解决的是布局问题,hexo 的所有页面渲染都会通过一个叫 layout 的文件,layout 文件中必须存在一个 <%- body %> 语句,在渲染时,hexo 会用其它页面的内容替换 layout 中的 <%- body %> 语句,包括 index 中,所以在 layout 中写好 HTML 框架之后,其它页面只需要负责写内容就行。实现一个最简单的主题(只有纯文字版网页),只需要下面几步:

  1. 在 index.ejs 文件中写入 <%- include('_partial/archive', {item: page, is_index: true}) %>
  2. 然后在 _partial 文件夹中 archive.ejs 文件中写入:
1
2
3
4
5
6
7
8
9
10
<% page.posts.each(function(item) { %>
<%- include('article', {item: item, is_index: true}) %>
<% }) %>

<% if (page.total > 1){ %>
<%- paginator({
prev_text: '&laquo; Prev',
next_text: 'Next &raquo;'
}) %>
<% } %>
  1. 在 _partial 文件夹中 article.ejs 文件中写入 <div><%- item.content %></div>
  2. 最后在 layout.ejs 文件中写入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
</head>

<body>
<div>
<%- body %>
</div>
</body>

</html>

即可将文章内容显示出来,前提是已有文章。当然也可把上面的1~3步合起来算作一步,直接在 index.ejs 文件中写入:

1
2
3
4
5
6
7
8
9
10
<% page.posts.each(function(post) { %>
<div><%- post.content %></div>
<% }) %>

<% if (page.total > 1){ %>
<%- paginator({
prev_text: '&laquo; Prev',
next_text: 'Next &raquo;'
}) %>
<% } %>

这样就算是实现了一个最简单的主题,只是这个主题十分丑陋,文章也没有对应的标题。

※注: 在写这几步的时候,Shaun 在这里发现 hexo-browsersync 插件和 hexo s 命令有冲突,会造成一个bug:hexo s 启动后,页面加载错误,大BUG,具体表现为:当直接使用 <%- post.content %> 在首页显示文章时,index.html 将会无法加载完全,后面的一部分会加载错误。解决办法为:卸载 hexo-browsersync 插件。

  完成上面几步,就算是写主题已经入门了,万事开头难,入门之后就相对简单了,只要按部就班的一步步走下去就行了,接下来就是慢慢进行排版布局问题,就这样,Shaun 一边参考其它一些主题的排版和写法,一边查阅网上资料实现自己的想法,一步一步的解决问题,直到完成该主题。

PS: 主题配置文件 _config.yml 中的配置变量的命名和其它编程语言一样,不能以数字作为第一个字符

文档篇

  Chi 主题涉及到的技术主要为:Bootstrap4、jQuery3、Stylus、EJS、HTML5、CSS3、ES6 等;运行环境为:node-v8.11.1、Hexo-3(hexo-cli-1.1.0)等;测试浏览器为Firefox 60.5.0 esr 和 Chrome 72.0.3626.109,其它浏览器没测过,也不考虑测,有兴趣的童鞋可以自己测自己改。

  Chi 主题的配色主要参考 Shaun 原来的主题 spfk_x,排版部分参考了 hexo-theme-freemind,部分代码也是来自这两个主题。Chi 主题的一些动画实现优先采用 CSS,除了那些无法用 CSS 实现或 Shaun 不知道如何用 CSS 实现的,所以 JS 代码部分不算很多,网页加载速度也勉强能够接受吧。

  Chi 主题的代码高亮部分本来想参考 为hexo博客加入prettify高亮插件 使用prettify替换默认的代码高亮,但使用了之后发现效果不是很好,就还是使用默认的样式了。

  Chi 主题的使用文档暂时就不写了,毕竟这个主题只是 Shaun 个人使用(应该也不会有其他人使用了,万一真有人要用却不太会用,欢迎提 issue,以后酌情考虑添加使用文档 🙃),由于 Shaun 只是前端小白,这个主题也只是当学习练手开发,里面肯定会有各种各样的问题,欢迎提 issue 或 fork 或 clone 后自行修改,提 issue 的话,Shaun 不保证一定能解决,毕竟水平有限,当然如果有代码优化想法还望不吝赐教 (。・ω・。)ノ♡ (至于 px 换 em 或 rem 就不用提了,没什么原因,主要是 Shaun 懒,更深层的原因在于 Shaun 手头上还没有更高分辨率的显示器,不知道显示差距有多大,不好进行测试 😓)。

PS: Shaun 使用了 Hexo 博客美化代码块| 梦魇小栈 中的脚本对 Markdown 代码部分进行了美化渲染,但是该脚本有时候渲染会出现一些问题,无法进行美化,可能是代码语法格式有错误,这时需要自己手动调整一下 Markdown 代码格式

使用 Chi 主题推荐安装插件:

  • hexo-renderer-pandoc # 使用pandoc渲染markdown,安装前需卸载默认渲染器hexo-renderer-marked
  • hexo-generator-feed # RSS订阅
  • hexo-generator-searchdb # 本地搜索
  • hexo-abbrlink # 文章唯一永久链接
  • hexo-all-minifier # 快速压缩优化代码

好了,暂时就写到这里了。

后记

  当 Shaun 有一天使用其它 blog 框架时,这个主题可能就不再维护更新了,但其中的排版样式应该还会或保留或更新。下面要做的事就不立 Flag 了,因为立了多半会完不成,这就很尴尬了,但不立又没有动力,真是让人脑壳疼啊 (๑•ั็ω•็ั๑),反正是一件长期要做的事了,长到可能接下来的业余时间可能都在做这件事,或开源或不开源,看以后的心情和完成程度了 (↖(^ ω ^)↗)。