红包照片四不像(三)——canvas实现

本篇介绍使用canvas实现红包照片的效果。
在前一篇已经介绍了canvas处理图片的一些接口,接下来直接用这些接口实现模糊和偷窥镜的效果。

一、模糊效果

1、获取imageData

前面已经介绍过,通过接口

var imageData = context.getImageData(sx,sy,sw,sh)

获取canvas中的图像数据,所以首先需要一个绘制了原图的canvas,canvas绘制原图采用回调的方式:

Image image = new Image();
image.src = './images/pic.jpg'; // 图片地址
image.onload = function() {
    context.drawImage(image, 0, 0, canvas.width, canvas.height);
    var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
}

2、对imageData进行模糊变换

模糊的算法在前一节已经介绍过,这里可以直接使用即可。需要注意的是imageData的数据结构:

1、imageData是一个数组
2、数组的长度为canvas.height*canvas.width*4
3、数组的4*i~4*i+3连续的四个元素表示一个像素的rgba的值
4、数组代表的像素依次对应图像横向排列的像素,图像的第i行第j列的像素对应数组的(j*canvas.width + i)*4开始的4个元素

3、绘制变换后imageData

context.putImageData(imageData, 0, 0);

二、偷窥镜处理

前面绘制好了模糊图片,现在处理偷窥镜效果需要在其上覆盖另外一层canvas。

1、绘制圆形清晰图片

绘制图片中的一部分,需要使用canvas的裁剪功能。

context.save(); // save和restore在裁剪时使用,避免裁剪路径的重复使用
context.beginPath();
context.arc(x, y, raduis, 0, 2*Math.PI, false); // 弧形的剪裁(需要圆心坐标、半径、弧度和绘制是否逆时针)
context.clip();
context.drawImage(imageData, 0, 0, canvas.width, canvas.height);
context.restore();

2、偷窥镜的动态处理

包括两个方面——改变圆心的位置、改变半径的大小,然后重新绘制新的圆形图像即可,需要注意的是

1、圆心的位置要保证整个圆都包含在canvas中
2、每次重新绘制之前,需要清除画布——context.clearRect(0, 0, canvas.width, canvas.height)

三、算法改善——高斯模糊

1、低效率

非常尴尬的是,一张约400*500的图片做模糊,在良好的环境下居然耗时2秒多,效率很低。
计算一下之前模糊算法复杂度

        O(4*width*height*r^2)。

从实现的角度是没有办法处理的,所以必须要改变算法。
算法有两个方面:

1、牺牲效果来提高效率;
2、提高效果。

2、提高效率

由于需要对每个点做模糊处理,所以width和height是无法优化的,只能对每个点的模糊区域做处理,比较普遍的方法是化面为线,即在做平均值时,只取纵向和横向两条线(而不是整个区域),也可以加上两条对角线。这样最终得到的算法复杂度为

        O(4*width*height*r*2)。

2、高斯模糊

首先模糊的概念就是每个点的值取周围点值的加权平均值;而我们之前的算法,每个点的权值相等。
而高斯模糊则是根据实际来确定权值,即靠的越近的点权值越大,权值依据正态分布曲线计算,得到二维的Gauss函数如下:


gaussian_blur_2.jpg

由于前面已经提到二维的效率太低,所以只能老老实实的回到一维到世界了


gaussian_blur_1.jpg

四、结语

具体效果大家可以参考:http://tkixp9.github.io/redbag/demo_canvas.html 。

五、家庭作业

之前我们讲了css和canvas实现模糊的方法,其实svg也可以实现模糊,大家可以参考http://tkixp9.github.io/redbag/demo_svg.html 来完成对应的模糊和偷窥镜的效果(注意兼容性)。具体的使用,将会在以后的svg章节一起介绍。

你可能感兴趣的:(红包照片四不像(三)——canvas实现)