图像处理之移动模糊

简介: 图像处理之移动模糊

                                                         - created by gloomyfish


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


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


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


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


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


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


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


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

0_1329056684jZ8c.png


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


设中心点坐标为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 时:

0_1329056751qGQk.png

 

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


0_1329056845gHyA.png

放缩模糊效果:

0_1329056902Tz3y.png


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

0_1329056940Cai2.png


关键代码解释:


计算三角几何角度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;
  }
 
}

后记:本滤镜的基点即中心像素,是可以调整的。 感兴趣的可以自己完成,转载文章请务必注明出自本博客

相关文章
|
23天前
|
算法 Java 计算机视觉
图像处理之基于NCC模板匹配识别
图像处理之基于NCC模板匹配识别
23 2
|
24天前
|
资源调度 计算机视觉
图像处理之图像加噪
图像处理之图像加噪
9 0
图像处理之图像加噪
|
1天前
|
并行计算 算法 Java
尺度函数在图像处理中的应用与优化
尺度函数在图像处理中的应用与优化
|
24天前
|
算法 计算机视觉
图像处理之基于像素的图像混合
图像处理之基于像素的图像混合
12 1
|
24天前
|
机器学习/深度学习 资源调度 算法
图像处理之高斯模糊
图像处理之高斯模糊
22 0
|
23天前
|
算法 计算机视觉
图像处理之USM锐化
图像处理之USM锐化
8 0
|
24天前
|
算法 计算机视觉
图像处理之基于阈值模糊
图像处理之基于阈值模糊
11 0
|
24天前
|
计算机视觉
图像处理之常见二值化方法汇总
图像处理之常见二值化方法汇总
12 0
|
1月前
|
计算机视觉
OpenCV图像运动模糊
OpenCV图像运动模糊
36 0
|
1月前
|
算法 计算机视觉
LabVIEW使用图像处理检测显微图像中的白血病
LabVIEW使用图像处理检测显微图像中的白血病
21 0