1. 程式人生 > >Android 實時濾鏡 高斯模糊(帶原始碼)

Android 實時濾鏡 高斯模糊(帶原始碼)

最近在做一個這樣一個需求,一個控制元件可以實時預覽攝像頭的內容,並且對此影象進行高斯模糊處理,現在來記錄一下。 

              1. 這裡寫圖片描述

基本的實現思路

1,攝像頭實時預覽的資料會回撥給onPreviewFrame(byte[] data, Camera camera) ,通過這個獲取YUV格式的資料。 
2,將YUV轉換成RGB陣列。 
3,cpu計算rgb陣列或者gpu來處理影象。(這裡用的cpu計算) 
github上有一個GPU實現高斯濾鏡的開源專案,但是我覺得它的高斯模糊實現的不夠好。 
android-gpuimage

開始onPreviewFrame(data)YUV420SP轉RGBdoBlur()CPU計算結束

一,YUV420SP

在onPreviewFrame文件中有這麼一段話。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * Callback interface used to deliver copies of preview frames as
     * they are displayed.
     *
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @see</span> #setPreviewCallback(Camera.PreviewCallback)
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @see</span> #setOneShotPreviewCallback(Camera.PreviewCallback)
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @see</span> #setPreviewCallbackWithBuffer(Camera.PreviewCallback)
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @see</span> #startPreview()
     */</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">PreviewCallback</span>
    {</span>
        <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
         * Called as preview frames are displayed.  This callback is invoked
         * on the event thread {@link #open(int)} was called from.
         *
         * <p>If using the {@link android.graphics.ImageFormat#YV12} format,
         * refer to the equations in {@link Camera.Parameters#setPreviewFormat}
         * for the arrangement of the pixel data in the preview callback
         * buffers.
         *
         *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> data the contents of the preview frame in the format defined
         *  by {@link android.graphics.ImageFormat}, which can be queried
         *  with {@link android.hardware.Camera.Parameters#getPreviewFormat()}.
         *  If {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}
         *             is never called, the default will be the YCbCr_420_SP
         *             (NV21) format.
         *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> camera the Camera service object.
         */</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> onPreviewFrame(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>[] data, Camera camera);
    };</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li></ul>

預設輸出的格式YUV420SP,註釋中的YCbCr就是YUV。 
YUV,分為三個分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值; 
而“U”和“V” 表示的則是色度(Chrominance或Chroma),作用是描述影像色彩及飽和度,用於指定畫素的顏色。

下面是擁有8個畫素的YUV陣列[4*2],YUV420SP即4個Y對應一個UV,如圖,Y1,Y2,Y9,Y10對應U1,V1。 
yuv420sp儲存示例

二,YUV420SP轉RGB

最主要是下面的轉換公式:

<code class="hljs markdown has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">//ITU-R BT.601 conversion

R = 1.164<span class="hljs-emphasis" style="box-sizing: border-box;">*(Y-16)+1.596*</span>(Cr-128)
G = 1.164<span class="hljs-emphasis" style="box-sizing: border-box;">*(Y-16)-0.392*</span>(Cb-128)-0.813*(Cr-128)
B = 1.164<span class="hljs-emphasis" style="box-sizing: border-box;">*(Y-16)+2.017*</span>(Cb-128)
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

或者

<code class="hljs perl has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">R<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''</span> = Y + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.140</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">*V</span>
G<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''</span> = Y - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>.<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">394</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">*U</span> - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>.<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">581</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">*V</span>
B<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''</span> = Y + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2.032</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">*U</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

只是工業標準不同而已。下面擷取android-gpu-image上面的程式碼並新增一些註釋,網上有很多轉換的方法,但是這個方法效能非常ok,耗時在10-20ms。為了最大可能獲取效能,程式碼中乘法等都變成了位操作和加法的方式。

<code class="language-c hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> YUVtoARBG(JNIEnv * env, jobject obj, jbyteArray yuv420sp, jint width, jint height, jintArray rgbOut)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             sz;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             i;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             j;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             Y;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             Cr = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             Cb = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             pixPtr = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//Y所佔的空間</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             jDiv2 = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//uv前面行所佔的空間</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             R = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             G = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             B = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>             cOff;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> w = width;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h = height;
    sz = w * h;

    jint *rgbData = (jint*) ((*env)->GetPrimitiveArrayCritical(env, rgbOut, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>));
    jbyte* yuv = (jbyte*) (*env)->GetPrimitiveArrayCritical(env, yuv420sp, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(j = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; j < h; j++) {
             pixPtr = j * w;     <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//Y所佔的空間</span>
             jDiv2 = j >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//除以2向下取整</span>
             <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < w; i++) {
                     Y = yuv[pixPtr];
                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(Y < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) Y += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255</span>;
                      <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//用位運算判斷是奇數還是偶數</span>
                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>((i & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x1</span>) != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) {
                             cOff = sz + jDiv2 * w + (i >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//計算 UV的位置  (i>>1)*2就是為了變成偶數  向下取整  因為U的遊標都是偶數位</span>
                             Cb = yuv[cOff];
                             <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(Cb < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) Cb += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">127</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> Cb -= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">128</span>;
                             Cr = yuv[cOff + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                             <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(Cr < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) Cr += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">127</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> Cr -= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">128</span>;
                     }

                     <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//ITU-R BT.601 conversion</span>
                     <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span>
                     <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//     R = 1.164*(Y-16)+1.596*(Cr-128)</span>
                     <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//     G = 1.164*(Y-16)-0.392*(Cb-128)-0.813*(Cr-128)</span>
                     <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//     B = 1.164*(Y-16)+2.017*(Cb-128)</span>
                     <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span>

                     Y = Y + (Y >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>) + (Y >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>) + (Y >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>);    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//Y=Y+Y*0.125+0.03125+0.00078</span>
                     R = Y + Cb + (Cb >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) + (Cb >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>) + (Cb >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>);
                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(R < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) R = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(R > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255</span>) R = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255</span>;
                     G = Y - Cb + (Cb >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>) + (Cb >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>) - (Cr >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) + (Cr >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>);
                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(G < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) G = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(G > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255</span>) G = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255</span>;
                     B = Y + (Cr << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) + (Cr >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>);
                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(B < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) B = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(B > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255</span>) B = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255</span>;
                     rgbData[pixPtr++] = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff000000</span> + (R << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>) + (G << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>) + B;
             }
    }

    (*env)->ReleasePrimitiveArrayCritical(env, rgbOut, rgbData, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);
    (*env)->ReleasePrimitiveArrayCritical(env, yuv420sp, yuv, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li></ul>

三,高斯模糊

至於原理請看:高斯模糊 
這裡用的FastBlur,之前考慮了RenderScript ,後來發現在實際使用中,最下方會出現閃爍的現象,故放棄。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Bitmap <span class="hljs-title" style="box-sizing: border-box;">doBlur</span>(Bitmap sentBitmap, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> radius, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> canReuseInBitmap) {

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Stack Blur v1.0 from</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Java Author: Mario Klingemann <mario at quasimondo.com></span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// http://incubator.quasimondo.com</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// created Feburary 29, 2004</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Android port : Yahel Bouaziz <yahel at kayenko.com></span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// http://www.kayenko.com</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ported april 5th, 2012</span>

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// This is a compromise between Gaussian Blur and Box blur</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// It creates much better looking blurs than Box Blur, but is</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 7x faster than my Gaussian Blur implementation.</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// I called it Stack Blur because this describes best how this</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// filter works internally: it creates a kind of moving stack</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// of colors whilst scanning through the image. Thereby it</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// just has to add one new block of color to the right side</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// of the stack and remove the leftmost color. The remaining</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// colors on the topmost layer of the stack are either added on</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// or reduced by one, depending on if they are on the right or</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// on the left side of the stack.</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// If you are using this algorithm in your code please add</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// the following line:</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Stack Blur Algorithm by Mario Klingemann <[email protected]></span>

        Bitmap bitmap;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (canReuseInBitmap) {
            bitmap = sentBitmap;
        } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
            bitmap = sentBitmap.copy(sentBitmap.getConfig(), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (radius < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>);
        }

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> w = bitmap.getWidth();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> h = bitmap.getHeight();

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[] pix = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[w * h];
        bitmap.getPixels(pix, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, w, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, w, h);

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> wm = w - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> hm = h - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> wh = w * h;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> div = radius + radius + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> r[] = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[wh];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> g[] = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[wh];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> b[] = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[wh];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> vmin[] = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[Math.max(w, h)];

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> divsum = (div + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
        divsum *= divsum;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> dv[] = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">256</span> * divsum];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">256</span> * divsum; i++) {
            dv[i] = (i / divsum);
        }

        yw = yi = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[][] stack = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[div][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> stackpointer;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> stackstart;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[] sir;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> rbs;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> r1 = radius + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> routsum, goutsum, boutsum;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> rinsum, ginsum, binsum;

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (y = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; y < h; y++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i = -radius; i <= radius; i++) {
                p = pix[yi + Math.min(wm, Math.max(i, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>))];
                sir = stack[i + radius];
                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] = (p & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff0000</span>) >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>;
                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] = (p & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x00ff00</span>) >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>;
                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>] = (p & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x0000ff</span>);
                rbs = r1 - Math.abs(i);
                rsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] * rbs;
                gsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] * rbs;
                bsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>] * rbs;
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
                    rinsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                    ginsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                    binsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];
                } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                    routsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                    goutsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                    boutsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];
                }
            }
            stackpointer = radius;

            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (x = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; 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[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                goutsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                boutsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];

                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (y == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
                    vmin[x] = Math.min(x + radius + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, wm);
                }
                p = pix[yw + vmin[x]];

                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] = (p & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff0000</span>) >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>;
                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] = (p & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x00ff00</span>) >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>;
                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>] = (p & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x0000ff</span>);

                rinsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                ginsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                binsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];

                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;

                stackpointer = (stackpointer + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) % div;
                sir = stack[(stackpointer) % div];

                routsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                goutsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                boutsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];

                rinsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                ginsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                binsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];

                yi++;
            }
            yw += w;
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (x = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; x < w; x++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
            yp = -radius * w;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i = -radius; i <= radius; i++) {
                yi = Math.max(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, yp) + x;

                sir = stack[i + radius];

                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] = r[yi];
                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] = g[yi];
                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>] = b[yi];

                rbs = r1 - Math.abs(i);

                rsum += r[yi] * rbs;
                gsum += g[yi] * rbs;
                bsum += b[yi] * rbs;

                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
                    rinsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                    ginsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                    binsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];
                } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                    routsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                    goutsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                    boutsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];
                }

                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i < hm) {
                    yp += w;
                }
            }
            yi = x;
            stackpointer = radius;
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (y = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; y < h; y++) {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Preserve alpha channel: ( 0xff000000 & pix[yi] )</span>
                pix[yi] = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff000000</span> & pix[yi]) | (dv[rsum] << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>) | (dv[gsum] << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>) | dv[bsum];

                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;

                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];

                routsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                goutsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                boutsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];

                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (x == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) {
                    vmin[y] = Math.min(y + r1, hm) * w;
                }
                p = x + vmin[y];

                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] = r[p];
                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] = g[p];
                sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>] = b[p];

                rinsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                ginsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                binsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];

                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;

                stackpointer = (stackpointer + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) % div;
                sir = stack[stackpointer];

                routsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                goutsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                boutsum += sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];

                rinsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
                ginsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>];
                binsum -= sir[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>];

                yi += w;
            }
        }

        bitmap.setPixels(pix, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, w, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, w, h);

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (bitmap);
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-si