zoukankan      html  css  js  c++  java
  • 图像处理------移动模糊 分类: 视频图像处理 2015-07-24 09:33 26人阅读 评论(0) 收藏

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

    是移动模糊特效也是基于卷积,相比于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值的代码如下:

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

     计算距离半径代码如下:

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

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

     

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

    完成Scale的代码如下:

    1. // scale the pixels  
    2. float scale = 1-zoom*f;  
    3. m11 = cx - cx*scale;  
    4. m22 = cy - cy*scale;  
    5. newY = (int)(newY * scale +m22);  
    6. newX = (int)(newX * scale + m11);  

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

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

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

    1. ta = clamp((int)(ta/count));  
    2. tr = clamp((int)(tr/count));  
    3. tg = clamp((int)(tg/count));  
    4. tb = clamp((int)(tb/count));  
    5. outPixels[index] = (ta << 24) | (tr<< 16) | (tg << 8) | tb;  

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

    1. package com.gloomyfish.process.blur.study;  
    2.   
    3. import java.awt.image.BufferedImage;  
    4.   
    5. public class MotionFilter {  
    6.   
    7.     private float distance = 0;// default;  
    8.     private float onePI = (float)Math.PI;  
    9.     private float angle = 0.0f;  
    10.     private float zoom = 0.4f;  
    11.   
    12.     public float getDistance() {  
    13.         return distance;  
    14.     }  
    15.   
    16.     public void setDistance(float distance) {  
    17.         this.distance = distance;  
    18.     }  
    19.   
    20.     public float getAngle() {  
    21.         return angle;  
    22.     }  
    23.   
    24.     public void setAngle(float angle) {  
    25.         this.angle = angle;  
    26.     }  
    27.   
    28.     public BufferedImage filter(BufferedImage src, BufferedImage dst) {  
    29.         int width = src.getWidth();  
    30.         int height = src.getHeight();  
    31.   
    32.         if ( dst == null )  
    33.             dst = createCompatibleDestImage( src, null );  
    34.   
    35.         int[] inPixels = new int[width*height];  
    36.         int[] outPixels = new int[width*height];  
    37.         getRGB( src, 00, width, height, inPixels );  
    38.         int index = 0;  
    39.         int cx = width/2;  
    40.         int cy = height/2;  
    41.           
    42.         // calculate the triangle geometry value  
    43.         float sinAngle = (float)Math.sin(angle/180.0f * onePI);  
    44.         float coseAngle = (float)Math.cos(angle/180.0f * onePI);  
    45.           
    46.         // calculate the distance, same as box blur  
    47.         float imageRadius = (float)Math.sqrt(cx*cx + cy*cy);  
    48.         float maxDistance = distance + imageRadius * zoom;  
    49.           
    50.         int iteration = (int)maxDistance;  
    51.         for(int row=0; row<height; row++) {  
    52.             int ta = 0, tr = 0, tg = 0, tb = 0;  
    53.             for(int col=0; col<width; col++) {  
    54.                 int newX= col, count = 0;  
    55.                 int newY = row;  
    56.                   
    57.                 // iterate the source pixels according to distance  
    58.                 float m11 = 0.0f, m22 = 0.0f;  
    59.                 for(int i=0; i<iteration; i++) {  
    60.                     newX = col;  
    61.                     newY = row;  
    62.                       
    63.                     // calculate the operator source pixel  
    64.                     if(distance > 0) {  
    65.                         newY = (int)Math.floor((newY + i*sinAngle));  
    66.                         newX = (int)Math.floor((newX + i*coseAngle));  
    67.                     }  
    68.                     float f = (float)i/iteration;  
    69.                     if (newX < 0 || newX >= width) {  
    70.                         break;  
    71.                     }  
    72.                     if (newY < 0 || newY >= height) {  
    73.                         break;  
    74.                     }  
    75.                       
    76.                     // scale the pixels  
    77.                     float scale = 1-zoom*f;  
    78.                     m11 = cx - cx*scale;  
    79.                     m22 = cy - cy*scale;  
    80.                     newY = (int)(newY * scale + m22);  
    81.                     newX = (int)(newX * scale + m11);  
    82.                       
    83.                     // blur the pixels, here  
    84.                     count++;  
    85.                     int rgb = inPixels[newY*width+newX];  
    86.                     ta += (rgb >> 24) & 0xff;  
    87.                     tr += (rgb >> 16) & 0xff;  
    88.                     tg += (rgb >> 8) & 0xff;  
    89.                     tb += rgb & 0xff;  
    90.                 }  
    91.                   
    92.                 // fill the destination pixel with final RGB value  
    93.                 if (count == 0) {  
    94.                     outPixels[index] = inPixels[index];  
    95.                 } else {  
    96.                     ta = clamp((int)(ta/count));  
    97.                     tr = clamp((int)(tr/count));  
    98.                     tg = clamp((int)(tg/count));  
    99.                     tb = clamp((int)(tb/count));  
    100.                     outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;  
    101.                 }  
    102.                 index++;  
    103.             }  
    104.         }  
    105.   
    106.         setRGB( dst, 00, width, height, outPixels );  
    107.         return dst;  
    108.     }  
    109.       
    110.     public int clamp(int c) {  
    111.         if (c < 0)  
    112.             return 0;  
    113.         if (c > 255)  
    114.             return 255;  
    115.         return c;  
    116.     }  
    117.   
    118. }  

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    象棋中马的遍历
    字符串压缩
    寻找丑数
    Educoder
    Educoder
    以太坊:EVM的存储结构
    以太坊:EVM执行字节码的过程
    以太坊:底层序列化编码方式RLP
    以太坊:在合约里调用指定地址的另一已部署合约
    以太坊:创建合约
  • 原文地址:https://www.cnblogs.com/mao0504/p/4706373.html
Copyright © 2011-2022 走看看