图像处理之移动模糊

                                                          - created by gloomyfish

卷积模糊或者卷积平滑滤波,可以消除图像噪声,也可以产生一些常见的图像模糊特效,但

是移动模糊特效也是基于卷积,相比于Box Blur, Gaussian Blur的算法,移动模糊只需要完成

一次的一维卷积,所不同的是一维卷积的完成,要基于一定的角度,而不是只是在水平和垂

直两个方向上。移动模糊的一维卷积要考虑一下三个因素:

                     a. 操作数的多少 - 即距离(Distance)

                     b.一维操作数在像素数组中的移动方向 �C 即角度(Angle)

                     c.一维操作数的拉影效应 �C 即Scale(放大和缩小程度)(Zoom/Scale)

距离和角度的关系可以用三角几何表示如下:


假设距离和角度已知的情知道中心点(目标像素点)则可以求出每个操作数的像素点坐标,假

设中心点坐标为Base(x0, y0) 则操作数P(a, b)坐标公式可以表示如下:

             a = sinx * c +y0

             b = cosx * c +x0

放缩功能其实是在XY两个方向对图像计算得到一个一维像素结合,再求这些像素的平均值

即可,假设中心点像素为x0, y0, 防缩比率为s0则每个操作数像素点坐标可以表示为:

         a= x0-x0 * s0 + a

         b= y0-y0*so + b

 

原理部分的解释大概如此,下面来看一下,实际图像处理效果和源代码详细解释。

程序运行效果如下�C 距离50个像素,角度 0 时:

 

角度30时候的滤镜运行结果:


放缩模糊效果:


角度,距离,放缩三个参数综合效果:


关键代码解释:

计算三角几何角度sin与cos值的代码如下:

// calculate the trianglegeometry value float sinAngle = (float)Math.sin(angle/180.0f * onePI); float coseAngle = (float)Math.cos(angle/180.0f * onePI);

 计算距离半径代码如下:

// calculate the distance,same as box blur float imageRadius = (float)Math.sqrt(cx*cx + cy*cy); float maxDistance = distance + imageRadius * zoom;

计算操作数像素坐标的代码如下:

 

// calculate the operatorsource pixel if(distance > 0) { newY = (int)Math.floor((newY+ i*sinAngle)); newX = (int)Math.floor((newX + i*coseAngle)); }

完成Scale的代码如下:

// scale the pixels float scale = 1-zoom*f; m11 = cx - cx*scale; m22 = cy - cy*scale; newY = (int)(newY * scale +m22); newX = (int)(newX * scale + m11);

求取像素平均值,完成一维卷积的代码如下:

// blur the pixels, here count++; int rgb= inPixels[newY*width+newX]; ta += (rgb >> 24) & 0xff; tr += (rgb >> 16) & 0xff; tg += (rgb >> 8) & 0xff; tb += rgb & 0xff;

重新填充目标像素的代码如下:

ta = clamp((int)(ta/count)); tr = clamp((int)(tr/count)); tg = clamp((int)(tg/count)); tb = clamp((int)(tb/count)); outPixels[index] = (ta << 24) | (tr<< 16) | (tg << 8) | tb;

移动模糊算法的完全源代码如下(不包含测试代码):

package com.gloomyfish.process.blur.study;  import java.awt.image.BufferedImage;  public class MotionFilter {  	private float distance = 0;// default; 	private float onePI = (float)Math.PI; 	private float angle = 0.0f; 	private float zoom = 0.4f;  	public float getDistance() { 		return distance; 	}  	public void setDistance(float distance) { 		this.distance = distance; 	}  	public float getAngle() { 		return angle; 	}  	public void setAngle(float angle) { 		this.angle = angle; 	}  	public BufferedImage filter(BufferedImage src, BufferedImage dst) { 		int width = src.getWidth();         int height = src.getHeight();          if ( dst == null )             dst = createCompatibleDestImage( src, null );          int[] inPixels = new int[width*height];         int[] outPixels = new int[width*height];         getRGB( src, 0, 0, width, height, inPixels );         int index = 0;         int cx = width/2;         int cy = height/2;                  // calculate the triangle geometry value         float sinAngle = (float)Math.sin(angle/180.0f * onePI);         float coseAngle = (float)Math.cos(angle/180.0f * onePI);                  // calculate the distance, same as box blur         float imageRadius = (float)Math.sqrt(cx*cx + cy*cy);         float maxDistance = distance + imageRadius * zoom;                  int iteration = (int)maxDistance;         for(int row=0; row<height; row++) {         	int ta = 0, tr = 0, tg = 0, tb = 0;         	for(int col=0; col<width; col++) {         		int newX= col, count = 0;         		int newY = row;         		         		// iterate the source pixels according to distance         		float m11 = 0.0f, m22 = 0.0f;         		for(int i=0; i<iteration; i++) {         			newX = col;         			newY = row;         			         			// calculate the operator source pixel         			if(distance > 0) { 	        			newY = (int)Math.floor((newY + i*sinAngle)); 	        			newX = (int)Math.floor((newX + i*coseAngle));         			}         			float f = (float)i/iteration;         			if (newX < 0 || newX >= width) {         				break; 					} 					if (newY < 0 || newY >= height) { 						break; 					} 					 					// scale the pixels 					float scale = 1-zoom*f; 					m11 = cx - cx*scale; 					m22 = cy - cy*scale; 					newY = (int)(newY * scale + m22); 					newX = (int)(newX * scale + m11); 					 					// blur the pixels, here 					count++; 					int rgb = inPixels[newY*width+newX]; 					ta += (rgb >> 24) & 0xff; 					tr += (rgb >> 16) & 0xff; 					tg += (rgb >> 8) & 0xff; 					tb += rgb & 0xff;         		}         		         		// fill the destination pixel with final RGB value         		if (count == 0) { 					outPixels[index] = inPixels[index]; 				} else { 					ta = clamp((int)(ta/count)); 					tr = clamp((int)(tr/count)); 					tg = clamp((int)(tg/count)); 					tb = clamp((int)(tb/count)); 					outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb; 				} 				index++;         	}         }          setRGB( dst, 0, 0, width, height, outPixels );         return dst; 	} 	 	public int clamp(int c) { 		if (c < 0) 			return 0; 		if (c > 255) 			return 255; 		return c; 	}  }
后记:本滤镜的基点即中心像素,是可以调整的。 感兴趣的可以自己完成,转载文章请务必注明出自本博客

你可能感兴趣的:(算法,null,float,DST,图像处理,distance)