Bobscript

使用Canvas生成照片直方图

使用Canvas生成照片直方图

最近刚接触HTML5的Canvas,然后想做点小东西。

什么是照片直方图

直方图是用来直观地表示图片的RGB三种颜色通道在不同亮度值上面,所占的量的多少。

大家都知道,电脑上的数码照片的每个像素由红绿蓝三种颜色合成,所以一个像素具有R-红色,G-绿色,B-蓝色三种颜色的信息;每种颜色取值是0-255————当为0的时候,表示当前像素没有这种颜色,当为最大值255的时候,表示这种颜色含量已经最高。

比如,纯红色的RGB就是(255,0,0),即红色最多,不含绿色和蓝色。黄色由红色和绿色合成,所以纯黄色RGB就是(255,255,0)。

Photoshop的直方图

然后,直方图的横坐标从左到右依次是0到255,纵坐标没有上限,当x为定值的时候,不同颜色的y值表示的是:亮度(姑且这么称呼)为x的这种颜色的量有y这么多。

直方图在摄影中经常用到,通过查看照片的直方图,可以知道曝光是否准确。如果需要的是正常的曝光,那么就应该使照片的各种颜色集中在x的中间值,大约100-150区间内,直方图呈现中间凸起的形状。

更多的信息,大家可以搜索查看照片直方图

说了这么多,终于进入正题了。

DEMO演示

点击查看:Canvas生成照片直方图

思路说明:

先载入一张图,然后获取图片的每个像素的值,然后对每个像素的R\G\B值分别统计,然后得到一个数组包含了3种颜色的量。这里设的是一个叫做tj的二维数组,红色是tj[0],绿色是tj1,蓝色是tj[2];用tj[0][210]的值来表示亮度为210的红色像素的数量。

得到tj数组之后转换为直方图:例如tj[1][145]=3872转换为在x为145,y为3872的像素的地方用绿色画一个点,当然,y太大的话,直方图太高,所以下面会将y除以10来“压扁”直方图。

代码部分的说明直接写到注释中了。

HTML部分很简单:

<canvas id="canvas" width="756" height="300"></canvas>

JS部分:

var c = document.getElementById("canvas"),
    ctx = c.getContext("2d"),
    img = new Image,
    tj=[[],[],[],[]]; //三维数组,统计RGB三种颜色的

//初始化统计数组
for (var i = 0; i < 256; i++) {
    tj[0][i]=0;
    tj[1][i]=0;
    tj[2][i]=0;
};

img.src='RGB.jpg';  //这里需要遵循同源原则,图片和JS要同域,不然待会读取不到图片像素数据
img.onload=function(){
    ctx.drawImage(img, 0, 0, 400,300);
    imgData=ctx.getImageData(0,0,400,300);
    imgDataTemp=ctx.createImageData(400,300);
    //imgDataTemp用来储存直方图的像素,这一步是将之用黑色背景初始化,setColor是自定义函数
    setColor(imgDataTemp.data,0);

    for (var i = 0; i < imgData.data.length; i++) {
        //统计不同颜色的数量,tj[0][210]的值表示亮度为210的红色像素的数量
        tj[i%4][ imgData.data[i] ] ++;
    };

    for (var i = 0; i < 4; i++) {
        for (var j = 0; j < 256; j++) {
            drawPoint(imgDataTemp,j,tj[i][j]/10,i)  //将颜色的数量除以10,防止直方图太高
        };
    };

    ctx.putImageData(imgDataTemp, 500, 0);

};

//函数drawPoint(img,x,y,c)表示在img对象的x、y坐标处用颜色c画一个点。c=0,1,2分别表示R,G,B
function drawPoint(img,x,y,c){
    x=Math.round(x);
    y=Math.round(y);
    var _px;
    for (var i = 300-y; i < 300; i++) {
        _px=(img.width*i+x)*4+c;
        img.data[_px]=255;
    };
}

//将imgData的每个像素用灰色填充(c,c,c),同时每个像素点的Alph透明度设置为不透明(255);
function setColor(o,c) {
    var l=o.length, i=0;
    for(;i<l;i++) {
        if (i%4!==3) {
            o[i] = c;
        }else{
            o[i] = 255;
        }
    };
};

本文结束,今天是广州今年最热的一天,下了一个多月的暴雨的季节应该也快结束了,夏天来了,蚊子来了。