图像处理之移动模糊
来源:互联网 发布:手机淘宝pc端在哪里 编辑:程序博客网 时间:2024/05/16 16:24
- created by gloomyfish
卷积模糊或者卷积平滑滤波,可以消除图像噪声,也可以产生一些常见的图像模糊特效,但
是移动模糊特效也是基于卷积,相比于Box Blur, Gaussian Blur的算法,移动模糊只需要完成
一次的一维卷积,所不同的是一维卷积的完成,要基于一定的角度,而不是只是在水平和垂
直两个方向上。移动模糊的一维卷积要考虑一下三个因素:
a. 操作数的多少 - 即距离(Distance)
b.一维操作数在像素数组中的移动方向 – 即角度(Angle)
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
原理部分的解释大概如此,下面来看一下,实际图像处理效果和源代码详细解释。
程序运行效果如下– 距离50个像素,角度 0 时:
角度30时候的滤镜运行结果:
放缩模糊效果:
角度,距离,放缩三个参数综合效果:
关键代码解释:
计算三角几何角度sin与cos值的代码如下:
// calculate the trianglegeometry valuefloat sinAngle = (float)Math.sin(angle/180.0f * onePI);float coseAngle = (float)Math.cos(angle/180.0f * onePI);
计算距离半径代码如下:
// calculate the distance,same as box blurfloat imageRadius = (float)Math.sqrt(cx*cx + cy*cy);float maxDistance = distance + imageRadius * zoom;
计算操作数像素坐标的代码如下:
// calculate the operatorsource pixelif(distance > 0) {newY = (int)Math.floor((newY+ i*sinAngle));newX = (int)Math.floor((newX + i*coseAngle));}
完成Scale的代码如下:
// scale the pixelsfloat 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, herecount++;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 pixelsfloat 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, herecount++;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;}}后记:本滤镜的基点即中心像素,是可以调整的。 感兴趣的可以自己完成,转载文章请务必注明出自本博客
- 图像处理之移动模糊
- 图像处理之移动模糊
- 图像处理------移动模糊
- 图像处理之模糊理论
- 图像处理之高斯模糊
- 图像处理之基于阈值模糊
- 图像处理之基于一维高斯快速模糊
- android图片处理之图像模糊
- android图片处理之图像模糊
- android图片处理之图像模糊
- 图像处理之基于一维高斯快速模糊
- 图像处理之高斯模糊
- 图像处理之基于阈值模糊
- Delphi图像处理 -- 模糊
- android 图像模糊处理
- Android 图像模糊处理
- 图像模糊处理RenderScript
- 图像模糊处理
- STL 什么时候用哪种容器
- java 多线程拷贝copy 复制
- 让工作变得高效而简单的10种方法
- C#实现 类似 qq、 msn 的 任务栏通知窗口
- .Net一些基本语言特性(一)
- 图像处理之移动模糊
- CUnit开发环境搭建过程可能遇到的一些问题及解决方法
- 强化语言意识,优化自己的语言
- 小波变换网文精粹:小波:看森林,也看树木(一)
- 不能转换void (_thiscall CMainFrame::*)(void)to LRESULT (__thiscall CWn...
- 普林斯顿大学为何拒录4000名全A学生
- JQuery插件第二十二个:键值对字符串操作类
- SSI(Struts2, Spring, iBatis)框架整合小结
- 并查集——HDOJ 1272