JAVA图像处理系列(十四)——艺术效果:波纹

艺术效果:波纹

对图像上的像素点进行位置变换,就形成图像的形变效果。因波纹按正弦或余弦方式传播,对图像进行正弦或余弦变换,可形成类似波纹传播的效果。
以下是本文实现的两种波纹的效果。第一张为原始图像,第二张为第一种算法的静态波纹效果,第三张为第一种算法生成的动态GIF图的显示效果,第四张为第二种算法的静态波纹效果,第五张为第二种算法生成的动态GIF图的显示效果。


JAVA图像处理系列(十四)——艺术效果:波纹_第1张图片
cat.jpg

JAVA图像处理系列(十四)——艺术效果:波纹_第2张图片
cat-wave.jpg

cat-wave.gif

JAVA图像处理系列(十四)——艺术效果:波纹_第3张图片
cat-ripple.jpg

JAVA图像处理系列(十四)——艺术效果:波纹_第4张图片
cat-ripple.gif

算法实现

这里直接给出两种算法的代码,感兴趣的朋友可直接通过阅读代码了解实现细节。

import java.awt.image.BufferedImage;

public class RippleEffect {
  public static final double PI=3.1415926;
  public static final double REFRACT_INDEX = 0.9;

  public static final double arc = 3.1415926/6;

  // water wave....
  public static BufferedImage waveImage(BufferedImage image, int span, int peak, int beta, int offset) {
    BufferedImage bimg = new BufferedImage(image.getWidth(),image.getHeight(),BufferedImage.TYPE_INT_RGB);

    int x_center = image.getWidth()/2;
    int y_center = image.getHeight()/2;

    double v = -Math.cos(beta*PI/180.0);
    double distance, he;
    int y_offset;

    for (int y=0; y < image.getHeight(); y++) {
      for (int x=0; x < image.getWidth(); x++) {
        distance = Math.sqrt((x-x_center)*(x-x_center) + (y-y_center)*(y-y_center)/(v*v));
        he = Math.cos((distance+offset)*PI/span)*peak;
        y_offset = (int)(he * v);
        for (int i=y_offset-2; i <= y_offset+2; i++) {
          try {
            bimg.setRGB(x, y-i, image.getRGB(x, y));
          } catch (Exception e) {

          }
        }
      }
    }

    return bimg;
  }

  // ripple ....
  public static BufferedImage rippleImage(BufferedImage image, int span, int peak, int off) {
    BufferedImage bimg = new BufferedImage(image.getWidth(),image.getHeight(),BufferedImage.TYPE_INT_RGB);

    int x_center = image.getWidth()/2;
    int y_center = image.getHeight()/2;

    boolean isWidth = x_center > y_center;
    int r = isWidth ? x_center : y_center;

    double distance, d2, he;
    double arc_ref;
    double offset;
    int x_offset;
    int y_offset;
    int x1, y1;
    double scale = x_center/(double)y_center;

    double out;

    for (int y=0; y < image.getHeight(); y++) {
      for (int x=0; x < image.getWidth(); x++) {
        x1 = x-x_center;
        y1 = y-y_center;
        d2 = Math.sqrt(x1*x1+y1*y1*scale*scale) + off;

        distance = Math.sqrt(x1*x1+y1*y1);
        offset = Math.sin(d2*PI/span)*span*(1-distance/r);

        if (x1 == 0 && y1<=0) {
          x_offset = -(int)(offset*Math.cos(PI/2.0));
          y_offset = -(int)(offset*Math.sin(PI/2.0));
        } else if (x1 == 0 && y1>0) {
          x_offset = -(int)(offset*Math.cos(PI/2.0));
          y_offset = (int)(offset*Math.sin(PI/2.0));
        } else if (x > x_center) {
          x_offset = (int)(offset*Math.cos(Math.atan(y1/(double)x1)));
          y_offset = (int)(offset*Math.sin(Math.atan(y1/(double)x1)));
        } else {
          x_offset = -(int)(offset*Math.cos(Math.atan(y1/(double)x1)));
          y_offset = -(int)(offset*Math.sin(Math.atan(y1/(double)x1)));
        }

        try {
          bimg.setRGB(x, y, image.getRGB(x-x_offset, y-y_offset));
        } catch (Exception e) {

        }
      }
    }

    return bimg;
  }
}

waveImage函数实现第一种算法,rippleImage函数实现第二种算法。

测试代码

下面是测试代码:

public class GifEffectWaveTest {

    public static void waveImage() throws IOException {
        BufferedImage img = ImageIO.read(new File("cat.jpg"));
        
        BufferedImage resultImage = RippleEffect.waveImage(img, 30, 10, 30, 36);

        ImageIO.write(resultImage, "jpeg", new File("cat-wave.jpg"));
    }
    
    public static Vector waveEffect(BufferedImage img) {
        
        Vector images = new Vector<>();
        
        PlasmaRoutine pr = new PlasmaRoutine();
        pr.create(img.getWidth(), img.getHeight());
        pr.setAlpha(30);

        for (int i = 15; i >= 0; i--) {
            BufferedImage tmpImg = RippleEffect.waveImage(img, 30, 10, 30, i * 12);
            images.add(tmpImg);
        }

        return images;
    }
    
    public static void waveImageGif() throws IOException {
        BufferedImage img = ImageIO.read(new File("cat.jpg"));
        OutputStream out = new FileOutputStream("cat-wave.gif");
                
        GifEncoder gif = new GifEncoder();
        
        if (!gif.isInit()) {
            gif.init(img.getWidth(), img.getHeight(), out, true);
            gif.setDelay(10);
        }
        
        Vector images = waveEffect(img);
        
        for (BufferedImage item : images) {
            gif.addImage(item);
        }
        
        gif.setCount(0);
        gif.encodeMultiple();
        out.close();
    }

    public static void rippleImage() throws IOException {
        BufferedImage img = ImageIO.read(new File("cat.jpg"));
        
        BufferedImage resultImage = RippleEffect.rippleImage(img, 50, 10, 30);

        ImageIO.write(resultImage, "jpeg", new File("cat-ripple.jpg"));
    }
    
    public static Vector rippleEffect(BufferedImage img) {
        
        Vector images = new Vector<>();
        
        PlasmaRoutine pr = new PlasmaRoutine();
        pr.create(img.getWidth(), img.getHeight());
        pr.setAlpha(30);

        for (int i = 8; i >= 0; i--) {
            BufferedImage tmpImg = RippleEffect.rippleImage(img, 50, 10, i * 10);
            images.add(tmpImg);
        }

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

GIF图片生成类GifEncoder请参考文章《JAVA实现GIF动画》。

你可能感兴趣的:(JAVA图像处理系列(十四)——艺术效果:波纹)