高斯模糊

362 阅读3分钟

方法一:

源码位置:github.com/itkang/imag…

package com.ruoyi.common.utils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

/**
 * <p class="detail">
 * 描述:高斯模糊
 * </p>
 *
 * @version V1.0
 * @ClassName: GaussianBlurUtil
 */
public class GaussianBlurUtil {

    public static void main(String[] args) throws IOException {
        int radius = 15; //设置模糊权重

        //获取当前jar所在路径
        String img_root_path = "D:/Pictures/test-blur/";
        System.out.println("current path:" + img_root_path);
        //获取当前路径下的所有图片文件
        java.util.List<String> images = listImgs(img_root_path);

        //如果当前目录图片数量不为0,就循环处理图片
        if (null != images && images.size() > 0) {
            System.out.println("has images " + images.size());
            for (String image : images) {
                BufferedImage img = ImageIO.read(new File(img_root_path + image));
                long start = System.currentTimeMillis();
                img = blur(img, radius);
                long end = System.currentTimeMillis();
                ImageIO.write(img, "jpeg", new File(img_root_path + image));//覆盖源文件
                System.out.println(image + ":花费时间:" + (end - start));
            }
        } else {
            System.out.println("path is empty!");
        }
    }

    /**
     * <p class="detail">
     * 功能:模糊执行方法
     * </p>
     *
     * @param img    原图片
     * @param radius 模糊权重
     * @return 模糊后图片
     * @throws IOException
     * @date 2016年4月20日
     */
    public static BufferedImage blur(BufferedImage img, int radius) throws IOException {
        int height = img.getHeight();
        int width = img.getWidth();
        int[] values = getPixArray(img, width, height);
        values = doBlur(values, width, height, radius);
        img.setRGB(0, 0, width, height, values, 0, width);
        return img;
    }

    /**
     * <p class="detail">
     * 功能:获取图像像素矩阵
     * </p>
     *
     * @param im
     * @param w
     * @param h
     * @return
     * @date 2016年4月20日
     */
    private static int[] getPixArray(Image im, int w, int h) {
        int[] pix = new int[w * h];
        PixelGrabber pg = null;
        try {
            pg = new PixelGrabber(im, 0, 0, w, h, pix, 0, w);
            if (pg.grabPixels() != true)
                try {
                    throw new java.awt.AWTException("pg error" + pg.status());
                } catch (Exception eq) {
                    eq.printStackTrace();
                }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return pix;
    }

    /**
     * <p class="detail">
     * 功能:高斯模糊算法。
     * </p>
     *
     * @param pix
     * @param w
     * @param h
     * @param radius
     * @return
     * @throws IOException
     * @date 2016年4月20日
     */
    public static int[] doBlur(int[] pix, int w, int h, int radius) throws IOException {
        int wm = w - 1;
        int hm = h - 1;
        int wh = w * h;
        int div = radius + radius + 1;
        int[] r = new int[wh];
        int[] g = new int[wh];
        int[] b = new int[wh];
        int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
        int[] vmin = new int[Math.max(w, h)];
        int divsum = (div + 1) >> 1;
        divsum *= divsum;
        int[] dv = new int[256 * divsum];
        for (i = 0; i < 256 * divsum; i++) {
            dv[i] = (i / divsum);
        }
        yw = yi = 0;
        int[][] stack = new int[div][3];
        int stackpointer;
        int stackstart;
        int[] sir;
        int rbs;
        int r1 = radius + 1;
        int routsum, goutsum, boutsum;
        int rinsum, ginsum, binsum;
        for (y = 0; y < h; y++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
            for (i = -radius; i <= radius; i++) {
                p = pix[yi + Math.min(wm, Math.max(i, 0))];
                sir = stack[i + radius];
                sir[0] = (p & 0xff0000) >> 16;
                sir[1] = (p & 0x00ff00) >> 8;
                sir[2] = (p & 0x0000ff);
                rbs = r1 - Math.abs(i);
                rsum += sir[0] * rbs;
                gsum += sir[1] * rbs;
                bsum += sir[2] * rbs;
                if (i > 0) {
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];
                } else {
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];
                }
            }
            stackpointer = radius;
            for (x = 0; x < w; x++) {
                r[yi] = dv[rsum];
                g[yi] = dv[gsum];
                b[yi] = dv[bsum];
                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;
                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];
                routsum -= sir[0];
                goutsum -= sir[1];
                boutsum -= sir[2];
                if (y == 0) {
                    vmin[x] = Math.min(x + radius + 1, wm);
                }
                p = pix[yw + vmin[x]];
                sir[0] = (p & 0xff0000) >> 16;
                sir[1] = (p & 0x00ff00) >> 8;
                sir[2] = (p & 0x0000ff);
                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];
                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;
                stackpointer = (stackpointer + 1) % div;
                sir = stack[(stackpointer) % div];
                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];
                rinsum -= sir[0];
                ginsum -= sir[1];
                binsum -= sir[2];
                yi++;
            }
            yw += w;
        }
        for (x = 0; x < w; x++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
            yp = -radius * w;
            for (i = -radius; i <= radius; i++) {
                yi = Math.max(0, yp) + x;
                sir = stack[i + radius];
                sir[0] = r[yi];
                sir[1] = g[yi];
                sir[2] = b[yi];
                rbs = r1 - Math.abs(i);
                rsum += r[yi] * rbs;
                gsum += g[yi] * rbs;
                bsum += b[yi] * rbs;
                if (i > 0) {
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];
                } else {
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];
                }
                if (i < hm) {
                    yp += w;
                }
            }
            yi = x;
            stackpointer = radius;
            for (y = 0; y < h; y++) {
                // Preserve alpha channel: ( 0xff000000 & pix[yi] )
                pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16)
                        | (dv[gsum] << 8) | dv[bsum];
                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;
                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];
                routsum -= sir[0];
                goutsum -= sir[1];
                boutsum -= sir[2];
                if (x == 0) {
                    vmin[y] = Math.min(y + r1, hm) * w;
                }
                p = x + vmin[y];
                sir[0] = r[p];
                sir[1] = g[p];
                sir[2] = b[p];
                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];
                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;
                stackpointer = (stackpointer + 1) % div;
                sir = stack[stackpointer];
                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];
                rinsum -= sir[0];
                ginsum -= sir[1];
                binsum -= sir[2];
                yi += w;
            }
        }
        return pix;
    }


    /**
     * 获取文件夹下的所有图片
     *
     * @param rootPath
     * @return 路径下的所有的图片
     */
    private static java.util.List<String> listImgs(String rootPath) {
        File f = new File(rootPath);
        if (!f.exists()) {
            System.out.println(rootPath + " not exists");
            return new ArrayList<>();
        }

        File[] fa = f.listFiles();
        java.util.List<String> images = new ArrayList<>();
        for (int i = 0; i < fa.length; i++) {
            File fs = fa[i];
            if (!fs.isDirectory() && fs.getName().endsWith("jpeg")) {
                System.out.println(fs.getName());
                images.add(fs.getName());
            }
        }
        return images;
    }
}

方法二:

<dependency>
    <groupId>com.jhlabs</groupId>
    <artifactId>filters</artifactId>
    <version>${filters.version}</version>
</dependency>
//srcImage: 待处理的图片
public static BufferedImage gaussianfilter(BufferedImage srcImage) {
    GaussianFilter filter = new GaussianFilter();
    filter.setRadius(80.0F); //设置模糊度,数字越大越模糊

    BufferedImage dstImage = new BufferedImage(srcImage.getWidth(), srcImage.getHeight(), srcImage.getType());

    //处理
    filter.filter(srcImage, dstImage);

    return dstImage; //处理后的图片
}

小插曲

插曲一

使用方法二的时候,我最开始 imageType 用的是 java.awt.image.BufferedImage#TYPE_BYTE_GRAY ,处理其他类型图片还没啥,到了处理人像图片的时候,差点没给我送走😂😂😂

下面是处理人像图片后的结果 83e6c31e1f65edb45a093ed7e8c9391.jpg

插曲二

测试过程中,发现某些图片使用 java.awt.image.BufferedImage 读取不了,原因是默写图片虽然它的后缀是jpg、png、jpeg。但是用转移工具查看文件类型你就会发现它“包藏祸心”。图片如下

src=http___pic1.win4000.com_wallpaper_2020-07-09_5f06d07dce679.jpg&refer=http___pic1.win4000(1).png 图片格式截图 image.png

格式查看器软件(我也是在网上下载的,不负责软件安全🎊🎊)c0inwuoh4o.feishu.cn/file/boxcnz…

解决方法在这里: blog.csdn.net/jf991804033…

在代码里引入以下依赖就行

<dependency>
    <groupId>org.sejda.imageio</groupId>
    <artifactId>webp-imageio</artifactId>
    <version>0.1.6</version>
</dependency>

🧨🎇🧨顺便记录下tiff格式的解决办法

原文地址blog.51cto.com/u_15152252/…

在代码里引入以下依赖就行

<dependency>
    <groupId>com.twelvemonkeys.imageio</groupId>
    <artifactId>imageio-tiff</artifactId>
    <version>3.6.4</version>
</dependency>