美文网首页
Android图片纵向(竖直)模糊算法

Android图片纵向(竖直)模糊算法

作者: rome753 | 来源:发表于2019-05-05 21:38 被阅读0次

    高斯模糊是用得最广泛的图像模糊算法,它的原理很简单,对每个点计算它周围其他点的平均色值,设置到该点上,就是模糊后的图。取周围其他点的范围称为模糊半径,模糊半径越大也就越模糊。高斯模糊算法网上很多,可以参考这个:
    http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html

    然而最近项目需要图片在竖直方向上模糊,网上找了一下没有发现相应算法,于是自己写了一个。原理跟高斯模糊相似,由于只有一个方向,比高斯模糊少了一个维度,因此简单很多:

    1. 把图像Bitmap每一列的像素的ARGB(透明度和红绿蓝)值取出来
    2. 透明度不变,红绿蓝值分别根据模糊半径,跟竖直方向上相邻的点算平均值
    3. 将计算后的ARGB值合成新的像素,创建新的Bitmap
    public static Bitmap verticalBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {
            Bitmap bitmap;
            if (canReuseInBitmap) {
                bitmap = sentBitmap;
            } else {
                bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
            }
    
            int w = bitmap.getWidth();
            int h = bitmap.getHeight();
            int hm = h - 1;
            if (radius < 1) return bitmap;
            if(radius > hm / 2) radius = hm / 2;
    
            int[] pix = new int[w * h];
            bitmap.getPixels(pix, 0, w, 0, 0, w, h);
    
    
            int[] a = new int[h];
            int[] r = new int[h];
            int[] g = new int[h];
            int[] b = new int[h];
    
            for(int i = 0; i < w; i++) {
                a[0] = pix[i] & 0xff000000;
                r[0] = pix[i] >> 16 & 0x000000ff;
                g[0] = pix[i] >> 8 & 0x000000ff;
                b[0] = pix[i] & 0x000000ff;
                for(int j = 1; j < h; j++) {
                    int p = pix[i + j * w];
                    a[j] = (p & 0xff000000);
                    r[j] = (p >> 16 & 0x000000ff) + r[j - 1];
                    g[j] = (p >> 8 & 0x000000ff) + g[j - 1];
                    b[j] = (p & 0x000000ff) + b[j - 1];
                }
    
                for(int j = 0; j < h; j++) {
                    int low = j - radius, high = j + radius;
                    if(low < 0) low = 0;
                    if(high > hm) high = hm;
                    int len = high - low;
                    int rj = ((r[high] - r[low]) / len) << 16;
                    int gj = ((g[high] - g[low]) / len) << 8;
                    int bj = (b[high] - b[low]) / len;
                    pix[i + j * w] = a[j] | rj | gj | bj;
                }
            }
    
            bitmap.setPixels(pix, 0, w, 0, 0, w, h);
            return bitmap;
        }
    

    由于是在Java层计算的,为了提高效率,有一些技巧:

    bitmap.getPixels()方法将bitmap转换成一个一维数组int[], 直接操作数组是计算效率最高的

    尽量使用位运算, 像素的ARGB值恰好占一个int的四个八位, 取出和合成它们用 &| 就行

    重复计算一个数组中相邻几项的和只需要累加一次. 比如有数组A, 要计算从A[i]到A[j]的和, 先创建数组B, B[0] = A[0], B[1] = B[0] + A[1], B[i] = B[i - 1] + A[i]..., 这样累加一次后,从A[i]到A[j]的和就等于B[j] - B[i - 1].

    这样模糊一张500*500的图片大概需要十几ms. 效果如下:


    模糊半径小 模糊半径大

    相关文章

      网友评论

          本文标题:Android图片纵向(竖直)模糊算法

          本文链接:https://www.haomeiwen.com/subject/cfpvgqtx.html