zoukankan      html  css  js  c++  java
  • 高斯模糊

    要想实现高斯模糊的特点,则需要通过构建对应的权重矩阵来进行滤波。

    1.3.1 正态分布
     
    正态分布

    正态分布中,越接近中心点,取值越大,越远离中心,取值越小。
    计算平均值的时候,我们只需要将"中心点"作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。正态分布显然是一种可取的权重分配模式。

    1.3.2 高斯函数

    如何反映出正态分布?则需要使用高函数来实现。
    上面的正态分布是一维的,而对于图像都是二维的,所以我们需要二维的正态分布。


     
     

    正态分布的密度函数叫做"高斯函数"(Gaussian function)。它的一维形式是:

     
     

    其中,μ是x的均值,σ是x的方差。因为计算平均值的时候,中心点就是原点,所以μ等于0。

     
     

    根据一维高斯函数,可以推导得到二维高斯函数:

     
     
    在计算的时候可以将二维高斯函数拆分为两个一维高斯函数:
     
     
    在运算的时候速度会加快很多,有了这个函数 ,就可以计算每个点的权重了。
    1.3.3 获取权重矩阵

    假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下:

     
     

    更远的点以此类推。
    为了计算权重矩阵,需要设定σ的值。假定σ=1.5,则模糊半径为1的权重矩阵如下:
     
     

    这9个点的权重总和等于0.4787147,如果只计算这9个点的加权平均,还必须让它们的权重之和等于1,因此上面9个值还要分别除以0.4787147,得到最终的权重矩阵。
     
     

    除以总值这个过程也叫做”归一问题“
    目的是让滤镜的权重总值等于1。否则的话,使用总值大于1的滤镜会让图像偏亮,小于1的滤镜会让图像偏暗。
    1.3.4 计算模糊值

    有了权重矩阵,就可以计算高斯模糊的值了。
    假设现有9个像素点,灰度值(0-255)如下:

     
     

    每个点乘以自己的权重值:
     
     

    得到
     
     

    将这9个值加起来,就是中心点的高斯模糊的值。
    对所有点重复这个过程,就得到了高斯模糊后的图像。对于彩色图片来说,则需要对RGB三个通道分别做高斯模糊。
    1.3.5 边界值问题

    既然是根据权重矩阵来进行处理的

     
     

    如果一个点处于边界,周边没有足够的点,怎么办?

    • ① 对称处理,就是把已有的点拷贝到另一面的对应位置,模拟出完整的矩阵。
    • ② 赋0,想象图像是无限长的图像的一部分,除了我们给定值的部分,其他部分的像素值都是0
    • ③ 赋边界值,想象图像是无限制长,但是默认赋值的不是0而是对应边界点的值

     分别对x,y做一阶高斯滤波效果速度比较快

    <!DOCTYPE html>
    <html>
    
    <head lang="en">
        <meta charset="UTF-8">
        <title>test</title>
    </head>
    
    <body>
        <img src="./test.jpg" alt="img source" id="imgSource">
        <canvas id="canvas"></canvas>
        <script>
            window.onload = function() {
                var img = document.getElementById("imgSource"),
                    canvas = document.getElementById('canvas'),
                    width = img.width,
                    height = img.height;
    
                // console.log(width);
    
                canvas.width = width;
                canvas.height = height;
    
                var context = canvas.getContext("2d");
                context.drawImage(img, 0, 0);
    
                var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);
    
                //console.log(canvasData);
    
                // 开始
                var startTime = +new Date();
                var tempData = gaussBlur1(canvasData, 8);
                // var tempData = gosike(canvasData);
    
    
                context.putImageData(tempData, 0, 0);
    
                var endTime = +new Date();
                console.log(" 一共经历时间:" + (endTime - startTime) + "ms");
            }
    
            /**
             * 此函数为二重循环
             */
            function gaussBlur(imgData, radius, sigma) {
                var pixes = imgData.data,
                    width = imgData.width,
                    height = imgData.height;
    
                radius = radius || 5;
                sigma = sigma || radius / 3;
    
                var gaussEdge = radius * 2 + 1; // 高斯矩阵的边长
    
                var gaussMatrix = [],
                    gaussSum = 0,
                    a = 1 / (2 * sigma * sigma * Math.PI),
                    b = -a * Math.PI;
    
                for (var i = -radius; i <= radius; i++) {
                    for (var j = -radius; j <= radius; j++) {
                        var gxy = a * Math.exp((i * i + j * j) * b);
                        gaussMatrix.push(gxy);
                        gaussSum += gxy; // 得到高斯矩阵的和,用来归一化
                    }
                }
                var gaussNum = (radius + 1) * (radius + 1);
                for (var i = 0; i < gaussNum; i++) {
                    gaussMatrix[i] = gaussMatrix[i] / gaussSum; // 除gaussSum是归一化
                }
    
                //console.log(gaussMatrix);
    
                // 循环计算整个图像每个像素高斯处理之后的值
                for (var x = 0; x < width; x++) {
                    for (var y = 0; y < height; y++) {
                        var r = 0,
                            g = 0,
                            b = 0;
    
                        //console.log(1);
    
                        // 计算每个点的高斯处理之后的值
                        for (var i = -radius; i <= radius; i++) {
                            // 处理边缘
                            var m = handleEdge(i, x, width);
                            for (var j = -radius; j <= radius; j++) {
                                // 处理边缘
                                var mm = handleEdge(j, y, height);
    
                                var currentPixId = (mm * width + m) * 4;
    
                                var jj = j + radius;
                                var ii = i + radius;
                                r += pixes[currentPixId] * gaussMatrix[jj * gaussEdge + ii];
                                g += pixes[currentPixId + 1] * gaussMatrix[jj * gaussEdge + ii];
                                b += pixes[currentPixId + 2] * gaussMatrix[jj * gaussEdge + ii];
    
                            }
                        }
                        var pixId = (y * width + x) * 4;
    
                        pixes[pixId] = ~~r;
                        pixes[pixId + 1] = ~~g;
                        pixes[pixId + 2] = ~~b;
                    }
                }
                imgData.data = pixes;
                return imgData;
            }
    
            function handleEdge(i, x, w) {
                var m = x + i;
                if (m < 0) {
                    m = -m;
                } else if (m >= w) {
                    m = w + i - x;
                }
                return m;
            }
    
            
            /**
             * 此函数为分别循环
             */
            function gaussBlur1(imgData, radius, sigma) {
                var pixes = imgData.data;
                var width = imgData.width;
                var height = imgData.height;
                var gaussMatrix = [],
                    gaussSum = 0,
                    x, y,
                    r, g, b, a,
                    i, j, k, len;
    
    
                radius = Math.floor(radius) || 3;
                sigma = sigma || radius / 3;
    
                a = 1 / (Math.sqrt(2 * Math.PI) * sigma);
                b = -1 / (2 * sigma * sigma);
                //生成高斯矩阵
                for (i = 0, x = -radius; x <= radius; x++, i++) {
                    g = a * Math.exp(b * x * x);
                    gaussMatrix[i] = g;
                    gaussSum += g;
    
                }
                //归一化, 保证高斯矩阵的值在[0,1]之间
                for (i = 0, len = gaussMatrix.length; i < len; i++) {
                    gaussMatrix[i] /= gaussSum;
                }
                //x 方向一维高斯运算
                for (y = 0; y < height; y++) {
                    for (x = 0; x < width; x++) {
                        r = g = b = a = 0;
                        gaussSum = 0;
                        for (j = -radius; j <= radius; j++) {
                            k = x + j;
                            if (k >= 0 && k < width) { //确保 k 没超出 x 的范围
                                //r,g,b,a 四个一组
                                i = (y * width + k) * 4;
                                r += pixes[i] * gaussMatrix[j + radius];
                                g += pixes[i + 1] * gaussMatrix[j + radius];
                                b += pixes[i + 2] * gaussMatrix[j + radius];
                                // a += pixes[i + 3] * gaussMatrix[j];
                                gaussSum += gaussMatrix[j + radius];
                            }
                        }
                        i = (y * width + x) * 4;
                        // 除以 gaussSum 是为了消除处于边缘的像素, 高斯运算不足的问题
                        // console.log(gaussSum)
                        pixes[i] = r / gaussSum;
                        pixes[i + 1] = g / gaussSum;
                        pixes[i + 2] = b / gaussSum;
                        // pixes[i + 3] = a ;
                    }
                }
                //y 方向一维高斯运算
                for (x = 0; x < width; x++) {
                    for (y = 0; y < height; y++) {
                        r = g = b = a = 0;
                        gaussSum = 0;
                        for (j = -radius; j <= radius; j++) {
                            k = y + j;
                            if (k >= 0 && k < height) { //确保 k 没超出 y 的范围
                                i = (k * width + x) * 4;
                                r += pixes[i] * gaussMatrix[j + radius];
                                g += pixes[i + 1] * gaussMatrix[j + radius];
                                b += pixes[i + 2] * gaussMatrix[j + radius];
                                // a += pixes[i + 3] * gaussMatrix[j];
                                gaussSum += gaussMatrix[j + radius];
                            }
                        }
                        i = (y * width + x) * 4;
                        pixes[i] = r / gaussSum;
                        pixes[i + 1] = g / gaussSum;
                        pixes[i + 2] = b / gaussSum;
                        // pixes[i] = r ;
                        // pixes[i + 1] = g ;
                        // pixes[i + 2] = b ;
                        // pixes[i + 3] = a ;
                    }
                }
                //end
                imgData.data = pixes;
                return imgData;
            }
        </script>
    </body>
    
    </html>
    

      



  • 相关阅读:
    struts.xml,报错 1 c.opensymphony.xwork2.util.DomHelper
    poi 导入Excle
    Oracle update语句更新值来自另一张表中的数据
    Oracle 《积累章》 根据身份证号码更新当前出生日期
    java 反射得到属性与属性值
    spring mvc 简单的文件上传与下载
    java扫描文件。
    类加载机制
    容器工厂(原型&单例)
    容器工厂(原型)
  • 原文地址:https://www.cnblogs.com/ckAng/p/10903974.html
Copyright © 2011-2022 走看看