用Canvas实现一些简单的图片滤镜

在这个数码产品泛滥的时代里,拍照已经成为生活不可或缺的一部分,不管是居家,踏青,还是远途旅行,总会拍一些美美的照片。但相机直接拍出来的照片往往和我们的心理预期有一定的差距,那么怎么减小这种差距呢?答案是美颜P图,于是各种美颜相机铺天盖地而来,P图已经成为一门随身技能。

其实所谓的美颜不过是很多滤镜的配合使用罢了,而滤镜就是通过一定的算法来操作图片像素进而得到一些特殊的图像效果。用过Photoshop的朋友都清楚ps中有一大堆的滤镜,下面我们将会用js的canvas技术去实现几种滤镜效果。

1、灰度滤镜

对于灰度滤镜的实现一般有三种算法

1) 最大值法:即新的颜色值R=G=B=Max(R,G,B),通过这种方法处理后的图片看起来亮度值偏高。

2) 平均值法:即新的颜色值R=G=B=(R+G+B)/3,这种方法处理的效果比较柔和

3) 加权平均值法:即新的颜色值R=G=B=(R*Wr+G*Wg+B*Wb),一般由于人眼对不同颜色的敏感度不一样,所以三种颜色值的权重不一样,一般来说绿色最高,红色其次,蓝色最低,最合理的取值分别为Wr=30%,Wg=59%,Wb=11%

在这里我们使用加权平均值法:

function greyEffect(canvasId){
	var canvas = document.getElementById(canvasId),
		ctx = canvas.getContext("2d"),
		imageData = ctx.getImageData(0,0,canvas.width,canvas.height),
		pixelData = imageData.data;
	for(var i=0;i<canvas.width*canvas.height;i++){
		var r = pixelData[i*4+0],
			g = pixelData[i*4+1],
			b = pixelData[i*4+2];
		var grey = 0.3 * r + 0.59 * g + 0.11 * b;
		pixelData[i*4+0] = grey;
		pixelData[i*4+1] = grey;
		pixelData[i*4+2] = grey;
	}
	return imageData;
}

2、黑白滤镜

算法原理:求RGB平均值Avg=(R+G+B)/3,如果Avg>=100,则新的颜色值为R=G=B=255;如果Avg<100,则新的颜色值为R=G=B=0;255就是白色,0就是黑色;至于为什么用100作比较,这是一个经验值吧,设置为128也可以,可以根据效果来调整。

function blackEffect(canvasId){
	var canvas = document.getElementById(canvasId),
		ctx = canvas.getContext("2d"),
		imageData = ctx.getImageData(0,0,canvas.width,canvas.height),
		pixelData = imageData.data;
	for(var i=0;i<canvas.width*canvas.height;i++){ var r = pixelData[i*4+0], g = pixelData[i*4+1], b = pixelData[i*4+2]; var grey = (r+g+b)/3; if(grey>=100){
			v = 255;
		}else{
			v = 0;
		}
		pixelData[i*4+0] = v;
		pixelData[i*4+1] = v;
		pixelData[i*4+2] = v;
	}
	return imageData;
}

3、反相滤镜(底片效果)

算法原理:将当前像素点的RGB值分别与255之差后的值作为当前点的RGB值,即R=255–R;G=255–G;B=255–B

function reverseEffect(canvasId){
	var canvas = document.getElementById(canvasId),
		ctx = canvas.getContext("2d"),
		imageData = ctx.getImageData(0,0,canvas.width,canvas.height),
		pixelData = imageData.data;
	for(var i=0;i<canvas.width*canvas.height;i++){
		pixelData[i*4+0] = 255-pixelData[i*4+0];
		pixelData[i*4+1] = 255-pixelData[i*4+1];
		pixelData[i*4+2] = 255-pixelData[i*4+2];
	}
	return imageData;
}

4、模糊滤镜

算法原理:将当前像素的周边像素的RGB值各自的平均值作为新的RGB值。

function blurEffect(size){
	var canvas = document.getElementById(canvasId),
		ctx = canvas.getContext("2d"),
		imageData = ctx.getImageData(0,0,canvas.width,canvas.height),pixelData = imageData.data,
		tmpimageData = ctx.getImageData(0,0,canvas.width,canvas.height),
		tmppixelData = imageData.data;
	size = size ? size : 1;
	var count = Math.pow((size*2+1),2)-1;
	for(var i=0;i<canvas.height;i++){
        for(var j=0;j<canvas.width;j++){
            var totalr = 0,totalg = 0,totalb = 0;
            for(var dx=i-size;dx<=i+size;dx++){
                for(var dy=j-size;dy<=j+size;dy++){
                    var p = dx * canvas.width + dy;
                    if(dx===i && dy===j) continue;
                    tmppixelData[p*4+0] && (totalr += tmppixelData[p*4+0]);
                    tmppixelData[p*4+1] && (totalg += tmppixelData[p*4+1]);
                    tmppixelData[p*4+2] && (totalb += tmppixelData[p*4+2]);
                }
            }
            var p = i * canvas.width + j;
            pixelData[p*4+0] = totalr/count;
            pixelData[p*4+1] = totalg/count;
            pixelData[p*4+2] = totalb/count;
        }
    }
	return imageData;
}

5、马赛克滤镜

算法原理:其实就是将图像分成大小一致的图像块,每一个图像块都是一个正方形,并且在这个正方形中所有像素值都相等。我们可以将这个正方形看作是一个模板窗口,模板中对应的所有图像像素值都等于该模板的左上角第一个像素的像素值,这样的效果就是马赛克效果,而正方形模板的大小则决定了马赛克块的大小,即图像马赛克化的程度。

function gosike(size){
	var canvas = document.getElementById(canvasId),
		ctx = canvas.getContext("2d"),
		imageData = ctx.getImageData(0,0,canvas.width,canvas.height),pixelData = imageData.data,
		tmpimageData = ctx.getImageData(0,0,canvas.width,canvas.height),
		tmppixelData = imageData.data;
	size = size ? size : 16;
	var totalNum = Math.pow(size,2);
	var count = Math.pow((size*2+1),2);
	for(var i=0;i<canvas.height;i+=size){
		for(var j=0;j<canvas.width;j+=size){
			var totalr = 0,totalg = 0,totalb = 0;
			for(var dx=0;dx<=size;dx++){
				for(var dy=0;dy<=size;dy++){
					var x = i + dx;
					var y = j + dy;
					var p = x * canvas.width + y;
					totalr += tmppixelData[p*4+0];
					totalg += tmppixelData[p*4+1];
					totalb += tmppixelData[p*4+2];
				}
			}
			var p = i * canvas.width + j;
			var avgr = totalr/count;
			var avgg = totalg/count;
			var avgb = totalb/count;
			for(var dx=0;dx<=size;dx++){
				for(var dy=0;dy<=size;dy++){
					var x = i + dx;
					var y = j + dy;
					var p = x * canvas.width + y;
					pixelData[p*4+0] = avgr;
					pixelData[p*4+1] = avgg;
					pixelData[p*4+2] = avgb;
				}
			}
		}
	}
	return imageData;
}

6、浮雕滤镜

算法原理:用当前点的RGB值减去相邻点的RGB值并加上128作为新的RGB值。由于图片中相邻点的颜色值是比较接近的,因此这样的算法处理之后,只有颜色的边沿区域,也就是相邻颜色差异较大的部分的结果才会比较明显,而其他平滑区域则值都接近128左右,也就是灰色,这样就具有了浮雕效果。在实际的效果中,这样处理后,有些区域可能还是会有一些"彩色"的点或者条状痕迹,所以最好再对新的RGB值做一个灰度处理。

function outset(size){
	var canvas = document.getElementById(canvasId),
		ctx = canvas.getContext("2d"),
		imageData = ctx.getImageData(0,0,canvas.width,canvas.height),
		pixelData = imageData.data,
		precolor = {};
	for(var i=0;i<canvas.width*canvas.height;i++){
		if(i==0){
			precolor = {
				r : pixelData[i*4+0],
				g : pixelData[i*4+1],
				b : pixelData[i*4+2]
			}
		}else{
			var r = pixelData[i*4+0] - precolor.r + 128;
			var g = pixelData[i*4+1] - precolor.g + 128;
			var b = pixelData[i*4+2] - precolor.b + 128;
			precolor = {
				r : pixelData[i*4+0],
				g : pixelData[i*4+1],
				b : pixelData[i*4+2]
			}
			pixelData[i*4+0] = r;
			pixelData[i*4+1] = g;
			pixelData[i*4+2] = b;
		}
		var r = pixelData[i*4+0],
			g = pixelData[i*4+1],
			b = pixelData[i*4+2];
		var grey = 0.3 * r + 0.59 * g + 0.11 * b;
		pixelData[i*4+0] = grey;
		pixelData[i*4+1] = grey;
		pixelData[i*4+2] = grey;
	}
	return imageData;
}

7、去色滤镜

算法原理:将当前像素的RGB值得最大值和最小值求平均值并作为新的RGB值。

function removeColor(){
	var canvas = document.getElementById(canvasId),
		ctx = canvas.getContext("2d"),
		imageData = ctx.getImageData(0,0,canvas.width,canvas.height),
		pixelData = imageData.data;
	for(var i=0;i<canvas.width*canvas.height;i++){
		var r = pixelData[i*4+0],
			g = pixelData[i*4+1],
			b = pixelData[i*4+2];
		var c = Math.floor((Math.min(r,g,b) + Math.max(r,g,b))/2);
		pixelData[i*4+0] = c;
		pixelData[i*4+1] = c;
		pixelData[i*4+2] = c;
	}
	return imageData;
}

好了,暂时就这么些吧,以后再补充,我们的目标是做一个自带丰富滤镜库的在线PS!

在线Demo:http://demo.deanhan.cn/filter/

  • 支付宝二维码 支付宝
  • 微信二维码 微信
相关文章