兩幅32位帶Alpha通道的圖像,同時存在混合模式和不透明度的設定,最後混合後的顔色計算公式,在網上很難找到正确的,我這裡通過一步一步的測試,整理了不同情況下的混合公式。
大家可以在網上搜尋相關的主題啊,你可以搜尋到一堆,不過似乎沒有那一個講的很全面,我這裡抽空整理和測試一下資料,分享給大家。
我們假定有2個32位的圖層,圖層BG和圖層FG,其中圖層BG是背景層(位于下部),圖層FG是前景層(位于上部),我們摸索其混合後的顔色的計算公式。
我們取一個點的像素做分析:
其中BG層某點的顔色為: B1 = 168 G1 = 99 R1= 114 A1 = 70
其中FG層某點的顔色為: B2= 80 G2 = 71 R2= 162 A2 = 135
場景一:兩個圖層直接疊加
即混合模式為正常,前景的不透明度為100%,如下所示:
得到的混合結果為 B = 97 G = 76 R = 153 A = 168
注意這些資料的格式都是 Format32bppArgb,而非Format32bppPArgb,即沒有進行預乘的ARGB資料。
根據這些資料進行推算,得出以下規律,首先是結果色的A值計算公式如下:
其中ClampToByte函數的作用為限制括号内的資料在0和255之間,如果大于255,則取255,如果小于0,則取0值。
按照此公式複核下上面的結果看下:
結果正确。
對于RGB各分量,計算公式要複雜很多,經過推到和測試結果如下(以B分量為例):
把資料帶入核算一下:
同理:
公式完全正确。
上面的計算如果要保證精度,則A值需要用浮點數儲存,這樣可能在某些場合下造成計算瓶頸,如果要全部用整數運算,可利用用Matlab的符号運算在做簡化。
在matlab中用如下代碼做測試:
得到結果:
B1 - (255*A2*(B1 - B2))/(255*A2 - A1*(A2 - 255))
這個結果隻有一個除法,而且可以看到除法的分子和分母的資料也不會大于int32所能表達的範圍。這樣可借助于整數的除法實作結果。
場景二:僅僅改變圖層混合模式
我們僅僅改變前景色圖層的混合模式,而不改變其不透明度。以正片疊底模式為例,如下圖所示:
此時前述兩個顔色的混合值如下所示:
B = 91 G = 67 R = 133 A = 168
注意到A值并沒有任何的變化。
此時,我們定義一個函數F,表示混合模式對兩種的顔色影響,F(X, Y)表示某種混合模式下兩種顔色值X和Y的混合結果,對于正片疊底,F(X,Y)的計算方法為:
F(X,Y) = X * Y / 255;
經過測試,這個時候的RGB分量的混合公式為:
把資料帶入核算一下:
G和R的值就不進行重複的核算了。
這個計算式用Maltab去簡化的話基本沒有任何效果。
場景三:僅僅改變圖層的不透明度
如下所示設定,前景層的不透明度為70%。
此時前述兩個顔色的混合值如下所示:
B = 108 G = 80 R = 147 A = 139
所有的顔色都變了。
還是先來看A值,經過測試比對,此時A值的計算公式為:
其中O表示不透明度的值,有效範圍是[0,100]。
核算一下:
對于A值,我們可以認為不透明度首先修改了改成的Alpha,然後再拿這個新的Alpha和底層的Alpha進行正常的混合。
對于RGB各分量,經過推到和測試結果如下(以B分量為例):
正确無誤。
場景四:同時改變圖層混合模式和不透明度
如下所示設定,同時設定混合模式為正片疊底,不透明度為70%。
此時前述兩個顔色的混合值如下所示:
B = 103 G = 72 R = 130 A = 139
可以看到,A值和混合模式沒啥關系,之和不透明度有關,直接用隻改變不透明度時的公式:
那麼RGB的變化,從前面的幾個公式中可以猜測肯定是先下面這個式子了:
測試下:
完全正确。
那麼在寫代碼的時候,我們最需要優化的就是這個情況的公式。不過用matlab測試這個公式沒啥好優化的。
上述公式裡其實有些ClampToByte函數是可以不需要的。
上傳下我用于測試兩個小的32位圖像了供有興趣的朋友測試。
圖檔非常小啊,注意仔細觀察并下載下傳。
如果想時刻關注本人的最新文章,也可關注公衆号: