图像处理之玻璃水印特效(祝大家圣诞节快乐)

时间:2023-02-04 16:06:11

from:http://blog.csdn.net/jia20003/article/details/13159535


Water Ripple Effect - 水波纹效果

一:原理

模拟水波纹效果,最常见的是sine或者cosn的函数,周期性变化,贴近自然

当水波纹中中间开始向四周扩散的时候,一般都是慢慢的失去能量,振幅也是

越来越小,所以程序要模拟这个过程时候,要加上一个能量递减因子。然后用

公式 y = a*sine(bx + c)来表示波纹公式。

二:程序实现

最重要的一步是计算水波纹的振幅。在任意一点确定水波的中心位置,可以是

鼠标随机选取,对半径范围内的像素位置实现水波生成,然后转换为位置,对

位置实现浮点数取整,然后使用适当的插值算法,本例使用双线性插值。

三:程序效果

图像处理之玻璃水印特效(祝大家圣诞节快乐)

四:滤镜完全源代码,这次我写了些中文注解,不给源代码的博文不是好博文

  1. package com.gloomyfish.filter.study;  
  2.   
  3. import java.awt.image.BufferedImage;  
  4.   
  5. public class WaterFilter extends AbstractBufferedImageOp {  
  6.     private float wavelength = 16;  
  7.     private float amplitude = 10;  
  8.     private float phase = 0;  
  9.     private float centreX = 0.5f;  
  10.     private float centreY = 0.5f;  
  11.     private float radius = 50;  
  12.   
  13.     private float radius2 = 0;  
  14.     private float icentreX;  
  15.     private float icentreY;  
  16.       
  17.     public WaterFilter() {  
  18.   
  19.     }  
  20.   
  21.     @Override  
  22.     public BufferedImage filter(BufferedImage src, BufferedImage dest) {  
  23.         int width = src.getWidth();  
  24.         int height = src.getHeight();  
  25.   
  26.         if ( dest == null )  
  27.             dest = createCompatibleDestImage( src, null );  
  28.   
  29.         int[] inPixels = new int[width*height];  
  30.         int[] outPixels = new int[width*height];  
  31.         getRGB( src, 00, width, height, inPixels );  
  32.         icentreX = width * centreX;  
  33.         icentreY = height * centreY;  
  34.         if ( radius == 0 )  
  35.             radius = Math.min(icentreX, icentreY);  
  36.         radius2 = radius*radius;  
  37.         int index = 0;  
  38.         float[] out = new float[2];  
  39.         for(int row=0; row<height; row++) {  
  40.             for(int col=0; col<width; col++) {  
  41.                 index = row * width + col;  
  42.                   
  43.                 // 获取水波的扩散位置,最重要的一步  
  44.                 generateWaterRipples(col, row, out);  
  45.                 int srcX = (int)Math.floor( out[0] );  
  46.                 int srcY = (int)Math.floor( out[1] );  
  47.                 float xWeight = out[0]-srcX;  
  48.                 float yWeight = out[1]-srcY;  
  49.                 int nw, ne, sw, se;  
  50.                   
  51.                 // 获取周围四个像素,插值用,  
  52.                 if ( srcX >= 0 && srcX < width-1 && srcY >= 0 && srcY < height-1) {  
  53.                     // Easy case, all corners are in the image  
  54.                     int i = width*srcY + srcX;  
  55.                     nw = inPixels[i];  
  56.                     ne = inPixels[i+1];  
  57.                     sw = inPixels[i+width];  
  58.                     se = inPixels[i+width+1];  
  59.                 } else {  
  60.                     // Some of the corners are off the image  
  61.                     nw = getPixel( inPixels, srcX, srcY, width, height );  
  62.                     ne = getPixel( inPixels, srcX+1, srcY, width, height );  
  63.                     sw = getPixel( inPixels, srcX, srcY+1, width, height );  
  64.                     se = getPixel( inPixels, srcX+1, srcY+1, width, height );  
  65.                 }  
  66.                   
  67.                 // 取得对应的振幅位置P(x, y)的像素,使用双线性插值  
  68.                 /*if(xWeight >=0 || yWeight >= 0) 
  69.                 { 
  70.                     outPixels[index] = ImageMath.bilinearInterpolate(xWeight, yWeight, nw, ne, sw, se);                  
  71.                 } 
  72.                 else  
  73.                 { 
  74.                     outPixels[index] = inPixels[index]; 
  75.                 }*/  
  76.                 outPixels[index] = ImageMath.bilinearInterpolate(xWeight, yWeight, nw, ne, sw, se);  
  77.             }  
  78.         }  
  79.   
  80.         setRGB( dest, 00, width, height, outPixels );  
  81.         return dest;  
  82.     }  
  83.   
  84.     private int getPixel(int[] pixels, int x, int y, int width, int height) {  
  85.         if (x < 0 || x >= width || y < 0 || y >= height) {  
  86.             return 0// 有点暴力啦,懒得管啦  
  87.         }  
  88.         return pixels[ y*width+x ];  
  89.     }  
  90.   
  91.     protected void generateWaterRipples(int x, int y, float[] out) {  
  92.         float dx = x-icentreX;  
  93.         float dy = y-icentreY;  
  94.         float distance2 = dx*dx + dy*dy;  
  95.         // 确定 water ripple的半径,如果在半径之外,就直接获取原来位置,不用计算迁移量  
  96.         if (distance2 > radius2) {   
  97.             out[0] = x;  
  98.             out[1] = y;  
  99.         } else {  
  100.             // 如果在radius半径之内,计算出来  
  101.             float distance = (float)Math.sqrt(distance2);  
  102.             // 计算改点振幅  
  103.             float amount = amplitude * (float)Math.sin(distance / wavelength * ImageMath.TWO_PI - phase);  
  104.             // 计算能量损失,   
  105.             amount *= (radius-distance)/radius; // 计算能量损失,  
  106.             if ( distance != 0 )  
  107.                 amount *= wavelength/distance;  
  108.             // 得到water ripple 最终迁移位置  
  109.             out[0] = x + dx*amount;  
  110.             out[1] = y + dy*amount;  
  111.         }  
  112.     }  
  113.       
  114. }  

觉得不错请顶一下,谢谢!

转载请务必注明出处!谢谢!