AmazingCounters.com

[canvas入坑2]模糊效果

查看效果请到 http://philippica.github.io/  点击blur

 

模糊效果比较好的应该是高斯模糊,一个点的值变成了以该点为圆心的一个圆内所有像素的加权平均,权重由二维正态分布计算出

 

以前用qt实现过一个高斯模糊,但是js的速度毕竟不能和c++比,为了实现一个比较好的效果,这里在效率和效果方面做了个折中,每一点的值等于以这个点为中心的正方形内所有像素值的平均

这样的优点是计算速度快,矩阵天然的存着正方形,所以通过一个O(canvasWidth * canvasHeight)的预处理,接下来即可迅速地得到每个像素的值

具体方法应该是acm里用烂的方法,sum[i][j]存着以(i,j)为右下角的到左上角画布中所有该通道值的和,于是画布中任意矩形的和都可以用一个类似容斥的方法O(1)得到

预处理的代码:

 1     var ppImgData = context.getImageData(0, 0, ppCanvasWidth, ppCanvasHeight);
 2     var ppData = ppImgData.data;
 3     var ppTemp = ppData;
 4     var radius = 0;
 5     var length = ppData.length; 
 6     $('#range').attr("value", 0);
 7     for(var i = 0; i < ppCanvasHeight; i++)
 8     {
 9         for(var j = 0; j < ppCanvasWidth; j++)
10         {
11             var position = i * ppCanvasWidth + j;
12             var x = (position) * 4;
13             sumR[position] = ppData[x];
14             sumG[position] = ppData[x + 1];
15             sumB[position] = ppData[x + 2];
16             if(i != 0)
17             {
18                 sumR[position] += sumR[position - ppCanvasWidth];
19                 sumG[position] += sumG[position - ppCanvasWidth];
20                 sumB[position] += sumB[position - ppCanvasWidth];
21             }
22             if(j != 0)
23             {
24                 sumR[position] += sumR[position - 1];
25                 sumG[position] += sumG[position - 1];
26                 sumB[position] += sumB[position - 1];
27             }
28             if(i != 0 && j != 0)
29             {
30                 sumR[position] -= sumR[position - ppCanvasWidth - 1];
31                 sumG[position] -= sumG[position - ppCanvasWidth - 1];
32                 sumB[position] -= sumB[position - ppCanvasWidth - 1];
33             }
34         }
35     }

sumR sumG sumB分别存着三个通道内的预处理的值,radius表示模糊半径

 

具体计算模糊的代码:

 1     function ppBlur()
 2     {
 3         var area = (radius + radius + 1) * (radius + radius + 1);
 4         for(var i = 0; i < ppCanvasHeight; i++)
 5         {
 6             for(var j = 0; j < ppCanvasWidth; j++)
 7             {
 8                 var position = i * ppCanvasWidth + j;
 9                 var x = (position) * 4;
10                 var tt = (i + radius) * ppCanvasWidth + j + radius;
11                 var tt2 = (i - radius - 1) * ppCanvasWidth + j + radius;
12                 var tt3 = (i + radius) * ppCanvasWidth + j - radius - 1;
13                 var tt4 = (i - radius - 1) * ppCanvasWidth + j - radius - 1;
14                 ppTemp[x] = (sumR[tt] - sumR[tt2] - sumR[tt3] + sumR[tt4]) / area;
15                 ppTemp[x + 1] = (sumG[tt] - sumG[tt2] - sumG[tt3] + sumG[tt4]) / area;
16                 ppTemp[x + 2] = (sumB[tt] - sumB[tt2] - sumB[tt3] + sumB[tt4]) / area;            
17             }
18         }
19         ppData = ppTemp;
20         context.putImageData(ppImgData, 0, 0);
21     }
sumR[tt] - sumR[tt2] - sumR[tt3] + sumR[tt4]就是容斥出该正方形内R通道的和,再除以该区域内像素的总数即是平均值

总结:边界处理不好,在图片的边缘会明显变暗,主要是在边界处area的发生了变化

 

posted @ 2015-10-31 11:12  philippica  阅读(599)  评论(0编辑  收藏  举报