通过RGB和HSV之间的转换修改图片的亮度

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

版权声明:本文为suyuanli原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/suyuanli/p/14541067.html