图像处理 高斯滤波(带权值的均值滤波)

一、介绍

1、一维高斯滤波。

         \LARGE f(x)=\frac{1}{\sqrt{2\pi }\sigma }e^\frac{-(x-u)^2}{2\sigma^2 }

    a表示得到曲线的高度,u是指曲线在x轴的中心, σ指width(与半峰全宽有关,即平方差)。

2、二维高斯滤波。

        \LARGE f(x,y)=\frac{1}{2\pi \sigma ^2}e^\frac{-(x^2+y^2)}{2\sigma ^2}

二、二维高斯滤波模版

1、生成维高斯滤波模版。

public class MathUtils {
    /**
     * 获取高斯滤波模版的二维数组
     *
     * @param length 模版长度,length=6sigma(%99.74), length=4sigma(95%), length=2sigma(68%)
     * @param sigma  模版标准差,length=6sigma(%99.74), length=4sigma(95%), length=2sigma(68%)
     */
    public static double[][] getGaussTemplate(int length, double sigma) {
        double[][] gaussTemplate = new double[length][length];    // 用于存储结果
        int centerIndex = (length - 1) / 2;//模版的中心点
        double variance = sigma * sigma;//方差
        double sum = 0;
        for (int i = 0; i < length; ++i) {
            for (int j = 0; j < length; ++j) {
                int xLength = j - centerIndex;//x上的距离
                int yLength = i - centerIndex;//y上的距离
                double e = Math.exp(-(xLength * xLength + yLength * yLength) / (2 * variance));
                gaussTemplate[i][j] = e / (2 * Math.PI * variance);
                sum += gaussTemplate[i][j];
            }
        }
        //占得比重
        for (int i = 0; i < length; ++i) {
            for (int j = 0; j < length; ++j) {
                gaussTemplate[i][j] = gaussTemplate[i][j] / sum;
            }
        }
        //打印模版
        System.out.println(String.format("生成大小为%d,标准差为%.3f的二维高斯模版:", length, sigma));
        for (double[] doubles : gaussTemplate) {
            for (int j = 0; j < gaussTemplate.length; j++) {
                System.out.print(String.format("%8.3f", doubles[j]));
            }
            System.out.println();
        }
        return gaussTemplate;
    }
}
public static void main(String[] args) {
        //高斯滤波的模版,length=6sigma(%99.74), length=4sigma(95%), length=2sigma(68%)
        double[][] gaussTemplate1 = FilterUtils.getGaussTemplate(3, 1.5);
        double[][] gaussTemplate2 = FilterUtils.getGaussTemplate(3, 0.75);
        double[][] gaussTemplate3 = FilterUtils.getGaussTemplate(3, 0.5);
        double[][] gaussTemplate4 = FilterUtils.getGaussTemplate(5, 2.5);
        double[][] gaussTemplate5 = FilterUtils.getGaussTemplate(5, 1.25);
        double[][] gaussTemplate6 = FilterUtils.getGaussTemplate(5, 0.833);
        double[][] gaussTemplate7 = FilterUtils.getGaussTemplate(7, 3.5);
        double[][] gaussTemplate8 = FilterUtils.getGaussTemplate(7, 1.75);
        double[][] gaussTemplate9 = FilterUtils.getGaussTemplate(7, 1.167);
    }

2、日志打印的结果。

        生成大小为3,标准差为1.500的二维高斯模版:
           0.095   0.118   0.095
           0.118   0.148   0.118
           0.095   0.118   0.095
        生成大小为3,标准差为0.750的二维高斯模版:
           0.051   0.124   0.051
           0.124   0.301   0.124
           0.051   0.124   0.051
        生成大小为3,标准差为0.500的二维高斯模版:
           0.011   0.084   0.011
           0.084   0.619   0.084
           0.011   0.084   0.011
        生成大小为5,标准差为2.500的二维高斯模版:
           0.029   0.036   0.039   0.036   0.029
           0.036   0.046   0.050   0.046   0.036
           0.039   0.050   0.054   0.050   0.039
           0.036   0.046   0.050   0.046   0.036
           0.029   0.036   0.039   0.036   0.029
        生成大小为5,标准差为1.250的二维高斯模版:
           0.009   0.022   0.031   0.022   0.009
           0.022   0.058   0.080   0.058   0.022
           0.031   0.080   0.110   0.080   0.031
           0.022   0.058   0.080   0.058   0.022
           0.009   0.022   0.031   0.022   0.009
        生成大小为5,标准差为0.833的二维高斯模版:
           0.001   0.006   0.013   0.006   0.001
           0.006   0.054   0.112   0.054   0.006
           0.013   0.112   0.230   0.112   0.013
           0.006   0.054   0.112   0.054   0.006
           0.001   0.006   0.013   0.006   0.001
        生成大小为7,标准差为3.500的二维高斯模版:
           0.013   0.016   0.018   0.019   0.018   0.016   0.013
           0.016   0.020   0.023   0.024   0.023   0.020   0.016
           0.018   0.023   0.026   0.027   0.026   0.023   0.018
           0.019   0.024   0.027   0.028   0.027   0.024   0.019
           0.018   0.023   0.026   0.027   0.026   0.023   0.018
           0.016   0.020   0.023   0.024   0.023   0.020   0.016
           0.013   0.016   0.018   0.019   0.018   0.016   0.013
        生成大小为7,标准差为1.750的二维高斯模版:
           0.003   0.007   0.011   0.013   0.011   0.007   0.003
           0.007   0.015   0.025   0.030   0.025   0.015   0.007
           0.011   0.025   0.041   0.048   0.041   0.025   0.011
           0.013   0.030   0.048   0.057   0.048   0.030   0.013
           0.011   0.025   0.041   0.048   0.041   0.025   0.011
           0.007   0.015   0.025   0.030   0.025   0.015   0.007
           0.003   0.007   0.011   0.013   0.011   0.007   0.003
        生成大小为7,标准差为1.167的二维高斯模版:
           0.000   0.001   0.003   0.004   0.003   0.001   0.000
           0.001   0.006   0.019   0.027   0.019   0.006   0.001
           0.003   0.019   0.056   0.081   0.056   0.019   0.003
           0.004   0.027   0.081   0.117   0.081   0.027   0.004
           0.003   0.019   0.056   0.081   0.056   0.019   0.003
           0.001   0.006   0.019   0.027   0.019   0.006   0.001
           0.000   0.001   0.003   0.004   0.003   0.001   0.000

3、结论。

        方差越大模版大小越大,各点和中心点的差距越大。并且模版长度length和标准差sigma之间的关系:length=6sigma(%99.74)、length=4sigma(%95)、length=2sigma(%68)。其中括号中的百分比指的是高斯模版中的数据占全部数据的百分之多少。

三、高斯滤波(带权值的均值滤波)

1、原图。高斯滤波只是在计算平均值的时候,根据距离的远近,带有权值而已。

2、代码。生成4张图片,高斯模版大小和方差分别是:(3、1)、(3、0.5)、(5、1)、(5、0.5)。

package com.zxj.reptile.test.mnist;

import com.zxj.reptile.utils.image.ImageService;
import com.zxj.reptile.utils.image.ImageUtils;

public class ImgTest {

    private static final String File_Path = "G:\\xiaojie-java-test\\img\\";

    public static void main(String[] args) {
        //高斯过滤
        String gaussSourcePath = File_Path + "滤波\\高斯滤波\\高斯噪声.jpg";
        String gaussTargetPath = File_Path + "滤波\\高斯滤波\\高斯滤波_";
        //高斯过滤 length=6sigma(%99.74), length=4sigma(95%), length=2sigma(68%)
        gaussFilter(sourcePath, targetPath + "3_6sigma.jpg", 3, 1.5);
        gaussFilter(sourcePath, targetPath + "3_4sigma.jpg", 3, 0.75);
        gaussFilter(sourcePath, targetPath + "3_2sigma.jpg", 3, 0.5);
        gaussFilter(sourcePath, targetPath + "5_6sigma.jpg", 5, 2.5);
        gaussFilter(sourcePath, targetPath + "5_4sigma.jpg", 5, 1.25);
        gaussFilter(sourcePath, targetPath + "5_2sigma.jpg", 5, 0.833);
        gaussFilter(sourcePath, targetPath + "7_6sigma.jpg", 7, 3.5);
        gaussFilter(sourcePath, targetPath + "7_4sigma.jpg", 7, 1.75);
        gaussFilter(sourcePath, targetPath + "7_2sigma.jpg", 7, 1.167);
    }
}
package com.zxj.reptile.utils.image;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;

public class ImageService {
    /**
     * 高斯过滤(加权的均值过滤)
     *
     * @param sourcePath 原图像
     * @param targetPath 目标图像
     * @param grayType   灰度化方式
     * @param length     模版长度,length=6sigma(%99.74), length=4sigma(95%), length=2sigma(68%)
     * @param sigma      模版标准差,length=6sigma(%99.74), length=4sigma(95%), length=2sigma(68%)
     */
    public static void gaussFilter(String sourcePath, String targetPath, int grayType, int length, double sigma) {
        try {
            //高斯模版
            double[][] gaussTemplate = ImageUtils.getGaussTemplate(length, sigma);
            //获取原图像对象,并获取原图像的二维数组
            BufferedImage image = ImageIO.read(new File(sourcePath));
            int[][] imgArrays = ImageUtils.getTwoDimension(image);
            //生成新图像的二维数组
            imgArrays = ImageUtils.getGrayImg(imgArrays, grayType);//灰度化
            int[][] newImgArrays = ImageUtils.getGaussFilter(imgArrays, gaussTemplate);//均值过滤
            //生成新图片对象,填充像素
            BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
            ImageUtils.setTwoDimension(newImage, newImgArrays, ImageUtils.Channel_Type_1);
            //生成图片文件
            ImageIO.write(newImage, "JPEG", new File(targetPath + size + "_" + variance + ".jpg"));
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package com.zxj.reptile.utils.image;

import java.awt.image.BufferedImage;

public class ImageUtils {
    /**
     * 获取高斯滤波模版的二维数组
     *
     * @param length 模版长度,length=6sigma(%99.74), length=4sigma(95%), length=2sigma(68%)
     * @param sigma  模版标准差,length=6sigma(%99.74), length=4sigma(95%), length=2sigma(68%)
     */
    public static double[][] getGaussTemplate(int length, double sigma) {
        double[][] gaussTemplate = new double[length][length];    // 用于存储结果
        int centerIndex = (length - 1) / 2;//模版的中心点
        double variance = sigma * sigma;//方差
        double sum = 0;
        for (int i = 0; i < length; ++i) {
            for (int j = 0; j < length; ++j) {
                int xLength = j - centerIndex;//x上的距离
                int yLength = i - centerIndex;//y上的距离
                double e = Math.exp(-(xLength * xLength + yLength * yLength) / (2 * variance));
                gaussTemplate[i][j] = e / (2 * Math.PI * variance);
                sum += gaussTemplate[i][j];
            }
        }
        //占得比重
        for (int i = 0; i < length; ++i) {
            for (int j = 0; j < length; ++j) {
                gaussTemplate[i][j] = gaussTemplate[i][j] / sum;
            }
        }
//        //打印模版
//        System.out.println(String.format("生成大小为%d,标准差为%.3f的二维高斯模版:", length, sigma));
//        for (double[] doubles : gaussTemplate) {
//            for (int j = 0; j < gaussTemplate.length; j++) {
//                System.out.print(String.format("%8.3f", doubles[j]));
//            }
//            System.out.println();
//        }
        return gaussTemplate;
    }

    /**
     * 高斯滤波
     *
     * @param imgArrays     图像二维数组
     * @param gaussTemplate 高斯滤波模版的二维数组
     */
    public static int[][] getGaussFilter(int[][] imgArrays, double[][] gaussTemplate) {
        final int imgHeight = imgArrays.length;
        final int imgWidth = imgArrays[0].length;
        int[][] newImgArrays = new int[imgHeight][imgWidth];
        //模版长度和半径
        final int filterLength = gaussTemplate.length;
        final int filterRadius = (filterLength - 1) / 2;
        //高斯过滤
        for (int h = 0; h < imgHeight; h++) {//图片第几行
            for (int w = 0; w < imgWidth; w++) {//图片第几列
                double weightTotal = 0;
                double sum = 0;
                for (int templateH = -filterRadius; templateH <= filterRadius; templateH++) {//模版第几行
                    int rowIndex = h + templateH;
                    if (rowIndex < 0 || rowIndex > imgHeight - 1) {
                        continue;
                    }
                    for (int templateW = -filterRadius; templateW < filterRadius; templateW++) {//模版第几列
                        int columnIndex = w + templateW;
                        if (columnIndex < 0 || columnIndex > imgWidth - 1) {
                            continue;
                        }
                        double weight = gaussTemplate[templateH + filterRadius][templateW + filterRadius];
                        sum += (imgArrays[rowIndex][columnIndex] * weight);
                        weightTotal += weight;
                    }
                }
                newImgArrays[h][w] = (int) (sum / weightTotal);
            }
        }
        return newImgArrays;
    }

    
    //灰度处理的方法
    public static final byte Gray_Type_Default = 0;//默认加权法
    public static final byte Gray_Type_Min = 1;//最大值法
    public static final byte Gray_Type_Max = 2;//最小值法
    public static final byte Gray_Type_Average = 3;//平均值法
    public static final byte Gray_Type_Weight = 4;//加权法
    public static final byte Gray_Type_Red = 5;//红色值法
    public static final byte Gray_Type_Green = 6;//绿色值法
    public static final byte Gray_Type_Blue = 7;//蓝色值法

    //生成的图片是几通道的
    public static final byte Channel_Type_Default = 0;//默认三通道
    public static final byte Channel_Type_1 = 1;//单通道
    public static final byte Channel_Type_3 = 3;//三通道

    /**
     * 灰度化处理
     *
     * @param imgArrays 图像二维数组
     * @param grayType  灰度化方法
     */
    public static int[][] getGrayImg(int[][] imgArrays, int grayType) throws Exception {
        final int imgHeight = imgArrays.length;
        final int imgWidth = imgArrays[0].length;
        int[][] newImgArrays = new int[imgHeight][imgWidth];
        for (int h = 0; h < imgHeight; h++) {
            for (int w = 0; w < imgWidth; w++) {
                final int[] grb = getRgb(imgArrays[h][w]);
                newImgArrays[h][w] = getGray(grb, grayType);
            }
        }
        return newImgArrays;
    }

    /**
     * 通过像素值,返回r、g、b颜色通道的值
     *
     * @param pixel 像素值
     */
    public static int[] getRgb(int pixel) {
        int[] rgb = new int[3];
        rgb[0] = (pixel >> 16) & 0xff;
        rgb[1] = (pixel >> 8) & 0xff;
        rgb[2] = pixel & 0xff;
        return rgb;
    }

    /**
     * 根据不同的灰度化方法,返回灰度值
     *
     * @param rgb      r、g、b颜色通道的值
     * @param grayType 不同灰度处理的方法
     */
    public static int getGray(int[] rgb, int grayType) throws Exception {
        if (grayType == Gray_Type_Average) {
            return (rgb[0] + rgb[1] + rgb[2]) / 3;   //rgb之和除以3
        } else if (grayType == Gray_Type_Weight || grayType == Gray_Type_Default) {
            return (int) (0.3 * rgb[0] + 0.59 * rgb[1] + 0.11 * rgb[2]);
        } else if (grayType == Gray_Type_Red) {
            return rgb[0];//取红色值
        } else if (grayType == Gray_Type_Green) {
            return rgb[1];//取绿色值
        } else if (grayType == Gray_Type_Blue) {
            return rgb[2];//取蓝色值
        }
        //比较三个数的大小
        int gray = rgb[0];
        for (int i = 1; i < rgb.length; i++) {
            if (grayType == Gray_Type_Min) {
                if (gray > rgb[i]) {
                    gray = rgb[i];//取最小值
                }
            } else if (grayType == Gray_Type_Max) {
                if (gray < rgb[i]) {
                    gray = rgb[i];//取最大值
                }
            } else {
                throw new Exception("grayType出错");
            }
        }
        return gray;
    }

    /**
     * 获取二维像素
     *
     * @param image BufferedImage图像对象
     */
    public static int[][] getTwoDimension(BufferedImage image) {
        final int imgWidth = image.getWidth();
        final int imgHeight = image.getHeight();
        int[][] imgArrays = new int[imgHeight][imgWidth];
        for (int i = 0; i < imgHeight; i++) {
            for (int j = 0; j < imgWidth; j++) {
                imgArrays[i][j] = image.getRGB(j, i);
            }
        }
        return imgArrays;
    }

    /**
     * 将二维像素填充到图像中
     *
     * @param image       BufferedImage图像对象
     * @param imgArrays   二维像素
     * @param channelType 单通道还是三通道
     */
    public static void setTwoDimension(BufferedImage image, int[][] imgArrays, int channelType) throws Exception {
        final int imgWidth = image.getWidth();
        final int imgHeight = image.getHeight();
        for (int i = 0; i < imgHeight; i++) {
            for (int j = 0; j < imgWidth; j++) {
                if (channelType == Channel_Type_1) {
                    image.setRGB(j, i, (byte) imgArrays[i][j]);
                } else if (channelType == Channel_Type_3 || channelType == Channel_Type_Default) {
                    image.setRGB(j, i, imgArrays[i][j]);
                } else {
                    throw new Exception("channelType错误");
                }
            }
        }
    }
}

3、结果。可以跟没有权重的均值滤波进行对比,发现高斯滤波(带有权值的均值滤波)在细节上的保留效果来的更加的好些。

发布了67 篇原创文章 · 获赞 401 · 访问量 41万+

猜你喜欢

转载自blog.csdn.net/qq_36511401/article/details/102904972
今日推荐