天天看點

圖像處理------快速均值模糊(Box Blur)

圖像模糊的本質, 從數字信号處理的角度看,圖像模糊就要壓制高頻信号保留低頻信号,

壓制高頻的信号的一個可選擇的方法就是卷積濾波。選擇一個低頻濾波器,對圖像上的

每個像素實作低頻濾波,這樣整體效果就是一張數字圖像更加的模糊,顯示更少的細節資訊。

 傳統的卷積模糊計算量巨大,程式效率比較低,基于滑動視窗的box blur是一種快速模糊方法,

其結果近似于卷積模糊的結果。我沒證明過!

一:box blur數學原理

根據輸入的半徑r,計算起始2*r +1個像素的平均值, 作為第一個輸出像素的結果,

公式可以表示為

像素 x0 =  其中k代表輸入像素集合, i的取值範圍為 i∈[-r, r]

然後計算每一行輸出像素的值根據xi = x0 + (k[index + r + 1] – k[index - r])

二:box blur的特征

box blur是一種快速的圖像模糊技術, 相比于傳統的卷積模糊,box blur可以更有效率的

完成對圖像模糊, 模糊的程度取決一下三個輸入參數,

1.      x方向上半徑 h radius

2.      y方向上半徑 v radius

3.      疊代次數 iteration number

在半徑相同的情況下, 疊代次數越多,輸出的圖像就越模糊

在疊代次數相同的情況下, 像素半徑越大, 輸出的圖像就越模糊

上述兩者之間的不同是對圖像的拉伸效果, 半徑越大,對圖像的拉伸效果越顯著

box模糊利用滑動視窗算法,進而簡化了每次計算平均值帶來額外開銷。

從數字圖像和信号處理的角度看, box blur是一種不折不扣的低通濾波, 但是它并不

是真正的高斯低通濾波, 不是卷積實作, 因而速度更快。

 當水準和垂直半徑分别為1 時,是典型的3*3 的矩陣卷積

1, 1, 1

計算, 相比于傳統的卷積計算之後,要進行歸一化處理,box計算過程中已經完成像素平均,

無需歸一化處理。

圖像處理------快速均值模糊(Box Blur)

三:基于滑動視窗算法的box模糊效果

水準和垂直方向

圖像處理------快速均值模糊(Box Blur)

垂直方向:

圖像處理------快速均值模糊(Box Blur)

水準方向:

圖像處理------快速均值模糊(Box Blur)

四:程式關鍵代碼解析

注釋已經很詳細的寫在代碼中,最重要的一個步驟是提前建立index,根據index來找到平均值。

<span style="font-weight: normal;">    public static void blur( int[] in, int[] out, int width, int height, int radius ) {  

        int widthminus1 = width-1;  

        int tablesize = 2*radius+1;  

        int divide[] = new int[256*tablesize];  

        // the value scope will be 0 to 255, and number of 0 is table size  

        // will get means from index not calculate result again since   

        // color value must be  between 0 and 255.  

        for ( int i = 0; i < 256*tablesize; i++ )  

            divide[i] = i/tablesize;   

        int inindex = 0;  

        //   

        for ( int y = 0; y < height; y++ ) {  

            int outindex = y;  

            int ta = 0, tr = 0, tg = 0, tb = 0; // argb -> prepare for the alpha, red, green, blue color value.  

            for ( int i = -radius; i <= radius; i++ ) {  

                int rgb = in[inindex + imagemath.clamp(i, 0, width-1)]; // read input pixel data here. table size data.  

                ta += (rgb >> 24) & 0xff;  

                tr += (rgb >> 16) & 0xff;  

                tg += (rgb >> 8) & 0xff;  

                tb += rgb & 0xff;  

            }  

            for ( int x = 0; x < width; x++ ) { // get output pixel data.  

                out[ outindex ] = (divide[ta] << 24) | (divide[tr] << 16) | (divide[tg] << 8) | divide[tb]; // calculate the output data.  

                int i1 = x+radius+1;  

                if ( i1 > widthminus1 )  

                    i1 = widthminus1;  

                int i2 = x-radius;  

                if ( i2 < 0 )  

                    i2 = 0;  

                int rgb1 = in[inindex+i1];  

                int rgb2 = in[inindex+i2];  

                ta += ((rgb1 >> 24) & 0xff)-((rgb2 >> 24) & 0xff);  

                tr += ((rgb1 & 0xff0000)-(rgb2 & 0xff0000)) >> 16;  

                tg += ((rgb1 & 0xff00)-(rgb2 & 0xff00)) >> 8;  

                tb += (rgb1 & 0xff)-(rgb2 & 0xff);  

                outindex += height; // per column or per row as cycle...  

            inindex += width; // next (i+ column number * n, n=1....n-1)  

        }  

    }</span>  

繼續閱讀