Alpha合成

在電腦圖形學領域中，Alpha合成（alpha compositing），又稱Alpha混合（alpha blending），是一種將圖像與背景結合的過程，結合後可以產生部分透明或全透明的視覺效果。Alpha合成也叫阿爾法合成或透明合成。渲染圖像時，通常會將目標圖像中的多個子元素單獨渲染，最後再把多張子元素的圖片合成 (特效)為單獨的圖像。例如，電視直播時就會將大量電腦生成的圖像元素合成到現場鏡頭上。

要正確結合圖像元素，每個元素的必須有對應的遮片。遮片包含覆蓋範圍資訊——圖中幾何對象的形狀——可以藉此分辨圖像中的任意位置到底是被繪製的幾何對象本身，還是邏輯上的「空白」區域。

## 描述

為了保存遮片資訊，匠白光提出了Alpha通道的概念，後由Thomas Porter和湯姆·達夫完善。二維圖像里記錄著每個像素的顏色資訊，額外的資訊以 0 和 1 之間的值表示，記錄在Alpha通道里。0 表示該像素沒有覆蓋資訊，是透明的，即圖中的幾何體沒有覆蓋到本像素；而 1 則表示像素不透明，幾何體完全覆蓋了此像素。

圖像中使用的Alpha通道通常有兩種表示形式：平直Alpha（straight alpha）和預乘Alpha（premultiplied alpha）。

- 如果使用平直Alpha，圖像中的RGB分量僅表示像素的顏色，與是否透明無關。
- 如果使用預乘Alpha，圖像中的RGB分量也表示像素的顏色，但事先已經和不透明度做了乘法。某些使用場景下，這樣的做法可以在後續合成時節省一次乘法。不過預乘Alpha的最顯著優勢在於使用簡單、準確而非性能。

如果用平直的（非預乘）RGBA 元組表達像素顏色，那麼像素值 (0, 0.7, 0, 0.5) 表示像素有 70% 的最大綠色亮度，同時不透明度是 50%。同樣條件下的純綠色是 (0, 1, 0, 0.5)。而如果用預乘Alpha，此處的 RGB 值 (0, 0.7, 0) 需要都乘以 0.5，表達為 (0, 0.35, 0, 0.5)。雖然此處 G 通道的值是 0.35，但它表示的還是最大亮度的 70%（其中包含了 50% 的不透明度）。此時的純綠色則需要表達為 (0, 0.5, 0, 0.5)。因此，了解圖像（文件）到底使用的是平直Alpha還是預乘Alpha非常重要，只有這樣才能對圖像做正確的處理和合成。

有了Alpha通道，圖片的合成操作就可以用合成代數的形式表達。假設有圖像元素 A 和 B，最常見的合成操作就是把 A 作為前景、B 作為背景，我們稱這種操作（運算）為 over，記作 $A \operatorname{over} B$。除此之外，波特和達夫還定義了其它幾個運算符：in、out、atop、xor：

<image>

運算符 over 的效果與普通繪畫效果一致（見畫家算法），運算符 in 則等價於裁剪。

以運算符 over 為例，運算結果相當於對圖像中的所有像素做以下公式：

$$\alpha_o = \alpha_a + \alpha_b \left(1 - \alpha_a\right)$$

$$C_o = \frac{C_a \alpha_a + C_b \alpha_b \left(1 - \alpha_a\right)}{\alpha_o}$$

其中 $C_o$ 是運算結果，$C_a$ 是圖像 A 中的像素，$C_b$ 是圖像 B 中的像素，而 $\alpha_a$ 和 $\alpha_b$ 則分別是圖像 A、B 中對應像素的Alpha值。

如果假設顏色值都是預乘了Alpha值的（$c_i = \alpha_i C_i$），那麼我們就可以將等式進行改寫，結果圖像中的顏色即：

$$c_o = c_a + c_b \left(1 - \alpha_a\right)$$

結果中的Alpha值即：

$$\alpha_o = \frac{c_o}{C_o} = \alpha_a + \alpha_b \left(1 - \alpha_a\right)$$

## over 運算符的解析推導

通過研究正交覆蓋，Porter 和 Buff 給出了 alpha 合成的幾何解釋。在 1981 年 Bruce A. Wallace 的論文裡則給出了另一種基於的反射率/透過率的物理模型的另一種推導。

第三種推導方法通過使用兩條簡單的假設得到。為了簡單起見，我們將 over 運算符簡記成 $a \odot b$。

第一條假設是當背景是不透明（即 $\alpha_b = 1$）時，over 運算符表示前景顏色與背景顏色的凸組合：

$$C_o = \alpha_a C_a + (1 - \alpha_a) C_b$$

第二條假設是這種運算應該滿足結合律：

$$(a \odot b) \odot c = a \odot (b \odot c)$$

現在，可以假設 $a$ 和 $b$ 包含不透明度分量，而 $c$ 不包含。考慮中間變量

$o = a \odot b$.

由於結合律成立，有

$$o \odot c = a \odot (b \odot c)$$

由於 $c$ 是不透明的，因此 $b \odot c$ 也是不透明的。由第二條假設，在上面的式子中，上式地每個 $\odot$ 運算都可以用凸組合表達：

$$\begin{align} <pre> \alpha_o C_o + (1 - \alpha_o) C_c &= \alpha_a C_a + (1 - \alpha_a) (\alpha_b C_b + (1 - \alpha_b) C_c) \\ &= [\alpha_a C_a + (1 - \alpha_a) \alpha_b C_b] + (1 - \alpha_a) (1 - \alpha_b) C_c </pre> \end{align}$$

這個式子的兩邊都滿足 $X_0 + Y_0 C_c = X_1 + Y_1 C_c$ 的形式，令 $X_0 = X_1$ 且 $Y_0 = Y_1$，可以得到：

$$\begin{align} <pre> \alpha_o &= 1 - (1 - \alpha_a) (1 - \alpha_b),\\ C_o &= \frac{\alpha_a C_a + (1 - \alpha_a)\alpha_b C_b}{\alpha_o}, </pre> \end{align}$$

至此，我們推導出了 $o = a \odot b$ 的顏色和其 alpha 分量的解析式。

注意到 $(1 - \alpha_a)\alpha_b = \alpha_o - \alpha_a$，這樣，上式可以緊湊地表示成

$$<pre> C_o = \frac{\alpha_a}{\alpha_o} C_a + \left(1 - \frac{\alpha_a}{\alpha_o}\right) C_b </pre>$$

$\odot$ 運算符滿足非交換么半群的定義。這個群的單位元 $e$ 是所有滿足 $\alpha = 0$ 的二元組 $\langle C,\alpha\rangle$，這可以通過式子 $e \odot a = a \odot e = a$ 得到。

## Alpha混合

Alpha混合（alpha blending）是將半透明的前景色與背景色結合的過程，可以得到混合後的新顏色。前景色的透明度不限，從完全透明到完全不透明都可以。如果前景色完全透明，混合後的顏色就是背景色；如果前景色完全不透明，混合後的顏色就是前景色；如果在這兩種極端情況之間，混合後的顏色可以通過前景色和背景色的加權平均計算。

Alpha合成後的顏色可以這樣計算：

$$\begin{cases} \mathrm{out}_A = \mathrm{src}_A + \mathrm{dst}_A (1 - \mathrm{src}_A) \\ \mathrm{out}_{RGB} = \bigl( \mathrm{src}_{RGB} \mathrm{src}_A + \mathrm{dst}_{RGB} \mathrm{dst}_A \left( 1 - \mathrm{src}_A \right) \bigr) \div \mathrm{out}_A \\ \mathrm{out}_A = 0 \Rightarrow \mathrm{out}_{RGB} = 0 \end{cases}$$

如果背景色不透明，即 $dst_A = 1$，代入上述方程後可以得到：

$$\begin{cases} \mathrm{out}_A = 1 \\ \mathrm{out}_{RGB} = \mathrm{src}_{RGB} \mathrm{src}_A + \mathrm{dst}_{RGB} (1 - \mathrm{src}_A) \end{cases}$$

如果使用了預乘Alpha，最初的方程組可以簡化為：

$$\begin{cases} \mathrm{out}_A = \mathrm{src}_A + \mathrm{dst}_A (1 - \mathrm{src}_A) \\ \mathrm{out}_{RGB} = \mathrm{src}_{RGB} + \mathrm{dst}_{RGB} \left( 1 - \mathrm{src}_A \right) \end{cases}$$

## 伽瑪校正

<image>

<image>

電腦圖像一般不直接存儲光照亮度對應的 RGB 值，而是需要先對這些值做伽瑪校正。

伽瑪校正的大致過程如下：

- 設 $displayed_{RGB}$ 為螢幕上顯示的 RGB 亮度（標準化後的亮度值，在 0 和 1 之間）
- 設 $stored_{RGB}$ 為電腦記憶體中所存儲的 RGB 亮度（也是標準化後的亮度值）
- 設 $\gamma$ 為用於「解碼」$stored_{RGB}$ 圖像的伽瑪值 2.2（2.2 為 $\gamma$ 的典型取值）

則它們三者之間的關係為

$$displayed_{RGB} = {stored_{RGB}} ^ {\gamma}$$

因此，在處理電腦圖像的 RGB 值時（尤其是做 Alpha 混合時），可以在處理前先將伽瑪校正消除，完成處理後再重新做伽瑪校正，這樣做的效果比直接處理伽瑪校正後的 RGB 值要好。

例如有一張圖片 $overlay_{rgb}$，它對應的 Alpha 通道為 $overlay_{\alpha}$，現在要把它疊加到背景圖 $background_{rgb}$ 上，那麼最終的圖像 $out_{rgb}$ 可以這樣計算：

$$out_{rgb} = ({overlay_{rgb}}^{\gamma } \times overlay_{\alpha} + {background_{rgb}}^{\gamma } \times (1 <pre> - overlay_{\alpha})) ^{1/\gamma } </pre>$$

此處的 $out_{rgb}$ 是電腦記憶體中所存儲的數據；在電腦顯示器上會以 $out_{rgb} ^ {\gamma}$ 的數據顯示。