您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)如何進(jìn)行圖片JNI C++\Java高斯模糊的實(shí)現(xiàn),文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
說(shuō)明:其中代碼大部分來(lái)源于網(wǎng)絡(luò),不過(guò)都是開源的。
最原始的代碼:
// The Stack Blur Algorithm was invented by Mario Klingemann, // mario@quasimondo.com and described here: // http://incubator.quasimondo.com/processing/fast_blur_deluxe.php // This is C++ RGBA (32 bit color) multi-threaded version // by Victor Laskin (victor.laskin@gmail.com) // More details: http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp // This code is using MVThread class from my cross-platform framework // You can exchange it with any thread implementation you like // -------------------------------------- stackblur -----------------------------------------> static unsigned short const stackblur_mul[255] = { 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259 }; static unsigned char const stackblur_shr[255] = { 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 }; /// Stackblur algorithm body void stackblurJob(unsigned char* src, ///< input image data unsigned int w, ///< image width unsigned int h, ///< image height unsigned int radius, ///< blur intensity (should be in 2..254 range) int cores, ///< total number of working threads int core, ///< current thread number int step, ///< step of processing (1,2) unsigned char* stack ///< stack buffer ) { unsigned int x, y, xp, yp, i; unsigned int sp; unsigned int stack_start; unsigned char* stack_ptr; unsigned char* src_ptr; unsigned char* dst_ptr; unsigned long sum_r; unsigned long sum_g; unsigned long sum_b; unsigned long sum_a; unsigned long sum_in_r; unsigned long sum_in_g; unsigned long sum_in_b; unsigned long sum_in_a; unsigned long sum_out_r; unsigned long sum_out_g; unsigned long sum_out_b; unsigned long sum_out_a; unsigned int wm = w - 1; unsigned int hm = h - 1; unsigned int w4 = w * 4; unsigned int div = (radius * 2) + 1; unsigned int mul_sum = stackblur_mul[radius]; unsigned char shr_sum = stackblur_shr[radius]; if (step == 1) { int minY = core * h / cores; int maxY = (core + 1) * h / cores; for(y = minY; y < maxY; y++) { sum_r = sum_g = sum_b = sum_a = sum_in_r = sum_in_g = sum_in_b = sum_in_a = sum_out_r = sum_out_g = sum_out_b = sum_out_a = 0; src_ptr = src + w4 * y; // start of line (0,y) for(i = 0; i <= radius; i++) { stack_ptr = &stack[ 4 * i ]; stack_ptr[0] = src_ptr[0]; stack_ptr[1] = src_ptr[1]; stack_ptr[2] = src_ptr[2]; stack_ptr[3] = src_ptr[3]; sum_r += src_ptr[0] * (i + 1); sum_g += src_ptr[1] * (i + 1); sum_b += src_ptr[2] * (i + 1); sum_a += src_ptr[3] * (i + 1); sum_out_r += src_ptr[0]; sum_out_g += src_ptr[1]; sum_out_b += src_ptr[2]; sum_out_a += src_ptr[3]; } for(i = 1; i <= radius; i++) { if (i <= wm) src_ptr += 4; stack_ptr = &stack[ 4 * (i + radius) ]; stack_ptr[0] = src_ptr[0]; stack_ptr[1] = src_ptr[1]; stack_ptr[2] = src_ptr[2]; stack_ptr[3] = src_ptr[3]; sum_r += src_ptr[0] * (radius + 1 - i); sum_g += src_ptr[1] * (radius + 1 - i); sum_b += src_ptr[2] * (radius + 1 - i); sum_a += src_ptr[3] * (radius + 1 - i); sum_in_r += src_ptr[0]; sum_in_g += src_ptr[1]; sum_in_b += src_ptr[2]; sum_in_a += src_ptr[3]; } sp = radius; xp = radius; if (xp > wm) xp = wm; src_ptr = src + 4 * (xp + y * w); // img.pix_ptr(xp, y); dst_ptr = src + y * w4; // img.pix_ptr(0, y); for(x = 0; x < w; x++) { dst_ptr[0] = (sum_r * mul_sum) >> shr_sum; dst_ptr[1] = (sum_g * mul_sum) >> shr_sum; dst_ptr[2] = (sum_b * mul_sum) >> shr_sum; dst_ptr[3] = (sum_a * mul_sum) >> shr_sum; dst_ptr += 4; sum_r -= sum_out_r; sum_g -= sum_out_g; sum_b -= sum_out_b; sum_a -= sum_out_a; stack_start = sp + div - radius; if (stack_start >= div) stack_start -= div; stack_ptr = &stack[4 * stack_start]; sum_out_r -= stack_ptr[0]; sum_out_g -= stack_ptr[1]; sum_out_b -= stack_ptr[2]; sum_out_a -= stack_ptr[3]; if(xp < wm) { src_ptr += 4; ++xp; } stack_ptr[0] = src_ptr[0]; stack_ptr[1] = src_ptr[1]; stack_ptr[2] = src_ptr[2]; stack_ptr[3] = src_ptr[3]; sum_in_r += src_ptr[0]; sum_in_g += src_ptr[1]; sum_in_b += src_ptr[2]; sum_in_a += src_ptr[3]; sum_r += sum_in_r; sum_g += sum_in_g; sum_b += sum_in_b; sum_a += sum_in_a; ++sp; if (sp >= div) sp = 0; stack_ptr = &stack[sp*4]; sum_out_r += stack_ptr[0]; sum_out_g += stack_ptr[1]; sum_out_b += stack_ptr[2]; sum_out_a += stack_ptr[3]; sum_in_r -= stack_ptr[0]; sum_in_g -= stack_ptr[1]; sum_in_b -= stack_ptr[2]; sum_in_a -= stack_ptr[3]; } } } // step 2 if (step == 2) { int minX = core * w / cores; int maxX = (core + 1) * w / cores; for(x = minX; x < maxX; x++) { sum_r = sum_g = sum_b = sum_a = sum_in_r = sum_in_g = sum_in_b = sum_in_a = sum_out_r = sum_out_g = sum_out_b = sum_out_a = 0; src_ptr = src + 4 * x; // x,0 for(i = 0; i <= radius; i++) { stack_ptr = &stack[i * 4]; stack_ptr[0] = src_ptr[0]; stack_ptr[1] = src_ptr[1]; stack_ptr[2] = src_ptr[2]; stack_ptr[3] = src_ptr[3]; sum_r += src_ptr[0] * (i + 1); sum_g += src_ptr[1] * (i + 1); sum_b += src_ptr[2] * (i + 1); sum_a += src_ptr[3] * (i + 1); sum_out_r += src_ptr[0]; sum_out_g += src_ptr[1]; sum_out_b += src_ptr[2]; sum_out_a += src_ptr[3]; } for(i = 1; i <= radius; i++) { if(i <= hm) src_ptr += w4; // +stride stack_ptr = &stack[4 * (i + radius)]; stack_ptr[0] = src_ptr[0]; stack_ptr[1] = src_ptr[1]; stack_ptr[2] = src_ptr[2]; stack_ptr[3] = src_ptr[3]; sum_r += src_ptr[0] * (radius + 1 - i); sum_g += src_ptr[1] * (radius + 1 - i); sum_b += src_ptr[2] * (radius + 1 - i); sum_a += src_ptr[3] * (radius + 1 - i); sum_in_r += src_ptr[0]; sum_in_g += src_ptr[1]; sum_in_b += src_ptr[2]; sum_in_a += src_ptr[3]; } sp = radius; yp = radius; if (yp > hm) yp = hm; src_ptr = src + 4 * (x + yp * w); // img.pix_ptr(x, yp); dst_ptr = src + 4 * x; // img.pix_ptr(x, 0); for(y = 0; y < h; y++) { dst_ptr[0] = (sum_r * mul_sum) >> shr_sum; dst_ptr[1] = (sum_g * mul_sum) >> shr_sum; dst_ptr[2] = (sum_b * mul_sum) >> shr_sum; dst_ptr[3] = (sum_a * mul_sum) >> shr_sum; dst_ptr += w4; sum_r -= sum_out_r; sum_g -= sum_out_g; sum_b -= sum_out_b; sum_a -= sum_out_a; stack_start = sp + div - radius; if(stack_start >= div) stack_start -= div; stack_ptr = &stack[4 * stack_start]; sum_out_r -= stack_ptr[0]; sum_out_g -= stack_ptr[1]; sum_out_b -= stack_ptr[2]; sum_out_a -= stack_ptr[3]; if(yp < hm) { src_ptr += w4; // stride ++yp; } stack_ptr[0] = src_ptr[0]; stack_ptr[1] = src_ptr[1]; stack_ptr[2] = src_ptr[2]; stack_ptr[3] = src_ptr[3]; sum_in_r += src_ptr[0]; sum_in_g += src_ptr[1]; sum_in_b += src_ptr[2]; sum_in_a += src_ptr[3]; sum_r += sum_in_r; sum_g += sum_in_g; sum_b += sum_in_b; sum_a += sum_in_a; ++sp; if (sp >= div) sp = 0; stack_ptr = &stack[sp*4]; sum_out_r += stack_ptr[0]; sum_out_g += stack_ptr[1]; sum_out_b += stack_ptr[2]; sum_out_a += stack_ptr[3]; sum_in_r -= stack_ptr[0]; sum_in_g -= stack_ptr[1]; sum_in_b -= stack_ptr[2]; sum_in_a -= stack_ptr[3]; } } } } class MVImageUtilsStackBlurTask : public MVThread { public: unsigned char* src; unsigned int w; unsigned int h; unsigned int radius; int cores; int core; int step; unsigned char* stack; inline MVImageUtilsStackBlurTask(unsigned char* src, unsigned int w, unsigned int h, unsigned int radius, int cores, int core, int step, unsigned char* stack) { this->src = src; this->w = w; this->h = h; this->radius = radius; this->cores = cores; this->core = core; this->step = step; this->stack = stack; } inline void run() { stackblurJob(src, w, h, radius, cores, core, step, stack); } }; /// Stackblur algorithm by Mario Klingemann /// Details here: /// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html /// C++ implemenation base from: /// https://gist.github.com/benjamin9999/3809142 /// http://www.antigrain.com/__code/include/agg_blur.h.html /// This version works only with RGBA color void stackblur(unsigned char* src, ///< input image data unsigned int w, ///< image width unsigned int h, ///< image height unsigned int radius, ///< blur intensity (should be in 2..254 range) int cores = 1 ///< number of threads (1 - normal single thread) ) { if (radius > 254) return; if (radius < 2) return; unsigned int div = (radius * 2) + 1; unsigned char* stack = new unsigned char [div * 4 * cores]; if (cores == 1) { // no multithreading stackblurJob(src, w, h, radius, 1, 0, 1, stack); stackblurJob(src, w, h, radius, 1, 0, 2, stack); } else { MVImageUtilsStackBlurTask** workers = new MVImageUtilsStackBlurTask*[cores]; for (int i = 0; i < cores; i++) { workers[i] = new MVImageUtilsStackBlurTask(src, w, h, radius, cores, i, 1, stack + div * 4 * i); workers[i]->start(); } for (int i = 0; i < cores; i++) workers[i]->wait(); for (int i = 0; i < cores; i++) { workers[i]->step = 2; workers[i]->start(); } for (int i = 0; i < cores; i++) { workers[i]->wait(); delete workers[i]; } delete[] workers; } delete[] stack; }
這個(gè)是C++的代碼。
在網(wǎng)上發(fā)現(xiàn)了一個(gè)開源的 Android 模糊的例子,其中有該代碼的 Java 版本。
import android.graphics.Bitmap; import java.util.ArrayList; import java.util.concurrent.Callable; class JavaBlurProcess implements BlurProcess { private static final short[] stackblur_mul = { 512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, 454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512, 482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, 437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512, 497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, 320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456, 446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335, 329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512, 505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405, 399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328, 324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271, 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456, 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388, 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335, 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292, 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259 }; private static final byte[] stackblur_shr = { 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 }; @Override public Bitmap blur(Bitmap original, float radius) { int w = original.getWidth(); int h = original.getHeight(); int[] currentPixels = new int[w * h]; original.getPixels(currentPixels, 0, w, 0, 0, w, h); int cores = StackBlurManager.EXECUTOR_THREADS; ArrayList<BlurTask> horizontal = new ArrayList<BlurTask>(cores); ArrayList<BlurTask> vertical = new ArrayList<BlurTask>(cores); for (int i = 0; i < cores; i++) { horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1)); vertical.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 2)); } try { StackBlurManager.EXECUTOR.invokeAll(horizontal); } catch (InterruptedException e) { return null; } try { StackBlurManager.EXECUTOR.invokeAll(vertical); } catch (InterruptedException e) { return null; } return Bitmap.createBitmap(currentPixels, w, h, Bitmap.Config.ARGB_8888); } private static void blurIteration(int[] src, int w, int h, int radius, int cores, int core, int step) { int x, y, xp, yp, i; int sp; int stack_start; int stack_i; int src_i; int dst_i; long sum_r, sum_g, sum_b, sum_in_r, sum_in_g, sum_in_b, sum_out_r, sum_out_g, sum_out_b; int wm = w - 1; int hm = h - 1; int div = (radius * 2) + 1; int mul_sum = stackblur_mul[radius]; byte shr_sum = stackblur_shr[radius]; int[] stack = new int[div]; if (step == 1) { int minY = core * h / cores; int maxY = (core + 1) * h / cores; for(y = minY; y < maxY; y++) { sum_r = sum_g = sum_b = sum_in_r = sum_in_g = sum_in_b = sum_out_r = sum_out_g = sum_out_b = 0; src_i = w * y; // start of line (0,y) for(i = 0; i <= radius; i++) { stack_i = i; stack[stack_i] = src[src_i]; sum_r += ((src[src_i] >>> 16) & 0xff) * (i + 1); sum_g += ((src[src_i] >>> 8) & 0xff) * (i + 1); sum_b += (src[src_i] & 0xff) * (i + 1); sum_out_r += ((src[src_i] >>> 16) & 0xff); sum_out_g += ((src[src_i] >>> 8) & 0xff); sum_out_b += (src[src_i] & 0xff); } for(i = 1; i <= radius; i++) { if (i <= wm) src_i += 1; stack_i = i + radius; stack[stack_i] = src[src_i]; sum_r += ((src[src_i] >>> 16) & 0xff) * (radius + 1 - i); sum_g += ((src[src_i] >>> 8) & 0xff) * (radius + 1 - i); sum_b += (src[src_i] & 0xff) * (radius + 1 - i); sum_in_r += ((src[src_i] >>> 16) & 0xff); sum_in_g += ((src[src_i] >>> 8) & 0xff); sum_in_b += (src[src_i] & 0xff); } sp = radius; xp = radius; if (xp > wm) xp = wm; src_i = xp + y * w; // img.pix_ptr(xp, y); dst_i = y * w; // img.pix_ptr(0, y); for(x = 0; x < w; x++) { src[dst_i] = (int) ((src[dst_i] & 0xff000000) | ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16) | ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8) | ((((sum_b * mul_sum) >>> shr_sum) & 0xff))); dst_i += 1; sum_r -= sum_out_r; sum_g -= sum_out_g; sum_b -= sum_out_b; stack_start = sp + div - radius; if (stack_start >= div) stack_start -= div; stack_i = stack_start; sum_out_r -= ((stack[stack_i] >>> 16) & 0xff); sum_out_g -= ((stack[stack_i] >>> 8) & 0xff); sum_out_b -= (stack[stack_i] & 0xff); if(xp < wm) { src_i += 1; ++xp; } stack[stack_i] = src[src_i]; sum_in_r += ((src[src_i] >>> 16) & 0xff); sum_in_g += ((src[src_i] >>> 8) & 0xff); sum_in_b += (src[src_i] & 0xff); sum_r += sum_in_r; sum_g += sum_in_g; sum_b += sum_in_b; ++sp; if (sp >= div) sp = 0; stack_i = sp; sum_out_r += ((stack[stack_i] >>> 16) & 0xff); sum_out_g += ((stack[stack_i] >>> 8) & 0xff); sum_out_b += (stack[stack_i] & 0xff); sum_in_r -= ((stack[stack_i] >>> 16) & 0xff); sum_in_g -= ((stack[stack_i] >>> 8) & 0xff); sum_in_b -= (stack[stack_i] & 0xff); } } } // step 2 else if (step == 2) { int minX = core * w / cores; int maxX = (core + 1) * w / cores; for(x = minX; x < maxX; x++) { sum_r = sum_g = sum_b = sum_in_r = sum_in_g = sum_in_b = sum_out_r = sum_out_g = sum_out_b = 0; src_i = x; // x,0 for(i = 0; i <= radius; i++) { stack_i = i; stack[stack_i] = src[src_i]; sum_r += ((src[src_i] >>> 16) & 0xff) * (i + 1); sum_g += ((src[src_i] >>> 8) & 0xff) * (i + 1); sum_b += (src[src_i] & 0xff) * (i + 1); sum_out_r += ((src[src_i] >>> 16) & 0xff); sum_out_g += ((src[src_i] >>> 8) & 0xff); sum_out_b += (src[src_i] & 0xff); } for(i = 1; i <= radius; i++) { if(i <= hm) src_i += w; // +stride stack_i = i + radius; stack[stack_i] = src[src_i]; sum_r += ((src[src_i] >>> 16) & 0xff) * (radius + 1 - i); sum_g += ((src[src_i] >>> 8) & 0xff) * (radius + 1 - i); sum_b += (src[src_i] & 0xff) * (radius + 1 - i); sum_in_r += ((src[src_i] >>> 16) & 0xff); sum_in_g += ((src[src_i] >>> 8) & 0xff); sum_in_b += (src[src_i] & 0xff); } sp = radius; yp = radius; if (yp > hm) yp = hm; src_i = x + yp * w; // img.pix_ptr(x, yp); dst_i = x; // img.pix_ptr(x, 0); for(y = 0; y < h; y++) { src[dst_i] = (int) ((src[dst_i] & 0xff000000) | ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16) | ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8) | ((((sum_b * mul_sum) >>> shr_sum) & 0xff))); dst_i += w; sum_r -= sum_out_r; sum_g -= sum_out_g; sum_b -= sum_out_b; stack_start = sp + div - radius; if(stack_start >= div) stack_start -= div; stack_i = stack_start; sum_out_r -= ((stack[stack_i] >>> 16) & 0xff); sum_out_g -= ((stack[stack_i] >>> 8) & 0xff); sum_out_b -= (stack[stack_i] & 0xff); if(yp < hm) { src_i += w; // stride ++yp; } stack[stack_i] = src[src_i]; sum_in_r += ((src[src_i] >>> 16) & 0xff); sum_in_g += ((src[src_i] >>> 8) & 0xff); sum_in_b += (src[src_i] & 0xff); sum_r += sum_in_r; sum_g += sum_in_g; sum_b += sum_in_b; ++sp; if (sp >= div) sp = 0; stack_i = sp; sum_out_r += ((stack[stack_i] >>> 16) & 0xff); sum_out_g += ((stack[stack_i] >>> 8) & 0xff); sum_out_b += (stack[stack_i] & 0xff); sum_in_r -= ((stack[stack_i] >>> 16) & 0xff); sum_in_g -= ((stack[stack_i] >>> 8) & 0xff); sum_in_b -= (stack[stack_i] & 0xff); } } } } private static class BlurTask implements Callable<Void> { private final int[] _src; private final int _w; private final int _h; private final int _radius; private final int _totalCores; private final int _coreIndex; private final int _round; public BlurTask(int[] src, int w, int h, int radius, int totalCores, int coreIndex, int round) { _src = src; _w = w; _h = h; _radius = radius; _totalCores = totalCores; _coreIndex = coreIndex; _round = round; } @Override public Void call() throws Exception { blurIteration(_src, _w, _h, _radius, _totalCores, _coreIndex, _round); return null; } } }
該代碼與C++的代碼同出一源。下面來(lái)簡(jiǎn)要分析一下。
public Bitmap blur(Bitmap original, float radius) { int w = original.getWidth(); int h = original.getHeight(); int[] currentPixels = new int[w * h]; original.getPixels(currentPixels, 0, w, 0, 0, w, h); int cores = StackBlurManager.EXECUTOR_THREADS; ArrayList<BlurTask> horizontal = new ArrayList<BlurTask>(cores); ArrayList<BlurTask> vertical = new ArrayList<BlurTask>(cores); for (int i = 0; i < cores; i++) { horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1)); vertical.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 2)); } try { StackBlurManager.EXECUTOR.invokeAll(horizontal); } catch (InterruptedException e) { return null; } try { StackBlurManager.EXECUTOR.invokeAll(vertical); } catch (InterruptedException e) { return null; } return Bitmap.createBitmap(currentPixels, w, h, Bitmap.Config.ARGB_8888); }
方法進(jìn)入后,首先得到圖片的像素點(diǎn)集合;而后 New 兩個(gè) List ,分別存儲(chǔ) BlurTask 。
private static class BlurTask implements Callable<Void> { private final int[] _src; private final int _w; private final int _h; private final int _radius; private final int _totalCores; private final int _coreIndex; private final int _round; public BlurTask(int[] src, int w, int h, int radius, int totalCores, int coreIndex, int round) { _src = src; _w = w; _h = h; _radius = radius; _totalCores = totalCores; _coreIndex = coreIndex; _round = round; } @Override public Void call() throws Exception { blurIteration(_src, _w, _h, _radius, _totalCores, _coreIndex, _round); return null; } }
可以看出 BlurTask 是用于進(jìn)行 線程池的回調(diào)類;其主要調(diào)用了方法 blurIteration進(jìn)行模糊。
同時(shí)給方法,傳入的參數(shù)有:
像素點(diǎn)集合
寬
高
模糊半徑
最大內(nèi)核數(shù)
當(dāng)前內(nèi)核
而后回到第一步處:
int cores = StackBlurManager.EXECUTOR_THREADS;
其實(shí)是調(diào)用的:
Runtime.getRuntime().availableProcessors();
該方法用于返回當(dāng)前虛擬機(jī)的核數(shù);用此方法可以 最大效率的進(jìn)行多線程的分配。
而后:
for (int i = 0; i < cores; i++) { horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1)); vertical.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 2)); }
可以看出往列表中加上,對(duì)應(yīng)的線程回調(diào)操作;分別是 步驟1,和步驟2
而后:
try { StackBlurManager.EXECUTOR.invokeAll(horizontal); } catch (InterruptedException e) { return null; } try { StackBlurManager.EXECUTOR.invokeAll(vertical); } catch (InterruptedException e) { return null; }
該方法中: StackBlurManager.EXECUTOR 其實(shí)是:
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
可以看出其實(shí)是建立了一個(gè)線程池,線程池的運(yùn)行線程數(shù)為當(dāng)前虛擬機(jī)的核數(shù)。
然后把步驟1的集合丟進(jìn)線程池并等待執(zhí)行完成;而后丟進(jìn)步驟2.
其實(shí)從其命名就能看出:
步驟1其實(shí)是模糊水平方向
步驟2其實(shí)是模糊垂直方向
具體是不是可以看看 blurIteration 方法。
由于方法太長(zhǎng)就簡(jiǎn)化了一下:
private static void blurIteration(int[] src, int w, int h, int radius, int cores, int core, int step) { ... if (step == 1) { int minY = core * h / cores; int maxY = (core + 1) * h / cores; for(y = minY; y < maxY; y++) { ... } } // step 2 else if (step == 2) { int minX = core * w / cores; int maxX = (core + 1) * w / cores; for(x = minX; x < maxX; x++) <span > </span>{ <span > </span>... <span > </span>} } }
可以看出 分別進(jìn)行了模糊水平與垂直。
同時(shí),在模糊時(shí):分為了許多部分,具體取決于虛擬核數(shù)。
在這里有必要說(shuō)明一點(diǎn)就是;在模糊時(shí)只能先模糊第一步,而后才能模糊第二部。
意思就是說(shuō)第一步與第二步是不能同時(shí)進(jìn)行的;如果不贊同;可以啊把上面的兩個(gè)列表改成一個(gè)同時(shí)進(jìn)行多線程你就知道模糊的效果了。
這里截圖就不進(jìn)行截圖了,不過(guò)根據(jù)我的測(cè)試;該模糊方法在多線程下優(yōu)勢(shì)較為明顯;也就是說(shuō)手機(jī)核數(shù)越高其模糊速度越快。
如果該方法順序執(zhí)行,不使用多線程;那么其模糊所耗費(fèi)時(shí)間約比我上一章中介紹的方法多1/4的時(shí)間。
關(guān)于如何進(jìn)行圖片JNI C++\Java高斯模糊的實(shí)現(xiàn)就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。