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


高斯模糊是用得最广泛的图像模糊算法,它的原理很简单,对每个点计算它周围其他点的平均色值,设置到该点上,就是模糊后的图。取周围其他点的范围称为模糊半径,模糊半径越大也就越模糊。高斯模糊算法网上很多,可以参考这个:
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. 效果如下:
模糊半径小

模糊半径大

原创文章,作者:306829225,如若转载,请注明出处:https://blog.ytso.com/tech/275254.html

(0)
上一篇 2022年7月18日 20:18
下一篇 2022年7月18日 20:47

相关推荐

发表回复

登录后才能评论