使用哈尔小波变换实现模糊图像的功能

参考了网上别人的代码,实现了图像的哈尔小波变换,可以实现模糊图像的功能,另外将轮廓合并起来可以实现类似粉笔画的功能。

import org.junit.Test;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 哈尔小波变换
 * 参考:https://blog.csdn.net/baidu_21578557/article/details/51988006
 * https://blog.csdn.net/kezunhai/article/details/47080977
 */
public class HaarTransform {

    @Test
    public void test() throws IOException {
        String fromPic = "C:\\Users\\Dell\\Pictures\\QQ截图20210628085926.jpg";
        BufferedImage bufferedImage = ImageIO.read(new File(fromPic));

        // 进行哈尔小波变换,可以实现模糊图片的功能
        //BufferedImage destImg = haarWavelet(bufferedImage, 32, 2);

        // 通过哈尔小波变换获取图像轮廓
        BufferedImage destImg = haarWaveletEdge(bufferedImage, 32, 2);
        // 将横向,纵向和斜向轮廓叠加,可以实现粉笔画的功能
        BufferedImage mergedImg = mergeHaarWavelet(destImg);

        File newFile = new File("d:\\test8.jpg");
        ImageIO.write(mergedImg, "jpg", newFile);
    }

    /**
     * 哈尔小波变换
     * 作用:模糊图像
     * @param srcImage
     * @param range 2的整数倍,如果为1,就是原图像
     * @param difference 过滤阈值,越大图片越模糊,相邻两个像素间的差值
     * @return
     */
    public BufferedImage haarWavelet(BufferedImage srcImage, int range, double difference) {
        int iw = srcImage.getWidth();
        int ih = srcImage.getHeight();
        int[] pixels = new int[iw * ih];
        srcImage.getRGB(0, 0, iw, ih, pixels, 0, iw);

        // 赋初值
        int w = 1;
        int h = 1;
        // 计算进行付立叶变换的宽度和高度(2的整数次方)
        while (w * 2 <= iw) {
            w *= 2;
        }
        while (h * 2 <= ih) {
            h *= 2;
        }

        // 存储哈尔小波变换结果
        double[][] haar = new double[h][w];

        // 输出图像
        int[] newPixels = new int[h * w];

        // 对行进行haar小波变换
        for (int i = 0; i < h; i++) {
            // 获取一行输入图像
            double row[] = new double[w];
            for (int j = 0; j < w; j++) {
                row[j] = pixels[i * iw + j] & 0xff;
            }

            haarTransform(row);
            haar[i] = row;
        }

        // 对列进行haar小波变换
        for (int i = 0; i < w; i++) {
            // 获取一列输入图像
            double[] col = new double[h];
            for (int j = 0; j < h; j++) {
                col[j] = haar[j][i];
            }

            haarTransform(col);

            for (int j = 0; j < h; j++) {
                haar[j][i] = col[j];
            }
        }

        // 统计
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                int key = (int)Math.abs(haar[i][j]);
                if(map.containsKey(key)) {
                    map.put(key, map.get(key) + 1);
                } else {
                    map.put(key, 1);
                }
            }
        }

        for(Map.Entry<Integer, Integer> item : map.entrySet()) {
            System.out.println(item.getKey() + ", " + item.getValue());

        }

        // 进行过滤
        for (int i = h/range; i < h; i++) {
            for (int j = w/range; j < w; j++) {
                if (Math.abs(haar[i][j]) < difference) {
                    haar[i][j] = 0;
                }
            }
        }

        // 还原为图像
        // 先对列进行还原
        for (int i = 0; i < w; i++) {
            // 获取一列输入图像
            double col[] = new double[h];
            for (int j = 0; j < h; j++) {
                col[j] = haar[j][i];
            }
            iHaarTransform(col);
            for (int j = 0; j < h; j++) {
                haar[j][i] = col[j];
            }
        }

        // 再对行进行还原
        for (int i = 0; i < h; i++) {
            // 获取一行输入图像
            double row[] = new double[w];
            for (int j = 0; j < w; j++) {
                row[j] = haar[i][j];
            }
            iHaarTransform(row);
            haar[i] = row;
        }

        // 生成像素
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                int temp = (int)haar[i][j];
                newPixels[i * w + j] = (clamp(temp) << 16) | (clamp(temp) << 8) | clamp(temp);
            }
        }

        BufferedImage destImg = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
        destImg.setRGB(0, 0, w, h, newPixels, 0, w);

        return destImg;
    }

    /**
     * 提取横向,纵向,斜向的边界
     * @param srcImage
     * @param range
     * @param difference
     * @return
     */
    public BufferedImage haarWaveletEdge(BufferedImage srcImage, int range, double difference) {
        int iw = srcImage.getWidth();
        int ih = srcImage.getHeight();
        int[] pixels = new int[iw * ih];
        srcImage.getRGB(0, 0, iw, ih, pixels, 0, iw);

        // 赋初值
        int w = 1;
        int h = 1;
        // 计算进行付立叶变换的宽度和高度(2的整数次方)
        while (w * 2 <= iw) {
            w *= 2;
        }
        while (h * 2 <= ih) {
            h *= 2;
        }

        // 存储哈尔小波变换结果
        double[][] haar = new double[h][w];

        // 输出图像
        int[] newPixels = new int[h * w];

        // 对行进行haar小波变换
        for (int i = 0; i < h; i++) {
            // 获取一行输入图像
            double row[] = new double[w];
            for (int j = 0; j < w; j++) {
                row[j] = pixels[i * iw + j] & 0xff;
            }

            haarTransform2(row);
            haar[i] = row;
        }

        // 对列进行haar小波变换
        for (int i = 0; i < w; i++) {
            // 获取一列输入图像
            double[] col = new double[h];
            for (int j = 0; j < h; j++) {
                col[j] = haar[j][i];
            }

            haarTransform2(col);

            for (int j = 0; j < h; j++) {
                haar[j][i] = col[j];
            }
        }

        // 生成像素
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                int temp = (int) Math.abs(haar[i][j]);
                if (i > h / 2 || j > w / 2) {
                    //temp += 180;
                    temp += 60;
                }
                newPixels[i * w + j] = (clamp(temp) << 16) | (clamp(temp) << 8) | clamp(temp);
            }
        }

        BufferedImage destImg = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
        destImg.setRGB(0, 0, w, h, newPixels, 0, w);

        return destImg;
    }

    /**
     * 将横向,纵向,斜向的边界线进行合并
     * 素描效果
     * @param srcImage
     * @return
     */
    public BufferedImage mergeHaarWavelet(BufferedImage srcImage) {
        int w = srcImage.getWidth();
        int h = srcImage.getHeight();
        int[] pixels = new int[w * h];
        srcImage.getRGB(0, 0, w, h, pixels, 0, w);

        // 输出图像
        int[] newPixels = new int[w * h / 4];

        // 生成像素
        for (int i = h/2; i < h; i++) {
            for (int j = w/2; j < w; j++) {
                int rowPixel = pixels[(i - h/2) * w + j] & 0xff;
                int colPixel = pixels[i * w + (j - w/2)] & 0xff;
                int obliquePixel = pixels[i * w + j] & 0xff;
                int temp = rowPixel + colPixel + obliquePixel;
                newPixels[(i - h/2) * w / 2 + (j - w/2)] = (clamp(temp) << 16) | (clamp(temp) << 8) | clamp(temp);
            }
        }

        BufferedImage destImg = new BufferedImage(w/2, h/2, BufferedImage.TYPE_BYTE_GRAY);
        destImg.setRGB(0, 0, w/2, h/2, newPixels, 0, w/2);

        return destImg;
    }

    /**
     * 哈尔小波变换,一直变换到只剩一个像素点
     * @param src
     */
    public void haarTransform(double[] src) {
        int n = src.length;
        // 缩小到一个像素
        while (n > 1) {
            double[] dest = new double[n];
            for (int i=0; i<n / 2; i++) {
                double a = src[2*i];
                double b = src[2*i+1];
                dest[i] = (a + b) / 2;
                dest[i + n/2] = (a - b) / 2;
            }
            System.arraycopy(dest, 0, src, 0, n);
            n /= 2;
        }
    }

    /**
     * 哈尔小波变换,只变换一次
     * @param src
     */
    public void haarTransform2(double[] src) {
        int n = src.length;
        // 缩小到一个像素
        while (n > 1) {
            double[] dest = new double[n];
            for (int i=0; i<n / 2; i++) {
                double a = src[2*i];
                double b = src[2*i+1];
                dest[i] = (a + b) / 2;
                dest[i + n/2] = (a - b) / 2;
            }
            System.arraycopy(dest, 0, src, 0, n);
            n /= 2;

            break;
        }
    }

    /**
     * 哈尔小波变换逆变换
     * @param src
     */
    public void iHaarTransform(double[] src) {
        int n = 1;
        // 缩小到一个像素
        while (n < src.length) {
            double[] dest = new double[n*2];
            for (int i=0; i<n; i++) {
                double a = src[i];
                double b = src[i+n];
                dest[2*i] = (a + b);
                dest[2*i + 1] = (a - b);
            }
            System.arraycopy(dest, 0, src, 0, n*2);
            n *= 2;
        }
    }

    /**
     * 如果像素点的值超过了0-255的范围,予以调整
     *
     * @param value 输入值
     * @return 输出值
     */
    private int clamp(int value) {
        return value > 255 ? 255 : (Math.max(value, 0));
    }

    /**
     * 哈尔小波变换
     */
    @Test
    public void transform() {
        double[] src = new double[]{64,2,3,61,60,6,7,57};
        int n = src.length;
        // 缩小到一个像素
        while (n > 1) {
            double[] dest = new double[n];
            for (int i=0; i<n / 2; i++) {
                double a = src[2*i];
                double b = src[2*i+1];
                dest[i] = (a + b) / 2;
                dest[i + n/2] = (a - b) / 2;
            }
            System.arraycopy(dest, 0, src, 0, n);
            n /= 2;
        }

        for (double item : src) {
            System.out.print(item + ",");
        }
    }

    /**
     * 哈尔小波变换逆变换
     */
    @Test
    public void itransform() {
        double[] src = new double[]{32.5,0.0,0.5,0.5,31.0,-29.0,27.0,-25.0};
        int n = 1;
        // 缩小到一个像素
        while (n < src.length) {
            double[] dest = new double[n*2];
            for (int i=0; i<n; i++) {
                double a = src[i];
                double b = src[i+n];
                dest[2*i] = (a + b);
                dest[2*i + 1] = (a - b);
            }
            System.arraycopy(dest, 0, src, 0, n*2);
            n *= 2;
        }

        for (double item : src) {
            System.out.print(item + ",");
        }
    }

}

效果图

在这里插入图片描述

参考

Haar小波变换
哈尔小波变换实例讲解

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值