• [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的发生了变化
  • 相关阅读:
    响应式布局
    Margin是什么?
    分布式系统设计(1)
    Hadoop处理大量小文件的问题和解决方法
    Facebook揭密:如何让MySQL数据库集群自主运行
    大数据营销的优势
    LevelDB系列之SSTable(Sorted Strings Table)文件
    LevelDB系列之Log文件
    LevelDB系列之整体架构
    LevelDb系列之简介
  • 原文地址:https://www.cnblogs.com/philippica/p/4925156.html
Copyright © 2020-2023  润新知