聊聊顏色的技術(shù)實現(xiàn)(四)—— 從色覺到量化后的YUV

物理世界中的量變成編碼流程的顏色空間YUV歷程:

  1. 從物理世界中的量開始

物理世界中的一個絕對顏色,通過對比參照ICC(<u>International Color Consortium</u>)中RGB屬性的色彩配置文件酗钞,得到一個RGB值腹忽;或 攝像機根據(jù)其CCD/CMOS上每個單色像素點的電荷量(物理量)来累,生成相應的Raw文件,raw通過轉(zhuǎn)換矩陣(拜耳矩陣)窘奏,轉(zhuǎn)換成標準的RGB格式嘹锁。

  1. RGB經(jīng)伽馬校正形成 R'G'B';

伽馬校正:由于顯示器(陰極射線管顯示器CRT)顯示圖像的時候着裹,電壓增加一倍领猾,亮度并不跟著增加一倍,即輸出亮度和電壓并不是成線性關(guān)系的求冷,而是按冪函數(shù)變化瘤运,通常gamma值為2.2(2.2通常是是大多數(shù)顯示設(shè)備的大概平均gamma值〗程猓基于gamma2.2的顏色空間叫做sRGB顏色空間拯坟。每個監(jiān)視器的gamma曲線都有所不同,但是gamma2.2在大多數(shù)監(jiān)視器上表現(xiàn)都不錯)韭山,這樣當電壓為50%時郁季,亮度如果是線性的那么應該也是50%的亮度,由于gamma的存在钱磅,亮度為50%^2.2 = 21.8%梦裂,亮度要低很多;Gamma校正(Gamma Correction)的思路是在最終的顏色輸出上應用監(jiān)視器Gamma的倒數(shù)盖淡。

而在物理世界中年柠,如果光的強度增加一倍,那么亮度也會增加一倍褪迟;為了使顯示器顯示的顏色與人眼觀察世界看到的物理世界一樣冗恨,我們在顯示器輸入之前,做一個操作把顯示器的Gamma2.2影響平衡掉(人們并沒有去調(diào)節(jié)CRT本身味赃,也許太難搞了掀抹,或者問題發(fā)現(xiàn)時已經(jīng)有太多的CRT),這個叫做Gamma校正:本來相機采集到的亮度是線性的心俗,但存儲的時候采用了gamma編碼傲武,采用gamma值的倒數(shù)的冪函數(shù)處理顏色,也就是說城榛,我們的jpeg文件里的顏色值已經(jīng)進行了gamma校正揪利,都是非線性空間的值,位于gamma空間吠谢,記為R'G'B'土童,常見的sRGB標準中顏色值也是gamma空間的。而在圖形渲染時工坊,使用的顏色是按照線性空間考慮的献汗,要在線性空間計算顏色,所以顏色計算前需要將顏色重新轉(zhuǎn)回線性空間王污,后續(xù)會講罢吃。
(不過CRT已經(jīng)不主流了,但是gamma還是被保留了下來昭齐,可能是為了兼容各類輸入設(shè)備吧尿招。The gamma value has no effect on alpha samples, which are always a linear fraction of full opacity.)

Gamma Correction相關(guān)總的流程如下:



  1. R'G'B'==>Y'U'V'==>Y'Pb'Pr'==>Y'Cb'Cr'

YUV comes from R'G'B'

前文提到:

紅、綠阱驾、藍三個顏色通道每種色各分為255階亮度就谜,在0時“燈”最弱——是關(guān)掉的,而在255時“燈”最亮里覆。當三色數(shù)值相同時為無色彩的灰度色丧荐,而三色都為255時為最亮的白色,都為0時為黑色喧枷。

由于人眼對亮度更敏感虹统,我們就從R'G'B'把亮度提取出來,用Y分量表示

Y' = kr R' + (1-kb-kr)G' + kb B'

kr隧甚,kb的取值大小取決于色彩空間標準车荔,一般綠色G'前面系數(shù)(1-kb-kr)最大了,因為人眼對綠色的亮度程度更敏感戚扳。UV是由B'-Y'與R'-Y'限幅而來的忧便,限幅的目的是防止色域越限,同時確保編碼后的復合電視信號電平在VHF/UHF電視發(fā)射機的要求范圍內(nèi)一個RGB圖像可以在捕捉之后轉(zhuǎn)換為 YCbCr格式用來減少存儲和傳輸負擔帽借。

U' = B'-Y' = -kr R' -  (1-kb-kr)G' + (1 - kb)B' //亮度與藍色分量的差值
V' = R'-Y' = (1-kr)R' - (1-kb-kr)G' - kb B'  //亮度與紅色分量的差值

以上變換可以經(jīng)過矩陣變換實現(xiàn)珠增。

在顯示圖象之前,再轉(zhuǎn)回為RGB宜雀。G可以從YCbCr中解壓出來切平,這說明不需要存儲和傳輸Cg參數(shù)。

R' = Y' + (1-kr)/0.5 * V'
G' = Y' - 2kb(1-kb)/(1-kb-kr) * U' - 2kr(1-kr)/(1-kb-kr) * V'
B' = Y' + (1-kb)/0.5 * U'

而后根據(jù)使用場景需要對進行YUV進一步處理,獲得Y'U'V'、Y'Cb'Cr'咧栗、Y'Pb'Pr'等格式蜒程,后面統(tǒng)稱為Y'U'V';

Y'U'V'际度、Y'Cb'Cr'、Y'Pb'Pr',他們有什么區(qū)別嗎届氢?各自什么來歷呢?

我覺得還是很有必要分辨它們的覆旭,不然當你R'G'B'<=>Y'U'V'轉(zhuǎn)換時選用哪一個矩陣都可能混淆退子,導致色差岖妄。

首先Y'U'V'、Y'Cb'Cr'寂祥、Y'Pb'Pr'都是YUV格式荐虐,都是用亮度、色差來存儲顏色信息丸凭。其中Y'Pb'Pr'是用于模擬系統(tǒng)播放福扬,Y'Cb'Cr'適用于數(shù)字系統(tǒng)播放。實際上惜犀,Y'Pb'Pr' 是Y'U'V'基于偏移縮放產(chǎn)生的格式铛碑;Y'Cb'Cr'是基于Y'Pb'Pr'信號進行量化,從模擬信號轉(zhuǎn)化成數(shù)字信號的而來虽界;

為了更形象具體的解釋上述內(nèi)容汽烦,我們具體到SDTV with BT.601中來看:

Y'Pb'Pr' 
kr = 0.229
kb = 0.114
kg = 1 - kr - kb = 0.587
Umax = 0.5
Vmax = 0.5

所以

Y' = 0.299R' + 0.587G' + 0.114B'

Pb =( Umax /(1- Wb))* (B' - Y' ) = 0.564 * (B' - Y' )

Pr= ( Vmax /(1- Wr))* (R' - Y' ) = 0.713 * (R' - Y' )

Y~ [0,1] U,V~[-0.5,0.5] R', G', B' in [0; 1]



為了解決浮點型數(shù)的精度問題,Y'CbCr comes out~,Y'浓恳、Cb刹缝、Cr分量將會 scaled 為8bits 的整數(shù)Y:[ 0, 255 ],Cb'\Cr' :[-128,128]; 為了解決濾波后的過沖現(xiàn)象,Y分量將會 shift 到 [16, 235] 颈将,Cb\Cr分量將會 shift 到[16 , 240]梢夯,為了在數(shù)字系統(tǒng)中使用YUV格式來表示顏色,模擬信號將會被量化成數(shù)字信號晴圾。
具體步驟:

  1. 根據(jù)值域范圍進行縮放,成整數(shù)格式颂砸,整型運算代替浮點運算
    Limited Y~(16,235) U/V ~(16,240) RGB取值范圍均為0-255
    Y(scaled before shift) = Y * (235 - 16) = (0.299R' + 0.587G' + 0.114B')* (235 - 16) = 66 R' + 129 G' + 25 B'
    U (scaled before shift) = Pb * (240 - 16) = (-0.168736R' + 0.331264G' + 0.5B')* (240 - 16)
    V 就不贅述了......

    Full range Y~(0,256) U/V ~(0,256)
    Y = (77R + 150G + 29B)>>8;
    U = ((-44
    R - 87G + 131B)>>8) + 128;
    V = ((131R - 110G - 21*B)>>8) + 128 ;

  2. 根據(jù)值域范圍進行平移,為了使各個分量不會出現(xiàn)負數(shù)或者超出值域的值



    [16, 235] Y′ values are conventionally shifted and scaled to the range [16, 235] (referred to as studio swing or "TV levels") rather than using the full range of [0, 255] (referred to as full swing or "PC levels"). This practice was standardized in SMPTE-125M in order to accommodate signal overshoots ("ringing") due to filtering.

  3. 各個分量進行量化處理

  1. 為了方便運算 將分母轉(zhuǎn)化成256(相當于<<8),所以上式分子與分母應該都乘以256/255
  1. 對應逆轉(zhuǎn)公式如下:

ITU-R BT.601 recommendation幫我們整理了一下上述公式

于是 我們得到了我們會直接拿來用的矩陣公式

// BT.601, which is the standard for SDTV.
const GLfloat sColorConversion601[] = {
        1.164,  1.164, 1.164,
        0.0, -0.392, 2.017,
        1.596, -0.813,   0.0,
};

所以我們可以知道 這個公式對應的是 601 值域范圍為[16, 235]死姚、[16 , 240]的 digital的YUV 人乓,Y'Cb'Cr',轉(zhuǎn)換成R'G'B'的矩陣公式都毒。
Y'=0.5時,第一個圖是Y'U'V'色罚,第二個圖是Y'Cb'Cr'(坐標值歸一化后),


之所以展示這些圖是為了說明账劲,U分量決定色度戳护,Y分量決定亮度。

色差空間標準的加權(quán)值krkb不同瀑焦。

BT 709

BT 2020

我們常用的JPEG使用Y'Cr'Cb'的修訂后的BT 609 標準腌且,CB and CR have the full 8-bit range of [0...255], 就是 Full range,也就是·說上述第二步中的Y'分量不需要加16榛瓮,其他步驟保持不變铺董,從而

在YUV 家族中,Y'CbCr 是在計算機系統(tǒng)中應用最多的成員禀晓,我們絕大多數(shù)的場景中遇到的YUV格式精续,就是YCbCr坝锰。YCbCr其中Y是指亮度分量,Cb指藍色色度分量驻右,而Cr指紅色色度分量,可以從下圖中主觀感知一下Cb什黑、Cr的效果:

!](https://upload-images.jianshu.io/upload_images/6638024-27f4491bd2ab2de7?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

That the white snow is represented as a middle value in both Cr and Cb;

that the brown barn is represented by weak Cb and strong Cr;

that the green grass is represented by weak Cb and weak Cr;

and that the blue sky is represented by strong Cb and weak Cr.

  1. 編碼:輸入是Y'U'V'格式 輸出是文件崎淳;
  2. 解碼:輸入是文件 軟解碼輸出是Y'U'V'格式堪夭;硬解碼輸出是R'G'B'(Surface 紋理)
  3. OpenGL渲染圖形時gamma correction

https://learnopengl.com/Advanced-Lighting/Gamma-Correction

由于OpenGL渲染時會在線性RGB空間進行計算處理,所以顏色被發(fā)送到幀緩沖中已經(jīng)完成了gamma空間的R'G'B'到線性空間RGB的轉(zhuǎn)換拣凹。

float gamma = 2.2;
vec3 diffuseColor = pow(texture(diffuse, texCoords).rgb, vec3(gamma));

對于移動端森爽,這個轉(zhuǎn)換是默認進行的(后來實驗證明是錯的),默認執(zhí)行g(shù)lEnable(GL_FRAMEBUFFER_SRGB)嚣镜,以下說明均是以該開關(guān)enable的前提下爬迟。

在OpenGL中,shader以及texture的filtering 過程中菊匿,處理的顏色都要求是線性的付呕,而屏幕顯示是非線性的sRGB。所以存在一個轉(zhuǎn)換過程跌捆,即sRGB -> RGB, RGB -> sRGB徽职。最終會在讀取時進行sRGB到線性的轉(zhuǎn)換,并在寫入時進行線性到sRGB的轉(zhuǎn)換佩厚。
在OpenGL上姆钉,圖片可以用紋理表示,也可以用framebuffer表示抄瓦,它們都是一塊buffer潮瓶。sRGB圖片在OpenGL下會有以下幾種處理情況。
通過使用glTexImage2D钙姊、glTexSubImage2D等等毯辅,通過傳入的圖片數(shù)據(jù),生成使用sRGB顏色空間的圖片煞额。因此思恐,OpenGL 會認為傳入的數(shù)據(jù)所用的顏色空間是sRGB colorspace,如果傳入的圖片不在此顏色空間立镶,可能會發(fā)生圖片變色的情況壁袄。 shader通過sampler讀取數(shù)據(jù)(也就是texel),OpenGL會認為傳入圖片的texel處于sRGB顏色空間,(依然前提是glEnable(GL_FRAMEBUFFER_SRGB))但是shader處理的時候需要的是線性的顏色空間媚媒,這個時候嗜逻,OpenGL會自動執(zhí)行一次顏色空間的轉(zhuǎn)換,sRGB -> RGB缭召。
通過Framebuffer處理圖片栈顷,需要明確告訴OpenGL是否啟用伽瑪校正逆日。通過調(diào)用glEnable(GL_FRAMEBUFFER_SRGB) 啟用framebuffer的伽瑪校正,OpenGL會把輸出的顏色從線性的顏色空間轉(zhuǎn)換成非線性的sRGB萄凤,否則室抽,圖片輸出到屏幕的時候,是沒有伽瑪校正靡努,圖片會較暗坪圾。這一類的framebuffer叫作:sRGB Frame Buffer。它是由硬件支持的惑朦,在不支持GL_FRAMEBUFFER_SRGB的情況下(OpenGL ES 3.0 之后才支持)兽泄,數(shù)據(jù)的轉(zhuǎn)換可以通過shader來實現(xiàn),這里暫時不深究漾月。但是sRGB Frame Buffer的轉(zhuǎn)換速度要比它快病梢,畢竟是硬件支持的。另外需要注意的是alpha的數(shù)據(jù)是不做轉(zhuǎn)換的梁肿,而且只能支持每位8位的格式數(shù)據(jù)蜓陌。
可以通過glGetFramebufferAttachmentParameter來查詢該framebuffer是否開啟GL_FRAMEBUFFER_SRGB。

glGetFramebufferAttachmentParameter(GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)

寫:當fragment shader 向sRGB Frame Buffer寫入顏色的時候吩蔑,顏色會被編碼成sRGB格式的數(shù)據(jù)钮热,然后存儲到framebuffer中。 讀:當從sRGB Frame Buffer讀取數(shù)據(jù)的時候哥纫,顏色以sRGB的格式讀取霉旗,然后轉(zhuǎn)換成線性的顏色數(shù)據(jù)返回
其中sRGB就是R'G'B'中的一種,其對應的gamma值為 2.2蛀骇。
總結(jié):
我們的圖像資源解碼Y'CrCb轉(zhuǎn)換成R'G'B'厌秒,framebuffer里要存放的是sRGB的值,我們從fragment shader采樣的時候擅憔,將紋理 sRGB空間的值轉(zhuǎn)換成線性空間的顏色值鸵闪,然后線性空間的顏色值在傳入這個sRGB framebuffer的時候,framebuffer相關(guān)內(nèi)部操作會將顏色再轉(zhuǎn)成sRGB存入framebuffer中(sRGB framebuffer 會認為傳入的值都是線性空間的值)暑诸;當OpenGL需要信息一些渲染處理蚌讼,尤其是物理光模型,當硬件支持 GL 3.x+時个榕,從framebuffer中取出的值會自動轉(zhuǎn)換成 線性空間值篡石,然后對這個線性空間值做相應的filtering操作,或者把它跟其他framebuffer取出來的線性空間值進行blending西采,最后framebuffer相關(guān)內(nèi)部操作將blending后的線性空間值轉(zhuǎn)換成sRGB空間的值存入framebuffer凰萨;最后 用于顯示時,從framebuffer取出sRGB值來顯示。

大致先這些吧==

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胖眷,一起剝皮案震驚了整個濱河市武通,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌珊搀,老刑警劉巖冶忱,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異境析,居然都是意外死亡囚枪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門簿晓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來眶拉,“玉大人,你說我怎么就攤上這事憔儿。” “怎么了放可?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵谒臼,是天一觀的道長。 經(jīng)常有香客問我耀里,道長蜈缤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任冯挎,我火速辦了婚禮底哥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘房官。我一直安慰自己趾徽,他們只是感情好,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布翰守。 她就那樣靜靜地躺著孵奶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜡峰。 梳的紋絲不亂的頭發(fā)上了袁,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音湿颅,去河邊找鬼载绿。 笑死,一個胖子當著我的面吹牛油航,可吹牛的內(nèi)容都是我干的崭庸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冀自!你這毒婦竟也來了揉稚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤熬粗,失蹤者是張志新(化名)和其女友劉穎搀玖,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驻呐,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡灌诅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了含末。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片猜拾。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖佣盒,靈堂內(nèi)的尸體忽然破棺而出挎袜,到底是詐尸還是另有隱情,我是刑警寧澤肥惭,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布盯仪,位于F島的核電站,受9級特大地震影響蜜葱,放射性物質(zhì)發(fā)生泄漏全景。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一牵囤、第九天 我趴在偏房一處隱蔽的房頂上張望爸黄。 院中可真熱鬧,春花似錦揭鳞、人聲如沸炕贵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鲁驶。三九已至,卻和暖如春舞骆,著一層夾襖步出監(jiān)牢的瞬間钥弯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工督禽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脆霎,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓狈惫,卻偏偏與公主長得像睛蛛,于是被迫代替她去往敵國和親鹦马。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容