著色器圖像處理(亮度/對比度/反像)

基于固定基圖像的圖像混合操作:針對圖像各像素與常量值之間的混合操作

圖像的基本屬性。首先是亮度,也稱灰度,它是大 家常說的YUV格式的Y分量,如果使用RGB表示圖像,那么可采用前面 章節(jié)中提到的公式轉(zhuǎn)換出亮度信息;其次是對比度(contrast),即畫面黑與白的比值,也就是從黑到白的漸變層次,比值越大,說明從黑到白的漸變層次越多,色彩表現(xiàn)越豐富;最后是飽和度(saturation),是指 色彩的鮮艷程度,也稱為色彩的純度。

原圖

亮度調(diào)節(jié)

亮度調(diào)節(jié)有兩種一種是線性調(diào)節(jié), 一種是非線性調(diào)節(jié)

亮度值可視為顏色值中“非黑色”的數(shù)量。對于RGB顏色值,“淺色” 意味著顏色值分量接近于1.0,而“深色”則意味著顏色值分量接近于0.0。

1.非線性調(diào)節(jié)

頂點(diǎn)著色器

attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;

void main()
{
    varyTextCoord = textCoordinate;
    gl_Position = position;
}

片元著色器讓每一個RGB顏色分量都加上相同的增量

precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    /*
     以紋素的方式填充紋理, shader會自動的根據(jù)紋理坐標(biāo)去提取紋素來填充
     colorMap 紋理
     varyTextCoord 紋理坐標(biāo)
     */
    lowp vec4 temp = texture2D(colorMap, varyTextCoord);
    //取值范圍0-1, glsl不允許不同的類進(jìn)行計算
    float brightness = 0.5;
    gl_FragColor = vec4(temp.r+brightness, temp.g+brightness, temp.b+brightness, temp.a);
}

brightness 可以使用attribute的方式當(dāng)做參數(shù), 這樣可以動態(tài)修改

非線性調(diào)節(jié)結(jié)果, 結(jié)果感覺像是從外面加了一層蒙版一樣的感覺, 不太自然

Simulator Screen Shot - iPhone X - 2019-11-30 at 18.46.14.png
2.線性調(diào)節(jié)

為什么說線性調(diào)節(jié)會比較自然呢, 因為人眼并不會去區(qū)分RGB顏色分量占多少比例, 而是對明暗比較明暗, HSL就是通過色相(Hue)、飽和度 (Saturation)、明度(Lightness)三個通道的顏色,每個通道都可使用 0~255的數(shù)值來表示。這種調(diào)節(jié)是通過對色相、飽和度、明度三個顏色 通道的變化及其相互之間的疊加來得到各種顏色。符合人眼的直觀感覺.

  1. 線性調(diào)節(jié)的頂點(diǎn)著色器和非線性調(diào)節(jié)的頂點(diǎn)著色器是一樣
precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    
    lowp vec4 color = texture2D(colorMap, varyTextCoord);
    
    //這里的HSL是以0-255來表示的, 所以需要先把0-1范圍的RGB值轉(zhuǎn)為0-255
    float r = color.r * 255.0;
    float g = color.g * 255.0;
    float b = color.b * 255.0;

    //RGB最大值減去RGB最小值,除以2即為L
    float L = ((max(r, max(g, b)) + min(r, min(g, b))) / 2.0);

    float rHS = 0.0;
    float gHS = 0.0;
    float bHS = 0.0;
    //
    if(L > 128.0) {
        rHS = (r * 128.0 - (L - 128.0) * 256.0) / (256.0 - L);
        gHS = (g * 128.0 - (L - 128.0) * 256.0) / (256.0 - L);
        bHS = (b * 128.0 - (L - 128.0) * 256.0) / (256.0 - L);
    } else {
        rHS = r * 128.0 / L;
        gHS = g * 128.0 / L;
        bHS = b * 128.0 / L;
    }

    // [0-255]
    float delta = 50.0;
    float newL = L + delta - 128.0;
    float newR = .0;
    float newG = .0;
    float newB = .0;
    if(newL > 0.0) {
        newR = rHS + (256.0 - rHS) * newL / 128.0;
        newG = gHS + (256.0 - gHS) * newL / 128.0;
        newB = bHS + (256.0 - bHS) * newL / 128.0;
    } else {
        newR = rHS + rHS * newL / 128.0;
        newG = gHS + gHS * newL / 128.0;
        newB = bHS + bHS * newL / 128.0;
    }
       //這里的值RGB值根據(jù)delta值不同, 可能會大于1, 不過在OpenGL ES 中大于1的值會被處理成1, 也就是全部是白色的了.
    gl_FragColor = vec4(newR/255.0, newG/255.0, newB/255.0, color.a);

}
Simulator Screen Shot - iPhone X - 2019-11-30 at 18.46.44.png

看起來好像是比較自然, 從內(nèi)部向外部出來的顏色.

  1. 前面提到過, 亮度值可視為顏色中非黑色的數(shù)量, 所以提升亮度可以通過減少圖片展黑色的數(shù)量來做.
    使用mix函數(shù)來差值減少黑色數(shù)量, 如果ratio是0.0,它會返回第一個輸入;如果是1.0,會返回第二個輸入值。輸入0.2則會返回80%的第一個輸入顏色和20%的第二個輸入顏色,即返回兩個紋理的混合色。輸入大與1的數(shù), 則會提升圖片亮度.
mix(colorA, colorB, ratio)

片元著色器

precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    lowp vec4 color = texture2D(colorMap, varyTextCoord);
    lowp vec3 rgb = color.rgb;
    vec3 black = vec3(0.0, 0.0, 0.0);
    float ut = 3.0;
    vec3 mixColor = mix(black, rgb, ut);
    gl_FragColor = vec4(mixColor, color.a);
}

black定義一個黑色, 使用mix來差值計算黑色所占的比例, 下面是當(dāng)ut值為3時的渲染結(jié)果.

Simulator Screen Shot - iPhone X - 2019-12-01 at 13.22.24.png

同樣也可以把black改成其他的顏色值, 來混和成不同的結(jié)果.

  1. 還有一種更簡單的方式直接對RGBA執(zhí)行一個相同的倍數(shù)值

precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    vec4 sample0 = texture2D(colorMap, varyTextCoord);
    gl_FragColor = sample0 * 1.5;

}

對比度調(diào)節(jié)

圖像對比度描述了顏色值相對于灰度值的突出程度。當(dāng)計算圖像中的對比度時,可將50%的灰度圖作為基圖像

vec3(0.5, 0.5, 0.5)

在進(jìn)行插值計算值, 原圖所占的分量越大, 則灰度越少, 對比度越明顯, 即ut小于1, 將個顏色分量越接近0.5, 降低圖像對比度; 大于1將顏色分量遠(yuǎn)離0.5, 增加對比度;

precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    lowp vec4 color = texture2D(colorMap, varyTextCoord);
    lowp vec3 rgb = color.rgb;
    //亮度
//    vec3 target = vec3(0.0, 0.0, 0.0);
    //對比度
    vec3 target = vec3(0.5, 0.5, 0.5);
    float ut = 2.5;
    vec3 mixColor = mix(target, rgb, ut);
    gl_FragColor = vec4(mixColor, color.a);

}
Simulator Screen Shot - iPhone X - 2019-12-01 at 14.22.08.png

反像

反像操作針對圖像的“負(fù)”數(shù)據(jù)的工作方式進(jìn)行建模,從白色中減去各像素的顏色值即可獲得反像,如下所示:

vec3(1.0,1.0, 1.0) - color.rgb 

基于負(fù)像的片元著色器代碼,分別創(chuàng)建了某一顏色值及其負(fù)值。隨后,可用變量uT對其進(jìn)行混合。uT= 1處表示原始顏色值,uT= 0處則表示負(fù)值。

precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    lowp vec4 color = texture2D(colorMap, varyTextCoord);
    lowp vec3 rgb = color.rgb;
    //亮度
//    vec3 target = vec3(0.0, 0.0, 0.0);
    //對比度
//    vec3 target = vec3(0.5, 0.5, 0.5);
    //反像
    vec3 neg = vec3(1.0, 1.0, 1.0) - rgb;
    float ut = 0.0;
    gl_FragColor = vec4(mix(neg, rgb, ut), color.a);

}
Simulator Screen Shot - iPhone X - 2019-12-01 at 14.39.11.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容