NeRF 其一:NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis

NeRF 其一:NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis

  • 1. 什么是神经辐射场
  • 2. 论文简述
  • 3. 体渲染
    • 3.1 视线
    • 3.2 体渲染-连续
    • 3.3 体渲染-离散
  • 4. 神经网络与位置编码
  • 5. 损失函数与训练策略
    • 5.1 网络训练
    • 5.2 损失函数

Reference:

  1. 深蓝学院:NeRF基础与常见算法解析

系列文章:

  1. NeRF 其一:NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis
  2. NeRF 其二:Mip-NeRF

在这里插入图片描述

首先来看看 NeRF 开山之作的标题----NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis:

  • 使用神经辐射场来表达场景
  • 以完成视角合成的目标

1. 什么是神经辐射场

因此 NeRF 的目标也就相当清楚了:首先拍摄多视角的图像,然后要拿到这些图像对应的内外参数(可以使用 COLMAP),这时使用神经网络去学习三维场景内的辐射值(学习不同方向的光线),然后就可以在不同视角下做可视化了。
在这里插入图片描述这里要明白 光线(ray) 的含义,它是由 相机/眼睛 发出,已知会穿过实际 3D 物体的一条虚拟射线,如下图所示:
在这里插入图片描述

图中的 Image Plane 就是我们最后想得到的图,我们要用 NeRF 找到 Image Plane 上面每个像素的 RGB。

那么怎么找呢?就是利用图中的箭头,也就是我们说的 Ray,首先使用 NeRF 找到箭头与 Volume Data 也就是 3D 物体的若干交点,然后对这些交点做积分就行了。

这里并不是眼睛能发出光,而是相反只能接收光。但因为光路是可逆的,在理解问题时,可以假设眼睛发光,如下图所示。所以,一条光线对应最终图片中的一个像素,而确定光线的关键,就是要搞清楚相机的位姿,即光线的原点,因为所有的光线都是从相机 “发出” 的。
在这里插入图片描述

2. 论文简述

在这里插入图片描述
上图表示了 ReRF 内全部的 Pipeline。假设感兴趣的三维物体场景被包含在一个虚拟的 3D 立方体内。三维空间的一个点经过一个 [R|t],就可以转到摄像机坐标系,再通过相机内参就可以转到像素平面上,这样就可以将三维空间中的颜色赋给这个值,于是整张图像就都可以得到了。但是 NeRF 中考虑的不是一个点,而是考虑这条光线上所有的点,最后生成这个像素值,这个过程就被称为体渲染技术

论文内有以下几个重点概念:

  1. 三维场景
    输入(Position+Direction):一组相机位姿 { x , y , z , θ , ϕ } n \{x, y, z, \theta, \phi\}_n {x,y,z,θ,ϕ}n
    输出(Color+Density):体密度 σ \sigma σ + 观察角度 ( θ , ϕ ) (\theta, \phi) (θ,ϕ) 看到的颜色值 C C C
    上图内虚拟方格的每一个点都有一个 ( x , y , z ) (x,y,z) (x,y,z) 空间坐标值+一个体密度值 σ \sigma σ(体密度和这个点的材质有关,比如在图中拖拉机上和空气中的体密度就是不一样的)+颜色值 C C C,但是 C C C 在不同角度看过去颜色是不一样的-----这考虑到了镜面反射
  2. 辐射场
    辐射场为定义在空间中的函数,记录了空间中每个点的体密度 σ \sigma σ 以及该点每个方向上的颜色值 C C C(也就是辐射场内辐射值的概念)
    那么问题来了,什么样的函数能够记录这么多的信息?如果在每个角度都使用查找表,那这样做空间的消耗就太大了,也并不适合做推理。所以就用到了下一个概念-------全连接神经网络,来记录辐射场信息
  3. 神经网络
    全连接神经网络 F θ F_{\theta} Fθ
  4. 体渲染(Volume Rendering)
    视线上所有的点投射到图像上形成像素颜色的过程。

图像内包含两个流程:训练流程+推理流程。
有了这些概念,我们先描述推理流程:给我一个相机位置,就可以一个像素点一个像素点的生成一张图片。从一个像素点打一条光线出去,会与虚拟立方体空间相交获得一系列的点,通过这些点和训练好的辐射场信息,可以得到每个点的颜色和体密度。再通过体渲染将这些点合成起来,即可得到当前像素点的值。
训练流程的区别在于,获得了体渲染的颜色后需要和真实值进行比较,这就形成了一个 Loss(见图(d)),使用这个 Loss 来指导神经网络的更新,越接近越好。

3. 体渲染

3.1 视线

在这里插入图片描述

上一节提到了,视线上某一点由 5 5 5 维变量表示:

  • P P P 三维空间中的一个点(三维,世界坐标);
  • θ \theta θ 为视线的俯仰角(pitch);
  • ϕ \phi ϕ 为视线的偏航角(yaw)。

这里滚转角对于射线没有意义。激光雷达也是使用的这种模型,在《自动驾驶与机器人中的SLAM技术》一书中,把这种模型称为 RAE(Range Azimuth Elevation) 模型。

视线 r r r 上的点可以表示为:
r ( t ) = o + t d \boldsymbol{r}(t) = \boldsymbol{o}+t\boldsymbol{d} r(t)=o+td

  • o \boldsymbol{o} o 是摄像机的光心在世界坐标系的坐标;
  • d \boldsymbol{d} d 为直线方向,是世界坐标系下的一个单位向量(笛卡尔坐标系);
  • t t t 是一个实数,表示从 o \boldsymbol{o} o 点沿视线到 r ( t ) \mathbf{r}(t) r(t) 点的距离。

注意在论文中使用的是 θ \theta θ ϕ \phi ϕ 二维信息,但在代码内使用的还是三维向量。给定一个视线 r \boldsymbol{r} r,即 o \boldsymbol{o} o d \boldsymbol{d} d 已知,给定一个 t t t,就可以得到一个点的世界坐标

3.2 体渲染-连续

体渲染:视线上 r \boldsymbol{r} r 所有的点投射到图像上形成像素颜色 C C C 的过程,先来体渲染在连续情况下的函数:
C ( r ) = ∫ t n t f T ( t ) σ ( r ( t ) ) c ( r ( t ) , d ) d t , where  T ( t ) = exp ⁡ ( − ∫ t n t σ ( r ( s ) ) d s ) C(\boldsymbol{r}{)=\int_{t_{n}}^{t_{f}} T(t) \sigma(\boldsymbol{r}(t)) \boldsymbol{c}(\boldsymbol{r}(t), \boldsymbol{d}) d t } \text {, where } T(t)=\exp \left(-\int_{t_{n}}^{t} \sigma(\boldsymbol{r}(s)) d s\right) C(r)=tntfT(t)σ(r(t))c(r(t),d)dt, where T(t)=exp(tntσ(r(s))ds)其中,

  • r ( t ) \boldsymbol{r}(t) r(t) 为三维空间中的一个点, d \boldsymbol{d} d 为视线方向,这在 3.1 节提到了
  • 三维场景的近端和远端边界分别为 t n t_n tn 以及 t f t_f tf
    如果没有边界,那么意味着从 [ 0 , ∞ ) [0,\infty) [0,) 都要考虑,先不说可不可实现,计算量肯定是爆炸的。这里的 t n t_n tn t f t_f tf 是需要指定的先验信息。
  • c ( r ( t ) , d ) \boldsymbol{c}(\boldsymbol{r}(t), \boldsymbol{d}) c(r(t),d) 为三维点 r ( t ) \boldsymbol{r}(t) r(t) d \boldsymbol{d} d 这个方向看到的颜色值
    因为点的颜色值和方向相关所以需要多传一个视线方向 d \boldsymbol{d} d
  • σ ( r ( t ) ) \sigma(\boldsymbol{r}(t)) σ(r(t)) 为体密度函数,反映了 r ( t ) \boldsymbol{r}(t) r(t) 位置的物理材质吸收光线的能力
    比如物体表面、物体内部、空气中,这个值都是不一样的:
    • σ = 0 \sigma=0 σ=0:全透明场景,没有吸收光线,比如空气;
    • σ = ∞ \sigma = \infty σ=:一到这里光线就会被吸走,后面的点都看不见了;
    • σ = 正数 \sigma = \text{正数} σ=正数:这个材质会吸收一部分光线,另一部分光线会透过去,比如一会作为例子的海洋。
  • T ( t ) T(t) T(t) 是射线上从 t n t_n tn t t t累积透射率
    T T T 的范围应该是从 1 1 1 开始到 0 0 0,表示还剩下多少光强。当前点的 σ \sigma σ 越大、 T T T 越大,当前点对 C ( r ) C(\boldsymbol{r}) C(r) 的贡献也就越大。

从上面公式可以知道, σ \sigma σ c \boldsymbol{c} c 都是把当前三维点信息丢进神经网络内算出来的,而 T T T 是通过积分得到的。看下面一个例子:
在这里插入图片描述

  1. 开始因为在空气中,此时 σ = 0 \sigma=0 σ=0,因为 T T T σ = 0 \sigma=0 σ=0 的积分,这时 T T T 恒为 1 1 1,即这一部分完全投射;
  2. 开始进入水下,这时候 σ \sigma σ 是有值的了;
  3. 在这一部分中, T T T 的值逐渐减小,这一阶段开始,射线上的点将会对像素颜色 C C C 产生贡献;
  4. 在这时候 T T T 为零,往下的点不参与计算;
  5. 因为这时即往下 T T T 都是 0 0 0 了,即使后续的 σ \sigma σ 是有值的,但它也不会对当前像素的颜色 C C C 产生任何贡献了。

3.3 体渲染-离散

在 3.2 小节的公式中写的是积分,但是在实际计算肯定不会是连续的,所以需要离散化。

第一个想到的肯定是均匀采样,这里的均匀采样存在一个问题:两个点的跨度太大,中间的值没采到,这样肯定是不准确的。如下面示例,两个点中间的信息就没有采集到:
在这里插入图片描述
这时就想到了随机均匀采样的方法:
t n t_n tn t f t_f tf 拆分为 N N N 个均匀分布区间,从每个区间中随机均匀抽取一个样本 t i t_i ti
t i ∼ U [ t n + i − 1 N ( t f − t n ) , t n + i N ( t f − t n ) ] i从1到N t_{i} \sim \mathcal{U}\left[t_{n}+\frac{i-1}{N}\left(t_{f}-t_{n}\right), t_{n}+\frac{i}{N}\left(t_{f}-t_{n}\right)\right] \text{i从1到N} tiU[tn+Ni1(tftn),tn+Ni(tftn)]i1N即分成两个步骤:

  1. 均匀的划分成 N N N 份;
  2. 每个区间内随机抽取一个样本,两样本间的最大间距也就是两倍的间隔,不会出现过大的情况。

在这里插入图片描述
在这种采样下,如何进行体渲染呢?
C ^ ( r ) = ∑ i = 1 N T i ( 1 − exp ⁡ ( − σ i δ i ) ) c i  where  T i = exp ⁡ ( − ∑ j = 1 i − 1 σ j δ j ) \hat{C}{(\mathbf{r})=\sum_{i=1}^{N} T_{i}\left(1-\exp \left(-\sigma_{i} \delta_{i}\right)\right) \mathbf{c}_{i} } \text{ where } T_{i}=\exp \left(-\sum_{j=1}^{i-1} \sigma_{j} \delta_{j}\right) C^(r)=i=1NTi(1exp(σiδi))ci where Ti=exp(j=1i1σjδj)其中, δ i = t i + 1 − t i \delta_{i}=t_{i+1}-t_{i} δi=ti+1ti 表示相邻采样点之间的距离。

4. 神经网络与位置编码

4.1 神经网络

  • 用途:从第二节中已经了解到,神经网络用来记录辐射场信息
  • 输入坐标位置 x \boldsymbol{x} x位置编码 γ ( x ) \gamma(\boldsymbol{x}) γ(x) 以及视角向量 d \boldsymbol{d} d 的位置编码 γ ( d ) \gamma(\boldsymbol{d}) γ(d)
  • 输出:在坐标位置 x \boldsymbol{x} x 的体密度 σ \sigma σ 以及视线 d \boldsymbol{d} d 方向观察时 x \boldsymbol{x} x 处的 RGB 值 c

在这里插入图片描述

  • 从图中可以看到,本身 3 3 3 维的 x \boldsymbol{x} x 经过位置编码后变成了 60 60 60 维,而本身 3 3 3 维的 d \boldsymbol{d} d 经过位置编码后变成了 24 24 24
  • 每一层的激活函数都使用 ReLU
  • 经过 8 8 8 层神经网络以后,会输出一个 σ \sigma σ 值, σ \sigma σ 只和位置有关,与视角方向无关(前面均没有传入 d \boldsymbol{d} d);同时这一层传入了 d \boldsymbol{d} d 的位置编码,用于得到该方向观察到的 RGB 值
  • 将两个信息拼接起来送给神经网络的下一层,最后使用 sigmoid 输出一个 RGB 值,范围(0~1)

4.2 视线角度

为什么需要视角向量 d \boldsymbol{d} d

在这里插入图片描述
图二为 NeRF 论文内得到的结果,图三为不加视角向量得到的结果,可以看到图二中的反光比较明显,而图三中的镜面反射消失了,添加视角向量得到的结果更符合真实场景。

4.3 位置编码

为什么需要位置编码?

在这里插入图片描述将图二和图四进行比较,明显可以看到图四中的高频几何和纹理细节丢失了。

高频与低频

这里首先来理解一下高频低频的概念:

  • 图像信号:在图像中,也就是这个像素与旁边像素颜色的差异,在边缘处得到应该是高频信息,在颜色变化不大的位置得到的就是低频信息了;
  • 三维场景:与邻居点在颜色和体密度上的差异。

总的来说,高频就意味着差异。比如相邻的颜色属于不同俩物质,颜色差异比较大,如果这两个颜色学到一起去了,那肯定是不行的。


那么位置编码上的高频与低频,到底是怎样产生作用的?
在这里插入图片描述有两张图像,图一输入一个 A A A 点 和 一个 B B B 点坐标,希望输出颜色值 C A C_A CA C B C_B CB A A A B B B 是相邻的;图二也有两个点,希望输出值为 C A ‾ \overline{C_{A}} CA C B ‾ \overline{C_{B}} CB

A A A B B B 的坐标在相差比较小的时候,假设 A A A 输给神经网络得到 C A C_A CA B B B 输给神经网络产生的 C B C_B CB,因为这两个坐标是相邻的,理论上 C A C_A CA C B C_B CB 俩颜色差异也应该不大。

而事实上 A A A B B B 的差异很小,但希望在边界上学出来的俩差距要大。这就需要神经网络学会放大信息,但这会出现的一个情况是: C A C_A CA 的值是红色, C B C_B CB 的值突然一下变成一个差异很大的值,就会导致本来是一个很连续的图像,突然蹦出来一个阶跃信号,看起来非常不自然,就像多了一个噪声,这样的感受会非常难受。但是如果都差异小,这也不是所希望的。

比如像图中的情况那样,想让 C A C_A CA C B C_B CB 差距小,而 C A ‾ \overline{C_{A}} CA C B ‾ \overline{C_{B}} CB 差距大。这样神经网络就没法抉择,到底学大的还是学小。但是我们又知道,神经网络内学大的还是学小的是由神经网络内训练样本所占比例决定-------谁的比例多,就会倾向于谁。在真实样本中,处于边界上的点对关系比较少,所以神经网络内大量的样本是颜色差距比较小的,这就导致了神经网络偏向于学习更平滑的信息,这样细节就丢失了。这也是为什么说,神经网络更倾向于学习低频信息

所以怎样让神经网络既学习到高频又学习到低频信息呢?
⟶ \longrightarrow A A A B B B 的位置进行编码

NeRF 中如何进行位置编码

γ ( p ) = ( sin ⁡ ( 2 0 π p ) , cos ⁡ ( 2 0 π p ) , ⋯   , sin ⁡ ( 2 L − 1 π p ) , cos ⁡ ( 2 L − 1 π p ) ) {\gamma(p)=\left(\sin \left(2^{0} \pi p\right), \cos \left(2^{0} \pi p\right), \cdots, \sin \left(2^{L-1} \pi p\right), \cos \left(2^{L-1} \pi p\right)\right)} γ(p)=(sin(20πp),cos(20πp),,sin(2L1πp),cos(2L1πp))这样做的意义可见下图。 γ ( ⋅ ) \gamma(\cdot) γ() 越前面的维度,差异越小;越往后的维度差异越大。图中的空间位置改变了一点点,低频的位置编码特征变化并不大,而高频的位置编码特征连符号都变了。这样关注哪一维取决于场景是什么-----用低维的差异看,差距小是有道理的;用高维的差异看,差距大也是可以的。不同维度的差距可以让神经网络去选择,到底是关注大差距还是关注小差距,这样就有的选。神经网络也就具有了自适应的调节能力。

在这里插入图片描述
γ ( ⋅ ) \gamma(\cdot) γ() 独立应用于待编码向量的各个维度,对于位置向量 x \boldsymbol{x} x 编码时 L L L 10 10 10,对于视角向量 d \boldsymbol{d} d 编码时 L L L 4 4 4

经过位置编码, x \boldsymbol{x} x 的编码 γ ( x ) \gamma(\boldsymbol{x}) γ(x) 维度为 60 60 60 d \boldsymbol{d} d 的编码 γ ( d ) \gamma(\boldsymbol{d}) γ(d) 维度为 24 24 24
L L L 10 10 10 的时候,因为有 sin ⁡ \sin sin cos ⁡ \cos cos,位置向量有三维,所以 γ ( x ) \gamma(\boldsymbol{x}) γ(x) 的维度是 3 ∗ 2 ∗ 10 = 60 3*2*10=60 3210=60 γ ( d ) \gamma(\boldsymbol{d}) γ(d) 同理为 3 ∗ 2 ∗ 4 = 24 3*2*4=24 324=24

5. 损失函数与训练策略

5.1 网络训练

难点:每条射线需要在近点与远点之间采样大量的点进行评估,导致计算量大
先验:射线上大部分区域都是空的,或者是被遮挡,对最终的颜色没有贡献(被遮挡的点的 σ \sigma σ 更新毫无意义,就算更新也是给出一个错误的值)

在这里插入图片描述

根据于此,采用了一种 coarse to fine 的层级采样策略,同时优化 coarse 网络fine 网络 。在 coarse 的时候大致确定一下,在射线上,哪些点的位置、颜色、 σ \sigma σ 是很重要的(也就是颜色不是零和没有遮挡的),针对这些位置做下采样,将 coarse 网络fine 网络 一起做更新。具体步骤如下:

  1. coarse网络层次采样 N c N_c Nc 个位置,计算 w i ^ \hat{w_i} wi^ 权重;
    C ( r ) = ∑ i = 1 N T i ( 1 − exp ⁡ ( − σ i δ i ) ) c i ⟶ C ( r ) = ∑ i = 1 N w i c i w i = T i ( 1 − exp ⁡ ( − σ i δ i ) ) {C(\boldsymbol{r})=\sum_{i=1}^{N} T_{i}\left(1-\exp \left(-\sigma_{i} \delta_{i}\right)\right) c_{i} \longrightarrow C(r)=\sum_{i=1}^{N} w_{i} c_{i} \quad w_{i}=T_{i}\left(1-\exp \left(-\sigma_{i} \delta_{i}\right)\right)} C(r)=i=1NTi(1exp(σiδi))ciC(r)=i=1Nwiciwi=Ti(1exp(σiδi))其中 C ( r ) = ∑ i = 1 N w i c i C(r)=\sum_{i=1}^{N} w_{i} c_{i} C(r)=i=1Nwici 为色彩加权求和。

    • 左式中 T i ( 1 − exp ⁡ ( − σ i δ i ) ) T_{i}\left(1-\exp \left(-\sigma_{i} \delta_{i}\right)\right) Ti(1exp(σiδi)) 被简化为了 w i w_i wi
    • w i = 0 w_i=0 wi=0 的情况,要么是被遮挡了,不重要,要么是体密度为 0 0 0,也不重要

    但是如果以 w i w_i wi 去采样,它是一个绝对量,只会告诉我这个位置重不重要,没有相对关系,所以需要对射线上所有位置的权重 w i w_i wi 进行归一化,这就是一个概率密度函数
    w ^ i = w i / ∑ j = 1 N c w j {\widehat{w}_{i}=w_{i} / \sum_{j=1}^{N_{c}} w_{j}} w i=wi/j=1Ncwj在概率大的地方多采样,这些位置的值和颜色对于更新是比较重要的。

  2. 依据权重 w i ^ \hat{w_i} wi^ 采样出 N f N_f Nf 个位置。

  3. 单条光线总采样数为 N c + N f N_c+N_f Nc+Nf

在该更新的地方更新,不该更新的地方不更新,这样学习的效率就比较高。

5.2 损失函数

因为要同时优化 coarse 和 fine 两个网络,损失函数为实际颜色 C ( r ) C(r) C(r) 与 渲染结果 C ^ c ( r ) \hat{C}_c(r) C^c(r) C ^ f ( r ) \hat{C}_f(r) C^f(r) 的平方误差:
L = ∑ r ∈ R [ ∥ C ^ c ( r ) − C ( r ) ∥ 2 2 + ∥ C ^ f ( r ) − C ( r ) ∥ 2 2 ] {\mathcal{L}=\sum_{\mathbf{r} \in \mathcal{R}}\left[\left\|\hat{C}_{c}(\mathbf{r})-C(\mathbf{r})\right\|_{2}^{2}+\left\|\hat{C}_{f}(\mathbf{r})-C(\mathbf{r})\right\|_{2}^{2}\right]} L=rR[ C^c(r)C(r) 22+ C^f(r)C(r) 22]其中, r \mathbf{r} r 表示一条采样光线, R \mathcal{R} R 表示所有采样光线。也就是将粗网络与标答比较+细网络与标答比较,一起放入损失函数内。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/314685.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Pygame库来显示一个简单的窗口,并绘制一些基本的形状和文本

import pygame from pygame.locals import *# 初始化pygame库 pygame.init()# 创建窗口并设置大小和标题 screen_width 800 screen_height 600 screen pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption("My Pygame")# 定义颜色…

鸿蒙原生应用再添新丁!天眼查 入局鸿蒙

鸿蒙原生应用再添新丁!天眼查 入局鸿蒙 来自 HarmonyOS 微博1月12日消息,#天眼查启动鸿蒙原生应用开发#作为累计用户数超6亿的头部商业信息查询平台,天眼查可以为商家企业,职场人士以及普通消费者等用户便捷和安全地提供查询海量…

使用U盘作为系统的启动盘

1.我们使用到的工具ventoy-1.0.96.rar 下载资源 https://download.csdn.net/download/u011442726/88735129 2.怎么使用 ventoy软件的使用非常简单,直接解压后,把u盘插到电脑,然后点击exe这个文件即可。 然后点击之后,直接点击安…

Python基础知识:整理11 模块的导入、自定义模块和安装第三方包

1 模块的导入 1.1 使用import 导入time模块,使用sleep功能(函数) import time print("start") time.sleep(3) print("end")1.2 使用from 导入time的sleep功能 from time import sleep print("start") slee…

Error: start of central directory not found; zipfile corrupt.

【报错】使用 unzip 指令在 AutoDL 上解压 .zip 文件时遇到 Error: start of central directory not found; zipfile corrupt. 报错: 重新上传后还是解压失败排除了 .zip 文件上传中断的问题。 【原因】Windows 和 Linux 下的压缩文件的二进制格式有所不同&#x…

【UE Niagara学习笔记】04 - 火焰喷射时的黑烟效果

目录 效果 步骤 一、创建烟雾材质 二、添加新的发射器 三、设置新发射器 3.1 删除Color模块 3.2 减少生成的粒子数量 3.3 设置粒子初始颜色 3.4 设置烟雾的位置偏移 3.5 设置烟雾淡出 在上一篇博客(【UE Niagara学习笔记】03 - 火焰喷射效果&#xf…

【算法】动态中位数(对顶堆)

题目 依次读入一个整数序列,每当已经读入的整数个数为奇数时,输出已读入的整数构成的序列的中位数。 输入格式 第一行输入一个整数 P,代表后面数据集的个数,接下来若干行输入各个数据集。 每个数据集的第一行首先输入一个代表…

设计一个简易版的数据库路由

👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术🔥如果感觉博主的文章还不错的…

Linux的发展历程:从诞生到全球应用

一、前言 Linux作为一个开源操作系统,经历了令人瞩目的发展历程。从最初的创意到如今在全球范围内得到广泛应用,Linux不仅是技术的杰出代表,更是开源精神的典范。本文将追溯Linux的发展历程,深入了解它是如何从一个个人项目演变为…

Vue-根据角色获取菜单动态添加路由

文章目录 前提提要需求分析具体实现配置静态路由路由权限判断登录添加动态路由修复刷新路由丢失问题 结语 如果大家写过后台管理系统的项目,那么动态路由一定是绕不开的,如果想偷懒的话,就把所有路由一开始都配置好,然后只根据后端…

以报时机器人为例详细介绍tracker_store和event_broker

报时机器人源码参考[1][2],本文重点介绍当 tracker_store 类型为 SQL 时,events 表的表结构以及数据是如何生成的。以及当 event_broker 类型为 SQL 时,events 表的表结构以及数据是如何生成的。 一.报时机器人启动 [3] Rasa 对话系统启动方…

解决命令行无法启动scrapy爬虫

前言 最近在准备毕设项目,想使用scrapy架构来进行爬虫,找了一个之前写过的样例,没想到在用普通的启动命令时报错。报错如下 无法将“scrapy”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径…

最大公共子串

解题思路: 解题代码: UP主运用的方法很巧妙。厉害。

Chrome 浏览器插件从 Manifest V2 升级到 V3 版本所需要修改的点

一、Manifest V2 支持时间表 Chrome 浏览器官方已经给出确定的时间来弃用 V2 版本的插件了。 最早从 2024 年 6 月的 Chrome 127 开始,我们将开始停用 Chrome 的不稳定版本(开发者版、Canary 版和 Beta 版)中的 Manifest V2 扩展程序。受此变…

MySQL入门:DCL数据控制语言(管理用户,权限控制),MySQL函数(字符串,数值,日期,流程)

目录 1.DCL(数据控制语言)1.管理用户2.权限控制 2.函数1.字符串函数2.数值函数3.日期函数4.流程函数 1.DCL(数据控制语言) DCL英文全称是Data ControlLanguage(数据控制语言),用来管理数据库用户、控制数据库的访问权限…

vivado 使用项目摘要、配置项目设置、仿真设置

使用项目摘要 Vivado IDE包括一个交互式项目摘要,可根据设计动态更新命令被运行,并且随着设计在设计流程中的进展。项目摘要包括概览选项卡和用户可配置的仪表板,如下图所示。有关信息,请参阅《Vivado Design Suite用户指南&…

轻松上手Linux文件操作:五种方法教你创建文件

轻松上手Linux文件操作:五种方法教你创建文件 一、引言二、使用touch命令创建文件三、使用文本编辑器创建文件四、使用echo命令创建文件五、使用cat命令创建文件六、使用重定向符号创建文件七、总结 一、引言 本文介绍五种在Linux系统中创建文件的方法,…

PaaS服务的零代码开发平台——JNPF

目前市场上低代码平台鱼龙混杂,真正能满足企业复杂业务(ERP、MES等)的平台不多,这里推荐一款好用、靠谱、性价比较高的低代码平台:JNPF开发平台。 JNPF开发平台是一款PaaS服务为核心的零代码开发平台,集成了…

Go 如何处理死锁以提供哪些工具来检测或防死锁?

并发是 Go 的核心特性,它使程序能够同时处理多个任务。它是现代编程的一个强大组件,如果使用正确,可以产生高效、高性能的应用程序。然而,并发性也带来了顺序编程中不存在的某些类型错误的可能性,其中最臭名昭著的是死…

双指针问题——求只包含两个元素的最长连续子序列(子数组)

一,题目描述 你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。 你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必…
最新文章