JAVA图像处理系列(十二)—— 艺术效果:雕版

艺术效果:雕版

给图像进行矩阵操作,可以实现一些有趣的效果,本文介绍类似雕版效果的实现方法,先看看实现效果。
第一张为原始图片,第二张使用固定参数时的图片,第三张为参数变化时实现的动画效果。


cat.jpg

cat-engrave.jpg

cat-engrave.gif

实现思路及方法

我们采用提取图像边缘的思路对图像进行处理,使用维度为奇数的矩阵对图像进行计算。

假设矩阵的维度为n,矩阵的取值方式为:
矩阵的中间量取值为n*n,其余量取值为-1。

例如3维矩阵为:

5维矩阵为:

对图像进行变换的代码如下:

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;

public class EngraveEffect {

    public static BufferedImage expendImage(BufferedImage image, int width) {
        BufferedImage bimg = new BufferedImage(image.getWidth() + width, image.getHeight() + width, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = bimg.createGraphics();
        g2d.drawImage(image, width/2, width/2, null);
        g2d.dispose();
        return bimg;
    }

    public static BufferedImage convolveImage(BufferedImage image, int width, float[] elements) {
        image = expendImage(image, width);
        Kernel kernel = new Kernel(width, width, elements);
        ConvolveOp cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
        BufferedImage bimg = cop.filter(image, null);
        return expendImage(bimg, -width);
    }

    public static BufferedImage engraveImage(BufferedImage image, double radius) {
        int width = (int)(Math.ceil(radius*2)) + 1;
        if (width < 3) width = 3;

        BufferedImage bimg;

        float[] kernel = new float[width * width];
        for (int i = 0; i < width * width; i++) {
            kernel[i] = -1.0f;
        }

        kernel[width * width / 2] = width * width - 1.0f;
        bimg = convolveImage(image, width, kernel);

        return bimg;
    }
}

测试

采用如下代码进行测试,可实现本文中实现的效果。

public class GifEffectEngraveTest {

    public static void engraveImage() throws IOException {
        BufferedImage img = ImageIO.read(new File("cat.jpg"));

        BufferedImage img2 = EngraveEffect.engraveImage(img, 5);
        ImageIO.write(img2, "jpeg", new File("cat-engrave.jpg"));
    }

    public static Vector engraveEffect(BufferedImage img) {
        Vector images = new Vector<>();
        
        for (int i = 1; i < 20; i+=2) {
            BufferedImage tmpImg = EngraveEffect.engraveImage(img, i);
            images.add(tmpImg);
        }

        return images;
    }
    
    public static void engraveImageGif() throws IOException {
        BufferedImage img = ImageIO.read(new File("cat.jpg"));
        OutputStream out = new FileOutputStream("cat-engrave.gif");
                
        GifEncoder gif = new GifEncoder();
        if (!gif.isInit()) {
            gif.init(img.getWidth(), img.getHeight(), out, true);
            gif.setDelay(100);
        }
        
        Vector images = engraveEffect(img);
        
        for (BufferedImage item : images) {
            gif.addImage(item);
        }
        
        gif.setCount(0);
        gif.encodeMultiple();
        out.close();
    }
    
    public static void main(String[] argv) throws IOException {
        engraveImage();
        engraveImageGif();
    }
}

其中engraveImage使用半径为5的矩阵进行计算的实现效果,engraveImageGif实现参数由1到20进行渐变计算叠加生成的动态GIF图片。GIF图片生成类GifEncoder请参考文章《JAVA实现GIF动画》

你可能感兴趣的:(JAVA图像处理系列(十二)—— 艺术效果:雕版)