I have been working on the implementation of Image Blur effects on android a few days ago!
I can't find a method until I can see that others call JNI, but I am not familiar with JNI!
I have to start from scratch! Here we will not talk about JNI platform construction, but only about the key code of JNI. I will share the specific project with you!
I did not find C ++ to blur images in JNI, so I had to write C ++ for implementation.
A stack blur effect was found in a foreign project. The prototype is as follows:
// Stack Blur v1.0//// Author: Mario Klingemann <mario@quasimondo.com>// http://incubator.quasimondo.com// created Feburary 29, 2004// 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>PImage a;PImage b;void setup(){ a=loadImage("dog.jpg"); size(a.width, a.height); b=new PImage(a.width, a.height); fill(255); noStroke(); frameRate(25);}void draw(){ System.arraycopy(a.pixels,0,b.pixels,0,a.pixels.length); fastblur(b,mouseY/4); image(b, 0, 0);}void fastblur(PImage img,int radius){ if (radius<1){ return; } int[] pix=img.pixels; int w=img.width; int h=img.height; 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[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; for (y=0;y
At the same time, find a code to become Java after learning from this improvement, as shown below:
public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) { // 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; if (canReuseInBitmap) { bitmap = sentBitmap; } else { bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); } if (radius < 1) { return (null); } int w = bitmap.getWidth(); int h = bitmap.getHeight(); int[] pix = new int[w * h]; bitmap.getPixels(pix, 0, w, 0, 0, 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; 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; } 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++) { // Preserve alpha channel: ( 0xff000000 & pix[yi] ) pix[yi] = (0xff000000 & pix[yi]) | (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, 0, 0, w, h); return (bitmap); }
For reference, I made a C code. Basically, the overall process has not changed, but it has changed to C (C ++ can also be used:
File Name: ImageBlur. c
/*************************************** * ********* Copyright: copyright QIUJUER 2013. author: QiujuerDate: 2014-04-18Description: implement image fuzzy processing ************************************ * *************/# include <malloc. h> # define ABS (a) <(0 )? (-A) :( a) # define MAX (a, B) (a)> (B )? (A) :( B) # define MIN (a, B) (a) <(B )? (A) (B )) /*************************************** * ********* Function: stackBlur (stack blur) Description: image pixel blur using the stack method. CILS: mallocTable Accessed: NULLTable Updated: NULLInput: pixel set, image width, image height, and blur radius Output: return the blurred pixel set Return: returns the blurred pixel set Others: NULL *************************************** * ********/static int * StackBlur (int * pix, int w, int h, int radius) {int wm = w-1; int hm = h-1; int wh = w * h; int div = radius + 1; int * r = (int *) malloc (wh * sizeof (int); int * g = (int *) malloc (wh * sizeof (int )); int * B = (int *) malloc (wh * sizeof (int); int rsum, gsum, bsum, x, y, I, p, yp, yi, yw; int * vmin = (int *) malloc (MAX (w, h) * sizeof (int); int divsum = (div + 1)> 1; divsum * = divsum; int * dv = (int *) malloc (256 * divsum * sizeof (int); for (I = 0; I <256 * divsum; I ++) {dv [I] = (I/divsum);} yw = yi = 0; int (* stack) [3] = (int (*) [3]) malloc (div * 3 * sizeof (int); int stackpointer; int stackstart; int * sir; int rbs; int r1 = radius + 1; int routsum, goutsum, boutsum; int rinsum, ginsum, binsum; for (y = 0; y I also encountered a very comedy problem during the change. I found that after I used this to call the program, the memory size of the program increased until more than 500 mb, and the program got stuck. I know I wrote a memory leak!
Then I looked for it and found that it was. We had to make it free. Then, I found that the memory usage is indeed less than that of Java, and the speed is faster!
In JNI, I used two methods: one is to directly transfer files, and the other is to blur the set of transmitted pixels! They are as follows:
/* * Class: com_accumulation_imageblurring_app_jni_ImageBlur * Method: blurIntArray * Signature: ([IIII)V */JNIEXPORT void JNICALL Java_com_accumulation_imageblurring_app_jni_ImageBlur_blurIntArray (JNIEnv *, jclass, jintArray, jint, jint, jint);/* * Class: com_accumulation_imageblurring_app_jni_ImageBlur * Method: blurBitMap * Signature: (Landroid/graphics/Bitmap;I)V */JNIEXPORT void JNICALL Java_com_accumulation_imageblurring_app_jni_ImageBlur_blurBitMap (JNIEnv *, jclass, jobject, jint);
Corresponding Java call:
public class ImageBlur { public static native void blurIntArray(int[] pImg, int w, int h, int r); public static native void blurBitMap(Bitmap bitmap, int r); static { System.loadLibrary("JNI_ImageBlur"); }}
//////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// ///
At this time, I did three tests: one was implemented directly at the Java layer, the other was to pass the pixel set blur, and the other was to directly pass the image for blur. The result is as follows:
Through the comparison above, we can draw the following conclusion:
1. Java is indeed the slowest, but it is actually not much slower, and the virtual machine optimization is just as fierce.
2. The fastest speed for directly transferring pixel sets in C (first startup)
3. After I switched over the page multiple times, I found that the time consumed for directly transferring the pixel set increased, from over 60 to over 120.
4. After multiple switching, we found that the speed of directly transferring pixels is almost the same as that of transmitting images.
5. After multiple operations, it is found that the file transfer fluctuates slightly, ranging from 100 ~ Between 138, followed by large fluctuations in the set of transmitted pixels, and the biggest fluctuation in java!
The above is my conclusion. It may be incorrect, but it is true on my machine!
Note: If you select "Downscale before blur", the image is first compressed, then blurred, and then zoomed in. In this case, the blur effect will slightly lose some effect, but the speed is indeed incomparable.
The time consumed is: 1 ~ Computation can be completed within 10 ms. Of course it is related to the size of your blur!
Final: Project address: GitHub
For original works, please indicate the source for reprinting!
QIUJUER (qiujuer@live.cn)