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)=tn?tf??T(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(?tn?t?σ(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(tn?t),有
∫ 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*} tn?t?T(t)dT?lnT(t) ?tn?t?T(tn?t)=T(t)?T(tn?)?=?tn?t?σ(s)ds=?tn?t?σ(s)ds=exp(?tn?t?σ(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))dt?c(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)=tn?tf??T(t)σ(r(t))c(r(t),d)dt如果光線在路徑 t n → t f t_n → t_f tn?tf? 上未發生任何碰撞(所有 σ ( 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)=tn?tf??T(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] ti?U[tn?+Ni?1?(tf??tn?),tn?+Ni?(tf??tn?)]假設采樣的 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??=ti?ti+1??T(ti?t)?σ(t)?c(r(t),d)dt=σ(ti?)?c(ti?)ti?ti+1??T(ti?t)dt=σ(ti?)?c(ti?)ti?ti+1??exp(?ti?t?σ(s)ds)dt=σ(ti?)?c(ti?)ti?ti+1??exp(?σ(ti?)(t?ti?))dt=σ(ti?)?c(ti?)?σ(ti?)exp(?σ(ti?)(t?ti?))? ?ti?ti+1??=c(ti?)?(1?exp(?σ(ti?)(ti+1??ti?)))?值得注意的是,由于 d = t i + 1 ? t i d = t_{i + 1} - t_i d=ti+1??ti? 的數值很小,因此這里`假設區間 [ 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=1N?ti?ti+1??T(t)?σ(t)?c(r(t),d)dt=i=1N?ti?ti+1??T(0ti?)?T(ti?t)?σ(t)?c(r(t),d)dt=i=1N?T(0ti?)ti?ti+1??T(ti?t)?σ(t)?c(r(t),d)dt=i=1N?T(0ti?)?c(ti?)?(1?exp(?σ(ti?)(ti+1??ti?)))?不妨設 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+1??ti? σ 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=1N?Ti??(1?exp(?σ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=1i?1??σj?δj?)注意這里的 j j j 只取值到 i ? 1 i - 1 i?1
我們可以對體渲染公式做進一步簡化,令 α i = 1 ? exp ? ( ? σ i δ i ) \alpha_i = 1 - \exp(-\sigma_i \delta_i) αi?=1?exp(?σ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=1i?1??σj?δj?)=j=1i?1?exp(?σj?δj?)=j=1i?1?(1?αj?)=(1?α1?)(1?α2?)???(1?αi?1?) 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?αi?1?)αi??ci?=i=1N?ci?αi?j=1i?1?(1?αj?) w i = α i ∏ j = 1 i ? 1 ( 1 ? α j ) w_i = \alpha_i \prod_{j=1}^{i-1} (1 - \alpha_j) wi?=αi?j=1i?1?(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=iN?ci?αi?j=1i?1?(1?αj?)可以看出兩者具有一樣的數學表達式。

3. 代碼解讀

raw2outputs 函數實現了體渲染的計算。
1)計算采樣點之間的間距 δ i = t i + 1 ? t i \delta_i = t_{i + 1} - t_{i} δi?=ti+1??ti?

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?=1?exp(?σ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]=αi?j=1i?1?(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=1N?wi??zi?假設一條光線穿過一個簡單的場景(如一個立方體):
采樣點分布如下:

  • 采樣點 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ˉw1?t1?+w2?t2?+w3?t3?w2?t2?,即有效深度集中在立方體內部的采樣點,符合直覺。

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=1N?wi?zˉ?
雙目相機中視差 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 × 相對深度 絕對深度=α×相對深度

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/83142.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/83142.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/83142.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

標題:2025海外短劇爆發年:APP+H5雙端系統開發,解鎖全球流量與變現新大陸

描述: 2025年出海新風口!深度解析海外短劇系統開發核心(APPH5雙端),揭秘高效開發策略與商業化路徑,助您搶占萬億美元市場! 全球娛樂消費模式正在劇變。2025年,海外短劇市場已從藍海…

React JSX語法介紹(JS XML)(一種JS語法擴展,允許在JS代碼中編寫類似HTML的標記語言)Babel編譯

在線調試網站:https://zh-hans.react.dev/learn 文章目錄 JSX:現代前端開發的聲明式語法概述JSX的本質與工作原理什么是JSXJSX轉換流程 JSX語法特性表達式嵌入(JSX允許在大括號內嵌入任何有效的JavaScript表達式)屬性傳遞&#xf…

Unity UI系統中RectTransform詳解

一、基礎代碼示例 public GameObject node; var rect node.GetComponent<RectTransform>();Debug.Log($"anchoredPosition----{rect.anchoredPosition}"); Debug.Log($"offsetMin.x--{rect.offsetMin}"); Debug.Log($"offsetMax.x--{rect.of…

【數據庫】并發控制

并發控制 在數據庫系統&#xff0c;經常需要多個用戶同時使用。同一時間并發的事務可達數百個&#xff0c;這就是并發引入的必要性。 常見的并發系統有三種&#xff1a; 串行事務執行&#xff08;X&#xff09;&#xff0c;每個時刻只有一個事務運行&#xff0c;不能充分利用…

我們來學mysql -- “數據備份還原”sh腳本

數據備份&還原 說明執行db_backup_cover.sh腳本 說明 環境準備&#xff1a;來源數據庫(服務器A)&#xff1b;目標數據庫(服務器B)dbInfo.sh腳本記錄基本信息 來源庫、目標庫的ip、port及執行路徑 # MySQL 客戶端和 mysqldump 的路徑 MYSQL_CLIENT"/work/oracle/mysql…

【NLP 78、手搓Transformer模型結構】

你以為走不出的淤泥&#xff0c;也遲早會云淡風輕 —— 25.5.31 引言 ——《Attention is all you need》 《Attention is all you need》這篇論文可以說是自然語言處理領域的一座里程碑&#xff0c;它提出的 Transformer 結構帶來了一場技術革命。 研究背景與目標 在 Transfo…

深入理解CSS常規流布局

引言 在網頁設計中&#xff0c;理解元素如何排列和相互作用至關重要。CSS提供了三種主要的布局方式&#xff1a;常規流、浮動和定位。本文將重點探討最基礎也是最常用的常規流布局&#xff08;Normal Flow&#xff09;&#xff0c;幫助開發者掌握頁面布局的核心機制。 什么是…

樹結構詳細介紹(javascript版)

樹結構的基本概念 樹是一種非線性數據結構&#xff0c;由節點和連接節點的邊組成。與線性數據結構&#xff08;如數組、鏈表&#xff09;不同&#xff0c;樹具有層次結構&#xff0c;非常適合表示有層次關系的數據。 樹的基本術語 節點 (Node)&#xff1a; 樹中的基本單元&a…

element-plus bug整理

1.el-table嵌入el-image標簽預覽時&#xff0c;顯示錯亂 解決&#xff1a;添加preview-teleported屬性 <el-table-column label"等級圖標" align"center" prop"icon" min-width"80"><template #default"scope"&g…

RabbitMQ和MQTT區別與應用

RabbitMQ與MQTT深度解析&#xff1a;協議、代理、差異與應用場景 I. 引言 消息隊列與物聯網通信的重要性 在現代分布式系統和物聯網&#xff08;IoT&#xff09;生態中&#xff0c;高效、可靠的通信機制是構建穩健、可擴展應用的核心。消息隊列&#xff08;Message Queues&am…

零基礎遠程連接課題組Linux服務器,安裝anaconda,配置python環境(換源),在服務器上運行python代碼【3/3 適合小白,步驟詳細!!!】

遠程連接服務器 請查閱之前的博客——零基礎遠程連接課題組Linux服務器&#xff0c;安裝anaconda&#xff0c;配置python環境&#xff08;換源&#xff09;&#xff0c;在服務器上運行python代碼【1/3 適合小白&#xff0c;步驟詳細&#xff01;&#xff01;&#xff01;】&am…

Redis最佳實踐——安全與穩定性保障之訪問控制詳解

Redis 在電商應用的安全與穩定性保障之訪問控制全面詳解 一、安全訪問控制體系架構 1. 多層級防護體系 #mermaid-svg-jpkDj2nKxCq9AXIW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-jpkDj2nKxCq9AXIW .error-ico…

vue2源碼解析——響應式原理

文章目錄 引言數據劫持收集依賴數組處理渲染watchervue3中的響應式 引言 vue的設計思想是數據雙向綁定、數據與UI自動同步&#xff0c;即數據驅動視圖。 為什么會這樣呢&#xff1f;這就不得不提vue的響應式原理了&#xff0c;在使用vue的過程中&#xff0c;我被vue的響應式設…

gcc相關內容

gcc 介紹&#xff1a;linux就是由gcc編譯出來的&#xff0c;而且好像之前Linux只支持gcc編譯。gcc全稱為gnu compiler collection&#xff0c;它是gnu項目的一個組成部分。gnu致力于創建一個完全自由的操作系統&#xff0c;我感覺意思就是完全開源的操作系統。gnu有很多組件和…

android 圖片背景毛玻璃效果實現

圖片背景毛玻璃效果實現 1 依賴 // Glide implementation("com.github.bumptech.glide:glide:4.16.0") kapt("com.github.bumptech.glide:compiler:4.16.0") implementation("jp.wasabeef:glide-transformations:4.3.0") 2 布局<com.googl…

【Java開發日記】你會不會5種牛犇的yml文件讀取方式?

前言 除了爛大街的Value和ConfigurationProperties外&#xff0c;還能夠通過哪些方式&#xff0c;來讀取yml配置文件的內容&#xff1f; 1、Environment 在Spring中有一個類Environment&#xff0c;它可以被認為是當前應用程序正在運行的環境&#xff0c;它繼承了PropertyReso…

Spring Boot事務失效場景及解決方案

事務失效場景1&#xff1a;方法非public修飾 原因 Spring事務基于動態代理&#xff08;AOP&#xff09;實現&#xff0c;非public方法無法被代理攔截&#xff0c;導致事務失效。 代碼示例 Service public class OrderService {Transactionalprivate void createOrder() { //…

電子電路:怎么理解時鐘脈沖上升沿這句話?

時鐘脈沖是數字電路中用于同步各組件操作的周期性信號&#xff0c;通常表現為高低電平交替的方波。理解其關鍵點如下&#xff1a; 時鐘脈沖的本質&#xff1a; 由晶振等元件生成&#xff0c;呈現0/1&#xff08;低/高電平&#xff09;的規律振蕩每個周期包含上升沿→高電平→下…

docker部署redis mysql nacos seata rabbitmq minio onlyoffice nginx實戰

docker部署redis mysql nacos seata rabbitmq minio onlyoffice nginx實戰 一、環境介紹 操作系統&#xff1a;ubuntu22.04 軟件環境&#xff1a;docker、docker-compose 二、docker安裝 版本規定到26.1.3版本過低會引起莫名其妙的問題。打開終端。更新軟件包列表&#x…

全面解析:npm 命令、package.json 結構與 Vite 詳解

全面解析&#xff1a;npm 命令、package.json 結構與 Vite 詳解 一、npm run dev 和 npm run build 命令解析 1. npm run dev 作用&#xff1a;啟動開發服務器&#xff0c;用于本地開發原理&#xff1a; 啟動 Vite 開發服務器提供實時熱更新&#xff08;HMR&#xff09;功能…