canvas-修改圖片亮度

Mr.蘇發表於2021-03-16

canvas操作-修改圖片亮度

圖片亮度的概念

我們一般對圖片的概念就是又很多畫素點構成的一幅圖片,一個畫素點由RGBA四個值表示。

  • R:紅色
  • G:綠色
  • B:藍色
  • A:透明度

不過RGBA並不能直觀的表現出畫素點的亮度,它比較適合機器理解,給一個rgba的畫素我們可以猜出它是偏什麼顏色的,不過卻不能理解它的亮度值。所以rgba並不是一個很好作為圖片處理的格式,這裡我們引入HSV(HSB)它的組成為:

  • H:色調代表的是顏色,在這個模型中,色調是從0度到360度。
  • S:飽和度表示顏色空間中的灰色範圍。它的範圍從0到100%(0~1)。當值為0時,顏色為灰色,當值為1時,顏色為原色。一個比較淡的顏色是由於飽和度較低,也就是顏色包含更多的灰色。
  • V(B):值是顏色的亮度,並隨顏色飽和度而變化。它的範圍從0到100%,值為0時,顏色空間將全部變黑。隨著數值的增加,色彩空間亮度增加並顯示出各種顏色。

用下面這個圓柱體來表示 HSV 顏色空間,圓柱體的橫截面可以看做是一個極座標系 ,H 用極座標的極角表示,S 用極座標的極軸長度表示,V 用圓柱中軸的高度表示。

這裡色調各個角度表示的顏色如下:

角度 顏色
0-60 紅色
60-120 黃色
120-180 綠色
180-240 青色
240-300 藍色
300-360 紅紫色

image-20210315225621390

下面用ps截圖舉一個例子:

下圖的取到的點對應的HSV是(16,71,97),而RGB是(248,120,73)這裡通過HSV可以看出亮度是97,非常直觀。

image-20210315001231722

而下面這張圖是通過濾鏡給圖片增加了一個50%透明黑色遮罩,就是降低了50%的亮度。通過HSV可以看出亮度為49。所以我們可以通過rgba和hsv之間的轉換來調整圖片的亮度。

image-20210315001939110

調整圖片亮度的方案

  1. 通過rgbahsv之間的轉換
  2. 通過在原圖片的上層蓋上一層具有一定透明度的黑色遮罩

這裡方案2實施起來比較簡單,不過在處理具備透明度的png圖片時,會導致透明部分也被遮罩導致變得非透明。所以方案1會比較通用。

實現方案一

從RGB到HSV的轉換

轉換的公式

設 (r, g, b)分別是一個顏色的紅、綠和藍座標,它們的值是在0到1之間的實數。設max等價於r, gb中的最大者。設min等於這些值中的最小者。要找到在HSL空間中的 (h, s, l)值,這裡的h ∈ [0, 360)是角度的色相角,而s, l ∈ [0,1]是飽和度和亮度,計算為:

image-20210315232621310

h的值通常規範化到位於0到360°之間。而h = 0用於max = min的(定義為灰色)時候而不是留下h未定義。

HSL和HSV有同樣的色相定義,但是其他分量不同。HSV顏色的sv的值定義如下:

image-20210315232730896

javascript實現程式碼

// arr: rgb陣列
function rgb2hsv (arr) {
    let rr;
    let gg;
    let bb;
    let r = arr[0] / 255;
    let g = arr[1] / 255;
    let b = arr[2] / 255;
    let h;
    let s;
    let v = Math.max(r, g, b);
    let diff = v - Math.min(r, g, b);
    let diffc = function (c) {
        return (v - c) / 6 / diff + 1 / 2;
    };

    if (diff === 0) {
        h = s = 0;
    } else {
        s = diff / v;
        rr = diffc(r);
        gg = diffc(g);
        bb = diffc(b);

        if (r === v) {
            h = bb - gg;
        } else if (g === v) {
            h = (1 / 3) + rr - bb;
        } else if (b === v) {
            h = (2 / 3) + gg - rr;
        }
        if (h < 0) {
            h += 1;
        } else if (h > 1) {
            h -= 1;
        }
    }
    return [Math.round(h * 360), Math.round(s * 100), Math.round(v * 100)]
}

從HSV到RGB的轉換

轉換的公式

給定在HSV中 (h, s, v)值定義的一個顏色,帶有如上的變化於0到360之間的h,和分別表示飽和度和明度的變化於0到1之間的sv,在RGB空間中對應的 (r, g, b)三原色可以計算為(R,G,B變化於0到1之間):

image-20210315233245933

javascript實現程式碼

function hsv2rgb (hsv) {
    let _l = hsv[0];
    let _m = hsv[1];
    let _n = hsv[2];
    let newR;
    let newG;
    let newB;
    if (_m === 0) {
        _l = _m = _n = Math.round(255 * _n / 100);
        newR = _l;
        newG = _m;
        newB = _n;
    } else {
        _m = _m / 100;
        _n = _n / 100;
        let p = Math.floor(_l / 60) % 6;
        let f = _l / 60 - p;
        let a = _n * (1 - _m);
        let b = _n * (1 - _m * f);
        let c = _n * (1 - _m * (1 - f));
        switch (p) {
            case 0:
                newR = _n; newG = c; newB = a;
                break;
            case 1:
                newR = b; newG = _n; newB = a;
                break;
            case 2:
                newR = a; newG = _n; newB = c;
                break;
            case 3:
                newR = a; newG = b; newB = _n;
                break;
            case 4:
                newR = c; newG = a; newB = _n;
                break;
            case 5:
                newR = _n; newG = a; newB = b;
                break;
        }
        newR = Math.round(255 * newR);
        newG = Math.round(255 * newG);
        newB = Math.round(255 * newB);
    }
    return [newR, newG, newB]
}

實現亮度的調整

下面的程式碼是實現降低圖片50%亮度的實現

<body>
  <img src="./pic.jpg" id="pic">
  <canvas id="canvas" width="200" height="273"></canvas>
</body>
const pic = document.querySelector('#pic')
const canvas = document.querySelector('#canvas')
const ctx = canvas.getContext('2d')
ctx.drawImage(pic, 0, 0, 200, 273);
const imgData = ctx.getImageData(0, 0, 200, 273)
// 降低50%的亮度
ctx.putImageData(changeLuminance(imgData, -0.5), 0, 0)

// 修改圖片亮度, imgdata為從canvas獲取到的rgba陣列,value為需要增加或減少的亮度值(0~1)
function changeLuminance (imgdata, value) {
    const data = imgdata.data
    for (let i = 0; i < data.length; i+=4) {
        const hsv = rgb2hsv([data[i], data[i + 1], data[i + 2]])
        hsv[2] *= (1 + value)
        const rgb = hsv2rgb([...hsv])
        data[i] = rgb[0];
        data[i + 1] = rgb[1];
        data[i + 2] = rgb[2];
    }
    return imgdata
}

image-20210316002808817

相關文章