当前位置: 首页 > article >正文

NeRF PyTorch 源码解读 - 体渲染

文章目录

1. 体渲染公式推导

如下图所示,渲染图像上点 P P P 的颜色值 c c c 是累加射线 O P → \overrightarrow{OP} OP 在近平面和远平面范围内采样的一系列点的颜色值得到的。
在这里插入图片描述
具体的计算公式如下:
C ( r ) = ∫ t n t f T ( t ) σ ( r ( t ) ) c ( r ( t ) , d ) d t C(\mathbf{r}) = \int_{t_n}^{t_f} T(t) \sigma(\mathbf{r}(t)) c(\mathbf{r}(t), \mathbf{d}) dt C(r)=tntfT(t)σ(r(t))c(r(t),d)dt其中:

  • T ( t ) = exp ⁡ ( − ∫ t n t σ ( r ( s ) ) d s ) T(t) = \exp ( -\int_{t_n}^t \sigma(\mathbf{r}(s)) ds) T(t)=exp(tntσ(r(s))ds) T ( t ) T(t) T(t) 为累积透射率,表示光线从起点传播到位置 t t t 时未被阻挡的概率
  • σ ( x ) \sigma(\mathbf{x}) σ(x) 表示体密度,反映光线在空间位置 x \mathbf{x} x 处被微小粒子阻挡的概率密度
  • r ( t ) = o + t d \mathbf{r}(t) = \mathbf{o} + t \mathbf{d} r(t)=o+td o \mathbf{o} o 为相机位置, d \mathbf{d} d 为射线 O P → \overrightarrow{OP} OP 的方向向量,即用 r ( t ) \mathbf{r}(t) r(t) 表示射线 O P → \overrightarrow{OP} OP
  • t n t_n tn t f t_f tf 分别表示近平面和远平面
  • C ( r ) C(\mathbf{r}) C(r) 表示射线 O P → \overrightarrow{OP} OP 在渲染图像上点 P P P 的颜色值

现在来推导一下上述的体渲染公式,分为两部分: T ( t ) T(t) T(t) C ( r ) C(\mathbf{r}) C(r)

1.1. T ( t ) T(t) T(t) 的推导

假设事件 A A A 表示光线在区间 [ 0 , t + d t ] [0, t + dt] [0,t+dt] 没有被阻挡,事件 B B B 表示光线在区间 [ 0 , t ] [0, t] [0,t] 没有被阻挡,事件 C C C 表示光线在区间 ( t , t + d t ] (t, t + dt] (t,t+dt] 没有被阻挡,则有 P ( A ) = P ( B ) P ( C ) P(A) = P(B)P(C) P(A)=P(B)P(C),其中 P ( A ) = T ( t + d t ) P(A)=T(t + dt) P(A)=T(t+dt) P ( B ) = T ( t ) P(B) = T(t) P(B)=T(t) P ( C ) = 1 − σ ( t ) d t P(C) = 1 - \sigma(t)dt P(C)=1σ(t)dt
值得注意的是,由于 σ ( t ) \sigma(t) σ(t) 表示光线在空间位置 t t t 处被微小粒子阻挡的概率密度,由于 d t dt dt 非常小,因此可以将 σ ( t ) d t \sigma(t)dt σ(t)dt 近似为光线在空间位置 t + d t t + dt t+dt 处被微小粒子阻挡的概率,则光线在空间位置 t + d t t + dt t+dt 没有被阻挡的概率为 1 − σ ( t ) d t 1 - \sigma(t)dt 1σ(t)dt
即有:
T ( t + d t ) = T ( t ) ( 1 − σ ( t ) d t ) T(t + dt) = T(t)(1 - \sigma(t)dt) T(t+dt)=T(t)(1σ(t)dt)进一步转换可得:
T ( t + d t ) − T ( t ) d t = − T ( t ) σ ( t ) \dfrac{T(t + dt) - T(t)}{dt} = - T(t)\sigma(t) dtT(t+dt)T(t)=T(t)σ(t) d t → 0 dt→0 dt0 的时候,有 T ′ ( t ) = T ( t + d t ) − T ( t ) d t = d T d t T'(t) = \dfrac{T(t + dt) - T(t)}{dt}=\dfrac{dT}{dt} T(t)=dtT(t+dt)T(t)=dtdT,因此可得微分方程:
d T T ( t ) = − σ ( t ) d t \dfrac{dT}{T(t)} = - \sigma(t)dt T(t)dT=σ(t)dt现在我们要计算在区间 [ t n , t ] [t_n, t] [tn,t] 中光线未被阻挡的概率 T ( t n → t ) T(t_n → t) T(tnt),有
∫ t n t d T T ( t ) = − ∫ t n t σ ( s ) d s ln ⁡ T ( t ) ∣ t n t = − ∫ t n t σ ( s ) d s T ( t n → t ) = T ( t ) − T ( t n ) = exp ⁡ ( − ∫ t n t σ ( s ) d s ) \begin{align*} \int_{t_n}^{t} \frac{dT}{T(t)} &= -\int_{t_n}^{t} \sigma(s) ds \\ \ln T(t) \bigg|_{t_n}^{t} &= -\int_{t_n}^{t} \sigma(s) ds \\ T(t_n→t) = T(t) - T(t_n) &= \exp(-\int_{t_n}^{t} \sigma(s) ds) \end{align*} tntT(t)dTlnT(t) tntT(tnt)=T(t)T(tn)=tntσ(s)ds=tntσ(s)ds=exp(tntσ(s)ds) T ( t ) T(t) T(t) 随路径长度增加而指数衰减,表示光线越深入场景,越可能被遮挡(透射率降低)。如果路径上有不透明物体,后续区域的颜色贡献会被完全遮挡(即 T ( t ) → 0 T(t) → 0 T(t)0)。这与物理现象一致:光线被前景物体遮挡后,无法看到背景物体。

1.2. C ( r ) C(r) C(r) 的推导

在 NeRF 的体积渲染模型中,颜色贡献仅来自光子与介质粒子的碰撞(相互作用),即 σ ( r ( t ) ) ≠ 0 \sigma(\mathbf{r}(t)) ≠ 0 σ(r(t))=0。光线从近平面 t n t_n tn 到远平面 t f t_f tf 累积的总颜色为 C ( r ) C(\mathbf{r}) C(r)。在光线路径上,区间 [ t , t + d t ] [t, t + dt] [t,t+dt] 内的颜色贡献 d C dC dC 由以下三部分组成:

  • 光线达到 t t t 的概率: T ( t ) T(t) T(t)
  • [ t , t + d t ] [t, t + dt] [t,t+dt] 内光线被阻挡(即光子与介质粒子的碰撞)的概率: σ ( r ( t ) ) d t \sigma(\mathbf{r}(t))dt σ(r(t))dt
  • 相互作用的颜色贡献: c ( r ( t ) , d ) c(\mathbf{r}(t), \mathbf{d}) c(r(t),d)

则有:
d C = T ( t ) ⋅ σ ( r ( t ) ) d t ⋅ c ( r ( t ) , d ) dC = T(t) · \sigma(\mathbf{r}(t))dt·c(\mathbf{r}(t), \mathbf{d}) dC=T(t)σ(r(t))dtc(r(t),d) d C dC dC t n t_n tn t f t_f tf 进行积分可得:
C ( r ) = ∫ t n t f T ( t ) σ ( r ( t ) ) c ( r ( t ) , d ) d t C(\mathbf{r}) = \int_{t_n}^{t_f} T(t) \sigma(\mathbf{r}(t)) c(\mathbf{r}(t), \mathbf{d}) dt C(r)=tntfT(t)σ(r(t))c(r(t),d)dt如果光线在路径 t n → t f t_n → t_f tntf 上未发生任何碰撞(所有 σ ( r ( t ) ) = 0 \sigma(\mathbf{r}(t)) = 0 σ(r(t))=0),则 T ( t f ) = 1 T(t_f) = 1 T(tf)=1,且 C ( r ) = 0 C(\mathbf{r}) = 0 C(r)=0。但在实际应用中,NeRF 通常引入背景颜色(例如环境光或者天空)作为默认值,则 C ( r ) C(\mathbf{r}) C(r) 的表达式改为:
C ( r ) = ∫ t n t f T ( t ) ⋅ σ ( r ( t ) ) ⋅ c ( r ( t ) , d ) d t + T ( t f ) ⋅ c b a c k g r o u n d C(\mathbf{r}) = \int_{t_n}^{t_f} T(t) \cdot \sigma(\mathbf{r}(t)) \cdot c(\mathbf{r}(t), \mathbf{d}) dt + T(t_f) · \mathbf{c_{background}} C(r)=tntfT(t)σ(r(t))c(r(t),d)dt+T(tf)cbackground这种情况下,即使没有碰撞点,背景颜色仍会作为最终像素值的一部分。

2. 体渲染公式离散化

由于计算机只能处理离散值,因此需要将前面推导的体渲染公式进行离散化。
首先,我们将区间 [ t n , t f ] [t_n, t_f] [tn,tf] 划分成 N N N 个等距的小区间,从每一个小区间中随机取样一个点作为采样点,如下所示:
t i ∼ U [ t n + i − 1 N ( t f − t n ) , t n + i N ( t f − t n ) ] t_i \sim U\left[ t_n + \frac{i-1}{N}(t_f - t_n), \, t_n + \frac{i}{N}(t_f - t_n) \right] tiU[tn+Ni1(tftn),tn+Ni(tftn)]假设采样的 N N N 个点分别为 t 1 , t 2 , . . . , t N t_1,t_2,...,t_N t1,t2,...,tN,现在计算两个采样点 t i t_i ti t i + 1 t_{i + 1} ti+1 之间的颜色累积值 C i C_i Ci,则有
C i = ∫ t i t i + 1 T ( t i → t ) ⋅ σ ( t ) ⋅ c ( r ( t ) , d ) d t = σ ( t i ) ⋅ c ( t i ) ∫ t i t i + 1 T ( t i → t ) d t = σ ( t i ) ⋅ c ( t i ) ∫ t i t i + 1 exp ⁡ ( − ∫ t i t σ ( s ) d s ) d t = σ ( t i ) ⋅ c ( t i ) ∫ t i t i + 1 exp ⁡ ( − σ ( t i ) ( t − t i ) ) d t = σ ( t i ) ⋅ c ( t i ) exp ⁡ ( − σ ( t i ) ( t − t i ) ) − σ ( t i ) ∣ t i t i + 1 = c ( t i ) ⋅ ( 1 − exp ⁡ ( − σ ( t i ) ( t i + 1 − t i ) ) ) \begin{align*} C_{i} &= \int_{t_i}^{t_{i + 1}} T(t_i→t)\cdot\sigma(t)\cdot c(\mathbf{r}(t), \mathbf{d}) dt \\ &=\sigma(t_i) \cdot c(t_i)\int_{t_i}^{t_{i + 1}} T(t_i→t) dt \\ &=\sigma(t_i) \cdot c(t_i)\int_{t_i}^{t_{i + 1}} \exp(-\int_{t_i}^{t}\sigma(s)ds) dt \\ &=\sigma(t_i)\cdot c(t_i)\int_{t_i}^{t_{i + 1}}\exp(-\sigma(t_i)(t - t_i)) dt \\ &=\sigma(t_i) \cdot c(t_i) \left. \frac{\exp{(-\sigma(t_i) (t - t_i))}}{-\sigma(t_i)} \right|_{t_i}^{t_{i + 1}} \\ &=c(t_i) \cdot (1 - \exp(-\sigma(t_i)(t_{i + 1} - t_i))) \end{align*} Ci=titi+1T(tit)σ(t)c(r(t),d)dt=σ(ti)c(ti)titi+1T(tit)dt=σ(ti)c(ti)titi+1exp(titσ(s)ds)dt=σ(ti)c(ti)titi+1exp(σ(ti)(tti))dt=σ(ti)c(ti)σ(ti)exp(σ(ti)(tti)) titi+1=c(ti)(1exp(σ(ti)(ti+1ti)))值得注意的是,由于 d = t i + 1 − t i d = t_{i + 1} - t_i d=ti+1ti 的数值很小,因此这里`假设区间 [ t i , t i + 1 ] [t_i, t_{i + 1}] [ti,ti+1] 的体密度为常量 σ ( t i ) \sigma(t_i) σ(ti),颜色值也为常量 c ( t i ) c(t_i) c(ti)
C ( r ) = ∑ i = 1 N ∫ t i t i + 1 T ( t ) ⋅ σ ( t ) ⋅ c ( r ( t ) , d ) d t = ∑ i = 1 N ∫ t i t i + 1 T ( 0 → t i ) ⋅ T ( t i → t ) ⋅ σ ( t ) ⋅ c ( r ( t ) , d ) d t = ∑ i = 1 N T ( 0 → t i ) ∫ t i t i + 1 T ( t i → t ) ⋅ σ ( t ) ⋅ c ( r ( t ) , d ) d t = ∑ i = 1 N T ( 0 → t i ) ⋅ c ( t i ) ⋅ ( 1 − exp ⁡ ( − σ ( t i ) ( t i + 1 − t i ) ) ) \begin{align*} C(\mathbf{r}) &= \sum_{i=1}^{N} \int_{t_i}^{t_{i + 1}} T(t) \cdot \sigma(t) \cdot c(\mathbf{r}(t), \mathbf{d}) dt \\ &= \sum_{i=1}^{N} \int_{t_i}^{t_{i + 1}} T(0 → t_i) \cdot T(t_i → t) \cdot \sigma(t) \cdot c(\mathbf{r}(t), \mathbf{d}) dt \\ &= \sum_{i=1}^{N} T(0 → t_i) \int_{t_i}^{t_{i + 1}} T(t_i → t) \cdot \sigma(t) \cdot c(\mathbf{r}(t), \mathbf{d}) dt \\ &= \sum_{i=1}^{N} T(0 → t_i) \cdot c(t_i) \cdot (1 - \exp(-\sigma(t_i)(t_{i + 1} - t_i))) \end{align*} C(r)=i=1Ntiti+1T(t)σ(t)c(r(t),d)dt=i=1Ntiti+1T(0ti)T(tit)σ(t)c(r(t),d)dt=i=1NT(0ti)titi+1T(tit)σ(t)c(r(t),d)dt=i=1NT(0ti)c(ti)(1exp(σ(ti)(ti+1ti)))不妨设 T i = T ( 0 → t i ) T_i = T(0→t_i) Ti=T(0ti) c i = c ( t i ) c_i = c(t_i) ci=c(ti) δ i = t i + 1 − t i \delta_i = t_{i + 1}-t_i δi=ti+1ti σ i = σ ( t i ) \sigma_i = \sigma(t_i) σi=σ(ti),则上述公式可以简化为:
C ( r ) = ∑ i = 1 N T i ⋅ ( 1 − exp ⁡ ( − σ i δ i ) ) ⋅ c i C(\mathbf{r}) = \sum_{i=1}^{N} T_i \cdot (1 - \exp(-\sigma_i \delta_i)) \cdot c_i C(r)=i=1NTi(1exp(σiδi))ci T ( t ) T(t) T(t) 也进行离散化,根据上述公式,我们需要知道 T ( t i ) T(t_i) T(ti) 的离散化公式,如下:
T i = T ( t i ) = T ( 0 → t i ) = exp ⁡ ( − ∫ 0 t i σ ( t ) d t ) = exp ⁡ ( ∑ j = 1 i − 1 − σ j δ j ) T_i = T(t_i) = T(0 \to t_i) = \exp \left( -\int_0^{t_i} \sigma(t) \, dt \right) = \exp \left( \sum_{j=1}^{i - 1} -\sigma_j \delta_j \right) Ti=T(ti)=T(0ti)=exp(0tiσ(t)dt)=exp(j=1i1σjδj)注意这里的 j j j 只取值到 i − 1 i - 1 i1
我们可以对体渲染公式做进一步简化,令 α i = 1 − exp ⁡ ( − σ i δ i ) \alpha_i = 1 - \exp(-\sigma_i \delta_i) αi=1exp(σiδi),则有:
T i = exp ⁡ ( ∑ j = 1 i − 1 − σ j δ j ) = ∏ j = 1 i − 1 exp ⁡ ( − σ j δ j ) = ∏ j = 1 i − 1 ( 1 − α j ) = ( 1 − α 1 ) ( 1 − α 2 ) ⋅ ⋅ ⋅ ( 1 − α i − 1 ) T_i = \exp \left( \sum_{j=1}^{i - 1} -\sigma_j \delta_j \right) = \prod\limits_{j = 1}^{i - 1}\exp(-\sigma_j \delta_j) = \prod\limits_{j = 1}^{i - 1}(1 - \alpha_j) = (1-\alpha_1)(1-\alpha_2)···(1-\alpha_{i - 1}) Ti=exp(j=1i1σjδj)=j=1i1exp(σjδj)=j=1i1(1αj)=(1α1)(1α2)⋅⋅⋅(1αi1) C ( r ) = ∑ i = 1 N ( 1 − α 1 ) ( 1 − α 2 ) ⋅ ⋅ ⋅ ( 1 − α i − 1 ) α i ⋅ c i = ∑ i = 1 N c i α i ∏ j = 1 i − 1 ( 1 − α j ) C(\mathbf{r}) = \sum_{i=1}^{N} (1-\alpha_1)(1-\alpha_2)···(1-\alpha_{i - 1})\alpha_i \cdot c_i = \sum_{i=1}^{N} c_i \alpha_i \prod_{j=1}^{i-1} (1 - \alpha_j) C(r)=i=1N(1α1)(1α2)⋅⋅⋅(1αi1)αici=i=1Nciαij=1i1(1αj) w i = α i ∏ j = 1 i − 1 ( 1 − α j ) w_i = \alpha_i \prod_{j=1}^{i-1} (1 - \alpha_j) wi=αij=1i1(1αj),则 w i w_i wi 可以看做是采样点 i i i 对最终颜色的贡献权重。
3DGS 中论文给出的渲染公式如下:
C = ∑ i ∈ N c i α i ∏ j = 1 i − 1 ( 1 − α j ) C = \sum_{i \in N} c_i \alpha_i \prod_{j=1}^{i-1} (1 - \alpha_j) C=iNciαij=1i1(1αj)可以看出两者具有一样的数学表达式。

3. 代码解读

raw2outputs 函数实现了体渲染的计算。
1)计算采样点之间的间距 δ i = t i + 1 − t i \delta_i = t_{i + 1} - t_{i} δi=ti+1ti

dists = z_vals[..., 1:] - z_vals[..., :-1]
dists = torch.cat([dists, torch.Tensor([1e10]).expand(dists[..., :1].shape)], -1)  # [N_rays, N_samples]
dists = dists * torch.norm(rays_d[..., None, :], dim=-1)

2)将模型预测的原始颜色值(raw[…, :3])通过 s i g m o i d sigmoid sigmoid 映射到 [ 0 , 1 ] [0,1] [0,1] 范围

rgb = torch.sigmoid(raw[..., :3])  # [N_rays, N_samples, 3]

3)在训练时向体积密度 σ \sigma σ 加噪声,防止过拟合

noise = 0.
if raw_noise_std > 0.:noise = torch.randn(raw[..., 3].shape) * raw_noise_std

4)计算 α i = 1 − exp ⁡ ( − σ i δ i ) \alpha_i = 1 - \exp(-\sigma_i\delta_i) αi=1exp(σiδi)

raw2alpha = lambda raw, dists, act_fn=F.relu: 1. - torch.exp(-act_fn(raw) * dists)
alpha = raw2alpha(raw[..., 3] + noise, dists)  # [N_rays, N_samples]

5)计算每一条射线上的所有采样点的权重 w e i g h t s [ i ] weights[i] weights[i],并且 w e i g h t s [ i ] = α i ∏ j = 1 i − 1 ( 1 − α j ) weights[i] = \alpha_i \prod_{j=1}^{i-1} (1 - \alpha_j) weights[i]=αij=1i1(1αj)

weights = alpha * torch.cumprod(torch.cat([torch.ones((alpha.shape[0], 1)), 1. - alpha + 1e-10], -1), -1)[:, :-1]
rgb_map = torch.sum(weights[..., None] * rgb, -2)  # [N_rays, 3]

现在简单模拟一下这个过程的计算:

alpha = [[0.1, 0.2], [0.3, 0.4]
]1 - alpha = [[0.9, 0.8], [0.7, 0.6]
]torch.cat([torch.ones((alpha.shape[0], 1)), 1. - alpha + 1e-10], -1) 的输出为: 
[[1, 0.9, 0.8], [1, 0.7, 0.6]
]
torch.cumprod(torch.cat([torch.ones((alpha.shape[0], 1)), 1. - alpha + 1e-10], -1), -1) 的输出为:
[[1, 1*0.9, 1*0.9*0.8],[1, 1*0.7, 1*0.7*0.6]
]torch.cumprod(torch.cat([torch.ones((alpha.shape[0], 1)), 1. - alpha + 1e-10], -1), -1)[:, :-1] 的输出为:
[[1, 0.9],[1, 0.7]
]alpha * torch.cumprod(torch.cat([torch.ones((alpha.shape[0], 1)), 1. - alpha + 1e-10], -1), -1)[:, :-1] 的输出为:
[[0.1*1, 0.2*0.9][0.1, 0.18],[0.3*1, 0.4*0.7][0.3, 0.28]]

6)计算深度图

depth_map = torch.sum(weights * z_vals, -1)
disp_map = 1. / torch.max(1e-10 * torch.ones_like(depth_map), depth_map / torch.sum(weights, -1))

在 NeRF 中通过加权平均所有采样点的深度,得到每条射线的有效深度。有效深度可以看作是光线穿过场景时,最可能与物体表面相交的深度。有效深度的计算公式如下:
z ˉ = ∑ i = 1 N w i ⋅ z i \bar{z} = \sum_{i=1}^{N} w_i \cdot z_i zˉ=i=1Nwizi假设一条光线穿过一个简单的场景(如一个立方体):
采样点分布如下:

  • 采样点 1:位于立方体的前方, σ 1 \sigma_1 σ1 很小, w 1 w_1 w1 接近于 0
  • 采样点 2:位于立方体的内部, σ 2 \sigma_2 σ2 很大, w 2 w_2 w2 显著增大
  • 采样点 3:位于立方体的后方, σ 3 \sigma_3 σ3 很小, w 3 w_3 w3 接近于 0

则该光线的有效深度为 z ˉ ≈ w 1 t 1 + w 2 t 2 + w 3 t 3 ≈ w 2 t 2 \bar{z} ≈ w_1t_1 + w_2t_2 + w_3t_3 ≈ w_2t_2 zˉw1t1+w2t2+w3t3w2t2,即有效深度集中在立方体内部的采样点,符合直觉。

7)计算视差图
在 NeRF 中通过深度倒数计算视差,并添加极小值 1e-10 防止除零,计算公式如下:
disp = 1 max ⁡ ( ϵ , z ˉ n o r m ) \text{disp} = \frac{1}{\max(\epsilon, \bar{z}_{norm})} disp=max(ϵ,zˉnorm)1其中, z ˉ n o r m = z ˉ ∑ i = 1 N w i \bar{z}_{norm} = \dfrac{\bar{z}}{\sum_{i=1}^{N} w_i} zˉnorm=i=1Nwizˉ
双目相机中视差 d d d 和 深度 D D D 的关系如下:
d = B f Z d = \dfrac{Bf}{Z} d=ZBf其中:

  • B B B:双目相机的基线长度(两相机中心的水平距离)
  • f f f:相机焦距
  • Z Z Z:场景点的深度
  • d d d:视差(同一场景点在左右图像中的像素偏差)

d = B f Z d = \dfrac{Bf}{Z} d=ZBf 计算的是绝对深度(实际物理距离), B B B f f f 两个参数都需要人为标定。
而 NeRF 中计算视差的公式为 d = 1 Z d=\dfrac{1}{Z} d=Z1,这计算的是相对深度。相对深度描述的是场景中物体之间的相对远近关系,但不提供物体到相机或传感器的实际物理距离。
相对深度图缺乏真实尺度,但可以通过已知的基准点(如标定板)计算比例因子 α \alpha α,将相对深度映射到绝对深度,数学公式如下:
绝对深度 = α × 相对深度 绝对深度 = \alpha × 相对深度 绝对深度=α×相对深度

相关文章:

NeRF PyTorch 源码解读 - 体渲染

文章目录 1. 体渲染公式推导1.1. T ( t ) T(t) T(t) 的推导1.2. C ( r ) C(r) C(r) 的推导 2. 体渲染公式离散化3. 代码解读 1. 体渲染公式推导 如下图所示,渲染图像上点 P P P 的颜色值 c c c 是累加射线 O P → \overrightarrow{OP} OP 在近平面和远平面范围…...

SpringBoot 数据库批量导入导出 Xlsx文件的导入与导出 全量导出 数据库导出表格 数据处理 外部数据

介绍 poi-ooxml 是 Apache POI 项目中的一个库,专门用于处理 Microsoft Office 2007 及以后版本的文件,特别是 Excel 文件(.xlsx 格式)和 Word 文件(.docx 格式)。 在管理系统中需要对数据库的数据进行导…...

解决:install via Git URL失败的问题

为解决install via Git URL失败的问题,修改安全等级security_level的config.ini文件,路径如下: 还要重启: 1.reset 2.F5刷新页面 3.关机服务器,再开机(你也可以省略,试试) 4.Wind…...

OpenCV CUDA模块特征检测------创建Harris角点检测器的GPU实现接口cv::cuda::createHarrisCorner

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 该函数创建一个 基于 Harris 算法的角点响应计算对象,专门用于在 GPU 上进行高效计算。 它返回的是一个 cv::Ptrcv::cuda::Cornernes…...

【氮化镓】钝化层对p-GaN HEMT阈值电压的影响

2021年5月13日,中国台湾阳明交通大学的Shun-Wei Tang等人在《Microelectronics Reliability》期刊发表了题为《Investigation of the passivation-induced VTH shift in p-GaN HEMTs with Au-free gate-first process》的文章。该研究基于二次离子质谱(SIMS)、光致发光(PL)…...

C++:优先级队列

目录 1. 概念 2. 特征 3. 优先级队列的使用 1. 概念 优先级队列虽然名字有队列二字,但根据队列特性来说优先级队列不满足先进先出这个特征,优先级队列的底层是用堆来实现的。 优先级队列是一种容器适配器,就是将特定容器类封装作为其底层…...

睡眠分期 html

截图 代码 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>睡眠图表</title><script src…...

Java求职者面试:Spring、Spring Boot、Spring MVC与MyBatis技术深度解析

Java求职者面试&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术深度解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释什么是Spring框架&#xff1f;它的核心功能是什么&#xff1f; JY&#xff1a;Spring是一个开源的Java/Java EE企业级应用开…...

Github 2025-05-29 Go开源项目日报Top9

根据Github Trendings的统计,今日(2025-05-29统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Go项目9Assembly项目1Ollama: 本地大型语言模型设置与运行 创建周期:248 天开发语言:Go协议类型:MIT LicenseStar数量:42421 个Fork数量:27…...

前端项目种对某个文件夹进行大小写更改,git识别不到差异导致无变化

问题背景 开发过程中可能遇到一个文件名要更改大小写&#xff0c;但是更改后之后本地会有变化&#xff0c;但是git识别不到差异化&#xff0c;正常去更改一个文件名称git差异化会出现删除了原有文件,新增了一个新文件,但是更改大小写则不会 如何解决 在终端中输入git config…...

AWS VPC 网络详解:理解云上专属内网的关键要素

全面解读 AWS VPC、子网、安全组、路由与 NAT 网关的实际应用 在使用 AWS 云服务的过程中&#xff0c;许多用户最先接触的是 EC2&#xff08;云服务器&#xff09;。但你是否曾遇到过这样的情况&#xff1a;实例启动正常&#xff0c;却无法访问公网&#xff1f;或者数据库无法…...

Ubuntu24.04.2 + kubectl1.33.1 + containerdv1.7.27 + calicov3.30.0

Ubuntu24.04.2 kubectl1.33.1 containerdv1.7.27 calicov3.30.0 安装Ubuntu24.04.2 kubectl1.33.1 containerdv1.7.27 calicov3.30.0 1.安装Ubuntu24.04.2&#xff0c;设置阿里云镜像地址 $ sudo vim /etc/apt/sources.list.d/ubuntu.sources URIs: https://mirrors.aliy…...

循环神经网络(RNN)全面教程:从原理到实践

循环神经网络(RNN)全面教程&#xff1a;从原理到实践 引言 循环神经网络(Recurrent Neural Network, RNN)是处理序列数据的经典神经网络架构&#xff0c;在自然语言处理、语音识别、时间序列预测等领域有着广泛应用。本文将系统介绍RNN的核心概念、常见变体、实现方法以及实际…...

uniapp 键盘顶起页面问题

关于uniapp中键盘顶起页面的问题。这是一个在移动应用开发中常见的问题&#xff0c;特别是当输入框位于页面底部时&#xff0c;键盘弹出会顶起整个页面&#xff0c;导致页面布局错乱。 pages.json 文件内&#xff0c;在需要处理软键盘的页面添加 softinputMode 配置&#xff1…...

利用TOA与最小二乘法直接求解

为了利用到达时间&#xff08;TOA&#xff09;和最小二乘法直接求解&#xff0c;我们首先需要理解TOA定位的基本原理和最小二乘法的应用。 步骤1: 理解TOA定位原理 到达时间&#xff08;TOA&#xff09;定位是通过测量信号从发射源到达接收器的时间来确定位置的一种方法。假设…...

SpringBoot系列之RabbitMQ 实现订单超时未支付自动关闭功能

系列博客专栏&#xff1a; JVM系列博客专栏SpringBoot系列博客 RabbitMQ 实现订单超时自动关闭功能&#xff1a;从原理到实践的全流程解析 一、业务场景与技术选型 在电商系统中&#xff0c;订单超时未支付自动关闭功能是保障库存准确性、提升用户体验的核心机制。传统定时任…...

【C++高级主题】命令空间(五):类、命名空间和作用域

目录 一、实参相关的查找&#xff08;ADL&#xff09;&#xff1a;函数调用的 “智能搜索” 1.1 ADL 的核心规则 1.2 ADL 的触发条件 1.3 ADL 的典型应用场景 1.4 ADL 的潜在风险与规避 二、隐式友元声明&#xff1a;类与命名空间的 “私密通道” 2.1 友元声明的基本规则…...

ArcGIS Pro 3.4 二次开发 - 地图创作 1

环境:ArcGIS Pro SDK 3.4 + .NET 8 文章目录 ArcGIS Pro 3.4 二次开发 - 地图创作 11 样式管理1.1 如何通过名称获取项目中的样式1.2 如何创建新样式1.3 如何向项目添加样式1.4 如何从项目中移除样式1.5 如何向样式添加样式项1.6 如何从样式中移除样式项1.7 如何判断样式是否可…...

2.1HarmonyOS NEXT开发工具链进阶:DevEco Studio深度实践

HarmonyOS NEXT开发工具链进阶&#xff1a;DevEco Studio深度实践 在HarmonyOS NEXT全栈自研的技术体系下&#xff0c;DevEco Studio作为一站式开发平台&#xff0c;通过深度整合分布式开发能力&#xff0c;为开发者提供了从代码编写到多端部署的全流程支持。本章节将围绕多设…...

MyBatis常用注解全解析:从基础CRUD到高级映射

MyBatis常用注解全解析&#xff1a;从基础CRUD到高级映射 本文全面解析MyBatis核心注解体系&#xff0c;涵盖基础操作、动态SQL、关系映射等高级特性&#xff0c;助你彻底掌握MyBatis注解开发精髓 一、MyBatis注解概述 1.1 注解 vs XML配置 MyBatis同时支持XML配置和注解两种…...

国标GB28181设备管理软件EasyGBS视频平台筑牢文物保护安全防线创新方案

一、方案背景​ 文物作为人类文明的珍贵载体&#xff0c;具有不可再生性。当前&#xff0c;盗窃破坏、游客不文明行为及自然侵蚀威胁文物安全&#xff0c;传统保护手段存在响应滞后、覆盖不全等局限。随着5G与信息技术发展&#xff0c;基于GB28181协议的EasyGBS视频云平台&…...

十二、【核心功能篇】测试用例列表与搜索:高效展示和查找海量用例

【核心功能篇】测试用例列表与搜索:高效展示和查找海量用例 前言准备工作第一步:更新 API 服务以支持分页和更完善的搜索第二步:创建测试用例列表页面组件 (`src/views/testcase/TestCaseListView.vue`)第三步:测试列表、搜索、筛选和分页总结前言 当测试用例数量逐渐增多…...

Baklib内容中台AI重构智能服务

AI驱动智能服务进化 在智能服务领域&#xff0c;Baklib内容中台通过自然语言处理技术与深度学习框架的深度融合&#xff0c;构建出具备意图理解能力的知识中枢。系统不仅能够快速解析用户输入的显性需求&#xff0c;更通过上下文关联分析算法识别会话场景中的隐性诉求&#xf…...

数据库包括哪些?关系型数据库是什么意思?

目录 一、数据库包括哪些 &#xff08;一&#xff09;关系型数据库 &#xff08;二&#xff09;非关系型数据库 &#xff08;三&#xff09;分布式数据库 &#xff08;四&#xff09;内存数据库 二、关系型数据库是什么 &#xff08;一&#xff09;关系模型的基本概念 …...

Python爬虫监控程序设计思路

最近因为爬虫程序太多&#xff0c;想要为Python爬虫设计一个监控程序&#xff0c;主要功能包括一下几种&#xff1a; 1、监控爬虫的运行状态&#xff08;是否在运行、运行时间等&#xff09; 2、监控爬虫的性能&#xff08;如请求频率、响应时间、错误率等&#xff09; 3、资…...

Edge浏览器怎样开启兼容模式

允许站点在 IE 模式下重新加载&#xff1a; 打开 Edge 浏览器&#xff0c;点击右上角的三个点图标&#xff0c;选择 “设置”&#xff08;或者按下 “Alt F” 组合键后再点击 “设置”&#xff09;。在设置页面中&#xff0c;切换到左侧的 “默认浏览器” 选项卡。在 “Intern…...

【HarmonyOS 5】Laya游戏如何鸿蒙构建发布详解

【HarmonyOS 5】Laya游戏如何鸿蒙构建发布详解 一、前言 LayaAir引擎是国内最强大的全平台引擎之一&#xff0c;当年H5小游戏火的时候&#xff0c;腾讯入股了腊鸭。我还在游戏公司的时候&#xff0c;17年曾经开发使用腊鸭的H5小游戏&#xff0c;很怀念当年和腊鸭同事一起解决…...

C++ TCP传输心跳信息

在C++ TCP程序中实现心跳机制是保持连接活跃、检测连接状态的重要手段。以下是几种常见的心跳实现方式: 1. 应用层心跳(推荐) 基本心跳实现 #include <iostream> #include <thread> #include <chrono>...

Elasticsearch | 如何将修改已有的索引字段类型并迁移数据

CodingTechWork 引言 在 Elasticsearch 中&#xff0c;一旦索引的字段类型被定义&#xff0c;就无法直接修改已有字段的类型。例如&#xff0c;如果你已经将 timestamp 字段的类型设置为 TEXT&#xff0c;并希望将其更改为 DATE 类型&#xff0c;这将需要一些额外的步骤。在这…...

c++之STL容器的学习(上)

一、泛型编程&#xff08;函数模板和类模板&#xff09; 这部分围绕泛型编程技术展开&#xff0c;C中的泛型编程主要是通过函数模板和类模板实现的&#xff0c;主要会介绍标准模板库STL的知识点。1.关于模板的理解 模板就是建立一种通用的模式&#xff0c;从而提高复用性。在生…...