Android,即时模糊位图?

所以我试图尽可能快地模糊图像(即时感觉),因为当按下模糊button时活动需要被更新。

我遇到的问题是,我无法find足够快的模糊效果。 注意:模糊,最好是高斯模糊,并不一定是最好的质量。

我尝试了以下内容,但需要几秒钟,是否有代码可以使质量牺牲更快运行? 还是有其他的select吗? 我会研究GPU的东西,但这种模糊只是一个与用户界面相关的效果,只有当我按下打开一个透明的活动,大小为一个小方块…

有任何想法吗?

static Bitmap fastblur(Bitmap sentBitmap, int radius, int fromX, int fromY, int width, int height) { // Stack Blur v1.0 from // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html // // Java Author: Mario Klingemann <mario at quasimondo.com> // http://incubator.quasimondo.com // created Feburary 29, 2004 // Android port : Yahel Bouaziz <yahel at kayenko.com> // http://www.kayenko.com // ported april 5th, 2012 // This is a compromise between Gaussian Blur and Box blur // It creates much better looking blurs than Box Blur, but is // 7x faster than my Gaussian Blur implementation. // // I called it Stack Blur because this describes best how this // filter works internally: it creates a kind of moving stack // of colors whilst scanning through the image. Thereby it // just has to add one new block of color to the right side // of the stack and remove the leftmost color. The remaining // colors on the topmost layer of the stack are either added on // or reduced by one, depending on if they are on the right or // on the left side of the stack. // // If you are using this algorithm in your code please add // the following line: // // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com> Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); if (radius < 1) { return (null); } int w = width; int h = height; int[] pix = new int[w * h]; bitmap.getPixels(pix, 0, w, fromX, fromY, w, h); int wm = w - 1; int hm = h - 1; int wh = w * h; int div = radius + radius + 1; int r[] = new int[wh]; int g[] = new int[wh]; int b[] = new int[wh]; int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; int vmin[] = new int[Math.max(w, h)]; int divsum = (div + 1) >> 1; divsum *= divsum; int dv[] = new int[256 * divsum]; for (i = 0; i < 256 * divsum; i++) { dv[i] = (i / divsum); } yw = yi = 0; int[][] stack = new int[div][3]; int stackpointer; int stackstart; int[] sir; int rbs; int r1 = radius + 1; int routsum, goutsum, boutsum; int rinsum, ginsum, binsum; int originRadius = radius; for (y = 0; y < h; y++) { rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; for (i = -radius; i <= radius; i++) { p = pix[yi + Math.min(wm, Math.max(i, 0))]; sir = stack[i + radius]; sir[0] = (p & 0xff0000) >> 16; sir[1] = (p & 0x00ff00) >> 8; sir[2] = (p & 0x0000ff); rbs = r1 - Math.abs(i); rsum += sir[0] * rbs; gsum += sir[1] * rbs; bsum += sir[2] * rbs; if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; } else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; } } stackpointer = radius; for (x = 0; x < w; x++) { r[yi] = dv[rsum]; g[yi] = dv[gsum]; b[yi] = dv[bsum]; rsum -= routsum; gsum -= goutsum; bsum -= boutsum; stackstart = stackpointer - radius + div; sir = stack[stackstart % div]; routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2]; if (y == 0) { vmin[x] = Math.min(x + radius + 1, wm); } p = pix[yw + vmin[x]]; sir[0] = (p & 0xff0000) >> 16; sir[1] = (p & 0x00ff00) >> 8; sir[2] = (p & 0x0000ff); rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; rsum += rinsum; gsum += ginsum; bsum += binsum; stackpointer = (stackpointer + 1) % div; sir = stack[(stackpointer) % div]; routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2]; yi++; } yw += w; } radius = originRadius; for (x = 0; x < w; x++) { rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; yp = -radius * w; for (i = -radius; i <= radius; i++) { yi = Math.max(0, yp) + x; sir = stack[i + radius]; sir[0] = r[yi]; sir[1] = g[yi]; sir[2] = b[yi]; rbs = r1 - Math.abs(i); rsum += r[yi] * rbs; gsum += g[yi] * rbs; bsum += b[yi] * rbs; if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; } else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; } if (i < hm) { yp += w; } } yi = x; stackpointer = radius; for (y = 0; y < h; y++) { pix[yi] = 0xff000000 | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; rsum -= routsum; gsum -= goutsum; bsum -= boutsum; stackstart = stackpointer - radius + div; sir = stack[stackstart % div]; routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2]; if (x == 0) { vmin[y] = Math.min(y + r1, hm) * w; } p = x + vmin[y]; sir[0] = r[p]; sir[1] = g[p]; sir[2] = b[p]; rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; rsum += rinsum; gsum += ginsum; bsum += binsum; stackpointer = (stackpointer + 1) % div; sir = stack[stackpointer]; routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2]; yi += w; } } bitmap.setPixels(pix, 0, w, fromX, fromY, w, h); return (bitmap); 

}

Solutions Collecting From Web of "Android,即时模糊位图?"

尝试缩小图像2,4,8,…倍,然后再放大。 那很快。 否则在renderscript中实现它。

如果你想比缩放更多,你可以看看这个代码片段在renderscript。 它在另一个答案中做了同样的模糊。 在Java中可以实现相同的algorithm,并且是对其他答案的优化。 这段代码模糊了一行。 为了模糊一个位图,你应该为所有行调用这个,然后对所有列调用它(你需要重新实现它来处理列)。 要快速模糊,只需要做一次。 如果你想要一个更好看的模糊做几次。 我通常只做两次。

做一条线的原因是我试图对algorithm进行并行化,这给了一些改进,并且在renderscript中非常简单。 我为所有行并行地调用了下面的代码,然后对所有列调用相同的代码。

 int W = 8; uchar4 *in; uchar4 *out; int N; float invN; uint32_t nx; uint32_t ny; void init_calc() { N = 2*W+1; invN = 1.0f/N; nx = rsAllocationGetDimX(rsGetAllocation(in)); ny = rsAllocationGetDimY(rsGetAllocation(in)); } void root(const ushort *v_in) { float4 sum = 0; uchar4 *head = in + *v_in * nx; uchar4 *tail = head; uchar4 *p = out + *v_in * nx; uchar4 *hpw = head + W; uchar4 *hpn = head + N; uchar4 *hpx = head + nx; uchar4 *hpxmw = head + nx - W - 1; while (head < hpw) { sum += rsUnpackColor8888(*head++); } while (head < hpn) { sum += rsUnpackColor8888(*head++); *p++ = rsPackColorTo8888(sum*invN); } while (head < hpx) { sum += rsUnpackColor8888(*head++); sum -= rsUnpackColor8888(*tail++); *p++ = rsPackColorTo8888(sum*invN); } while (tail < hpxmw) { sum -= rsUnpackColor8888(*tail++); *p++ = rsPackColorTo8888(sum*invN); } } 

这里是垂直模糊:

 int W = 8; uchar4 *in; uchar4 *out; int N; float invN; uint32_t nx; uint32_t ny; void init_calc() { N = 2*W+1; invN = 1.0f/N; nx = rsAllocationGetDimX(rsGetAllocation(in)); ny = rsAllocationGetDimY(rsGetAllocation(in)); } void root(const ushort *v_in) { float4 sum = 0; uchar4 *head = in + *v_in; uchar4 *tail = head; uchar4 *hpw = head + nx*W; uchar4 *hpn = head + nx*N; uchar4 *hpy = head + nx*ny; uchar4 *hpymw = head + nx*(ny-W-1); uchar4 *p = out + *v_in; while (head < hpw) { sum += rsUnpackColor8888(*head); head += nx; } while (head < hpn) { sum += rsUnpackColor8888(*head); *p = rsPackColorTo8888(sum*invN); head += nx; p += nx; } while (head < hpy) { sum += rsUnpackColor8888(*head); sum -= rsUnpackColor8888(*tail); *p = rsPackColorTo8888(sum*invN); head += nx; tail += nx; p += nx; } while (tail < hpymw) { sum -= rsUnpackColor8888(*tail); *p = rsPackColorTo8888(sum*invN); tail += nx; p += nx; } } 

这里是调用rs代码的Java代码:

 private RenderScript mRS; private ScriptC_horzblur mHorizontalScript; private ScriptC_vertblur mVerticalScript; private ScriptC_blur mBlurScript; private Allocation alloc1; private Allocation alloc2; private void hblur(int radius, Allocation index, Allocation in, Allocation out) { mHorizontalScript.set_W(radius); mHorizontalScript.bind_in(in); mHorizontalScript.bind_out(out); mHorizontalScript.invoke_init_calc(); mHorizontalScript.forEach_root(index); } private void vblur(int radius, Allocation index, Allocation in, Allocation out) { mHorizontalScript.set_W(radius); mVerticalScript.bind_in(in); mVerticalScript.bind_out(out); mVerticalScript.invoke_init_calc(); mVerticalScript.forEach_root(index); } Bitmap blur(Bitmap org, int radius) { Bitmap out = Bitmap.createBitmap(org.getWidth(), org.getHeight(), org.getConfig()); blur(org, out, radius); return out; } private Allocation createIndex(int size) { Element element = Element.U16(mRS); Allocation allocation = Allocation.createSized(mRS, element, size); short[] rows = new short[size]; for (int i = 0; i < rows.length; i++) rows[i] = (short)i; allocation.copyFrom(rows); return allocation; } private void blur(Bitmap src, Bitmap dst, int r) { Allocation alloc1 = Allocation.createFromBitmap(mRS, src); Allocation alloc2 = Allocation.createTyped(mRS, alloc1.getType()); Allocation hIndexAllocation = createIndex(alloc1.getType().getY()); Allocation vIndexAllocation = createIndex(alloc1.getType().getX()); // Iteration 1 hblur(r, hIndexAllocation, alloc1, alloc2); vblur(r, vIndexAllocation, alloc2, alloc1); // Iteration 2 hblur(r, hIndexAllocation, alloc1, alloc2); vblur(r, vIndexAllocation, alloc2, alloc1); // Add more iterations if you like or simply make a loop alloc1.copyTo(dst); } 

高斯模糊准确地做到昂贵。 通过迭代平均像素可以实现更快的近似。 对图像进行模糊处理仍然很昂贵,但是您可以在每次迭代之间重新绘制,以便至less提供即时反馈和模糊的dynamic图像。

 static void blurfast(Bitmap bmp, int radius) { int w = bmp.getWidth(); int h = bmp.getHeight(); int[] pix = new int[w * h]; bmp.getPixels(pix, 0, w, 0, 0, w, h); for(int r = radius; r >= 1; r /= 2) { for(int i = r; i < h - r; i++) { for(int j = r; j < w - r; j++) { int tl = pix[(i - r) * w + j - r]; int tr = pix[(i - r) * w + j + r]; int tc = pix[(i - r) * w + j]; int bl = pix[(i + r) * w + j - r]; int br = pix[(i + r) * w + j + r]; int bc = pix[(i + r) * w + j]; int cl = pix[i * w + j - r]; int cr = pix[i * w + j + r]; pix[(i * w) + j] = 0xFF000000 | (((tl & 0xFF) + (tr & 0xFF) + (tc & 0xFF) + (bl & 0xFF) + (br & 0xFF) + (bc & 0xFF) + (cl & 0xFF) + (cr & 0xFF)) >> 3) & 0xFF | (((tl & 0xFF00) + (tr & 0xFF00) + (tc & 0xFF00) + (bl & 0xFF00) + (br & 0xFF00) + (bc & 0xFF00) + (cl & 0xFF00) + (cr & 0xFF00)) >> 3) & 0xFF00 | (((tl & 0xFF0000) + (tr & 0xFF0000) + (tc & 0xFF0000) + (bl & 0xFF0000) + (br & 0xFF0000) + (bc & 0xFF0000) + (cl & 0xFF0000) + (cr & 0xFF0000)) >> 3) & 0xFF0000; } } } bmp.setPixels(pix, 0, w, 0, 0, w, h); }