為什麼底片反轉後人臉會發青?C-41 橙色色罩消除原理與著色器實作
所有讓人臉發青的反轉工具都犯了同一個錯:把密度空間的問題當成線性問題來解。這裡給出推導與著色器程式碼。
把翻拍圖丟進任何通用修圖軟體,按一下「反相」,人臉就會發青。常見診斷是「白平衡不對」——這是錯的,所以你拉色溫滑桿永遠調不準。這層色偏是廠商刻意做進底片裡的,而清除它需要的是除法,不是減法。
一、片基為什麼是橙色的
彩色負片的青、洋紅染料在光譜上並不純淨,會吸收本不該吸收的波段(副吸收)。放著不管,從負片還原出的所有顏色都會被污染。C-41 通用的解法是彩色偶合劑:未參與反應的偶合劑維持黃橙色,形成一層與被補償副吸收形狀完全一致的正性色罩。那層橙色是內建的校正濾鏡,不是瑕疵。
由此得到的結論
沖洗完成的 C-41 負片是被刻意做成非中性的。任何假設片基中性的反轉演算法,從第一步就在解另一道題。
二、線性反相「1 − RGB」的陷阱
底片對光的響應是指數型的。光學密度定義為 D = log₁₀(1 / T)(T 為透過率),而乳劑對曝光呈線性的是密度而非透過率。用 255 - x 反轉 8 位 sRGB 值等於反轉透過率:橙色分量被反轉成青色留在畫面裡,位於透過率壓縮端的暗部則被壓成一塊死板的藏藍。
三、在密度空間裡減掉色罩
在密度空間裡,去掉片基就是一次普通減法:D_image = D_pixel − D_base。兩邊取指數後,減法變成除法 T_image = T_pixel / T_base——這正是著色器要「除以」取樣片基色而不是減去它的原因。之後一次冪運算再把乳劑的非線性響應還回來。
vec3 inverted = pow(max(vec3(0.0), 1.0 - (pixel / mask)), vec3(u_filmCurve));
inverted = clamp((inverted - u_black) / (u_white - u_black), 0.0, 1.0);
inverted = pow(inverted, vec3(1.0 / u_gamma));pixel / mask——密度空間中對橙色片基的減法。u_filmCurve(約 1.45–1.60)——還原 S 形乳劑響應,而非平直斜坡。u_black/u_white——色階拉伸,讓直方圖鋪滿又不截斷。u_gamma(1.8)——補償顯示傳遞函數;少了它中間調會偏暗發悶。
四、把 `mask` 取準:40×40 加離群值剔除
整套校正只依賴每個通道一個數值,因此一顆灰塵就能毀掉一整格。NegaScan 會在未曝光片基(齒孔間隙或格間空隙)取 40×40 區域求平均,並在平均前剔除超過 1.5 倍標準差的樣本,不需手工遮罩即可排除顆粒、灰塵與刮痕。
五、自己跑一次
與工作台完全相同的著色器,執行在你自己的 GPU 上。拖動分隔條,或把自己的負片拖進來看看你那捲的表現。
如果一個反轉工具說不出它把哪些像素當作片基,那它就是在猜——而這份猜測的後果,要你每一格親手去修。
繼續閱讀