1. 程式人生 > >高斯模糊效果實現方案及效能對比

高斯模糊效果實現方案及效能對比

高斯模糊實現方案探究

現在越來越多的app在背景圖中使用高斯模糊效果,如yahoo天氣,效果做得很炫。 這裡就用一個demo來談談它的不同實現方式及各自的優缺點。

1. RenderScript

談到高斯模糊,第一個想到的就是RenderScript。RenderScript是由Android3.0引入,用來在Android上編寫高效能程式碼的一種語言(使用C99標準)。 引用官方文件的描述:

RenderScript runtime will parallelize work across all processors available on a device, such as multi-core CPUs, GPUs, or DSPs, allowing you to focus on expressing algorithms rather than scheduling work or load balancing.

為了在Android中使用RenderScript,我們需要(直接貼官方文件,比直譯更通俗易懂):

  • High-performance compute kernels are written in a C99-derived language.
  • A Java API is used for managing the lifetime of RenderScript resources and controlling kernel execution.

上面兩點總結成一句話為:我們需要一組compute kernels(.rs檔案中編寫),及一組用於控制renderScript相關的java api(.rs檔案自動生成為java類)。 由於compute kernels

的編寫需要一定的學習成本,從JELLY_BEAN_MR1開始,Androied內建了一些compute kernels用於常用的操作,其中就包括了Gaussian blur

下面,通過實操來講解一下RenderScript來實現高斯模糊,最終實現效果(講文字背景進行模糊處理):

佈局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

    <ImageView 
        android:id="@+id/picture" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" 
        android:src="@drawable/splash" 
        android:scaleType="centerCrop" />

    <TextView 
        android:id="@+id/text"
        android:gravity="center_horizontal" 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Gaussian Blur"
        android:textColor="@android:color/black"
        android:layout_gravity="center_vertical"
        android:textStyle="bold"
        android:textSize="48sp" />

    <LinearLayout 
        android:id="@+id/controls" 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" 
        android:background="#7f000000" 
        android:orientation="vertical"
        android:layout_gravity="bottom" />
</FrameLayout>

核心程式碼:

private void applyBlur() {
    image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

        @Override
        public boolean onPreDraw() {
            image.getViewTreeObserver().removeOnPreDrawListener(this);
            image.buildDrawingCache();
            Bitmap bmp = image.getDrawingCache();
            blur(bmp, text, true);
            return true;
        }
    });
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void blur(Bitmap bkg, View view) {
    long startMs = System.currentTimeMillis();
    float radius = 20;

    Bitmap overlay = Bitmap.createBitmap((int)(view.getMeasuredWidth()), (int)(view.getMeasuredHeight()), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(overlay);
    canvas.translate(-view.getLeft(), -view.getTop());
    canvas.drawBitmap(bkg, 0, 0, null);

    RenderScript rs = RenderScript.create(SecondActivity.this);

    Allocation overlayAlloc = Allocation.createFromBitmap(rs, overlay);
    ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(rs, overlayAlloc.getElement());
    blur.setInput(overlayAlloc);
    blur.setRadius(radius);
    blur.forEach(overlayAlloc);
    overlayAlloc.copyTo(overlay);
    view.setBackground(new BitmapDrawable(getResources(), overlay));
    rs.destroy();

    statusText.setText("cost " + (System.currentTimeMillis() - startMs) + "ms");
}

當ImageView開始載入背景圖時,取出它的drawableCache,進行blur處理,Gaussian blur的主要邏輯在blur函式中。對於在Java中使用RenderScript,文件中也有詳細描述,對應到我們的程式碼,步驟為:

  • 初始化一個RenderScript Context.
  • 至少建立一個Allocation物件用於儲存需要處理的資料.
  • 建立compute kernel的例項,本例中是內建的ScriptIntrinsicBlur物件.
  • 設定ScriptIntrinsicBlur例項的相關屬性,包括Allocation, radius等.
  • 開始blur操作,對應(forEach).
  • 將blur後的結果拷貝回bitmap中。

此時,我們便得到了一個經過高斯模糊的bitmap。

從上圖可以看到,模糊處理花費了38ms(測試機為小米2s),由於Android假設每一幀的處理時間不能超過16ms(螢幕重新整理頻率60fps),因此,若在主執行緒裡執行RenderScript操作,可能會造成卡頓現象。最好的方式是將其放入AsyncTask中執行。

此外,RenderScript在3.0引入,而一些內建的compute kernelJELLY_BEAN_MR1中引入,為了在低版本手機中使用這些特性,我們不得不引入renderscript_v8相容包,對於手Q安裝包增量的硬性指標,貌似只能放棄JELLY_BEAN_MR1以下的使用者?

有點不甘心,想想別的解決方案吧。

2. FastBlur

由於高斯模糊歸根結底是畫素點的操作,也許在java層可以直接操作畫素點來進行模糊化處理。google一下,果不其然,一個名為stackblur的開源專案提供了名為fastBlur的方法在java層直接進行高斯模糊處理。

ok,現在來改造我們的程式.

private void blur(Bitmap bkg, View view) {
    long startMs = System.currentTimeMillis();
    float radius = 20;

    Bitmap overlay = Bitmap.createBitmap((int)(view.getMeasuredWidth()), (int)(view.getMeasuredHeight()), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(overlay);
    canvas.translate(-view.getLeft(), -view.getTop());
    canvas.drawBitmap(bkg, 0, 0, null);
    overlay = FastBlur.doBlur(overlay, (int)radius, true);
    view.setBackground(new BitmapDrawable(getResources(), overlay));
    statusText.setText("cost " + (System.currentTimeMillis() - startMs) + "ms");
}  

這裡,僅僅是把RenderScript相關的操作換成了FastBlur提供的api。效果圖如下:

效果還不錯,與RenderScript的實現差不多,但花費的時間卻整整多了2倍多,這完全是無法接受的。好吧,只能繼續探究。

3. AdvancedFastBlur

stackOverflow對於程式設計師來說永遠是最大的寶藏。http://stackoverflow.com/questions/2067955/fast-bitmap-blur-for-android-sdk這篇提問帖終於提供了新的解決思路:

This is a shot in the dark, but you might try shrinking the image and then enlarging it again. This can be done with Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter). Make sure and set the filter parameter to true. It'll run in native code so it might be faster.

它所表述的原理為先通過縮小圖片,使其丟失一些畫素點,接著進行模糊化處理,然後再放大到原來尺寸。由於圖片縮小後再進行模糊處理,需要處理的畫素點和半徑都變小,從而使得模糊處理速度加快。 瞭解原理,繼續改善:

private void blur(Bitmap bkg, View view) {
    long startMs = System.currentTimeMillis();
    float radius = 2;
    float scaleFactor = 8;

    Bitmap overlay = Bitmap.createBitmap((int)(view.getMeasuredWidth()/scaleFactor), (int)(view.getMeasuredHeight()/scaleFactor), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(overlay);
    canvas.translate(-view.getLeft()/scaleFactor, -view.getTop()/scaleFactor);
    canvas.scale(1 / scaleFactor, 1 / scaleFactor);
    Paint paint = new Paint();
    paint.setFlags(Paint.FILTER_BITMAP_FLAG);
    canvas.drawBitmap(bkg, 0, 0, paint);
    overlay = FastBlur.doBlur(overlay, (int)radius, true);
    view.setBackground(new BitmapDrawable(getResources(), overlay));
    statusText.setText("cost " + (System.currentTimeMillis() - startMs) + "ms");
} 

最新的程式碼所建立的bitmap為原圖的1/8大小,接著,同樣使用fastBlur來進行模糊化處理,最後再為textview設定背景,此時,背景圖會自動放大到初始大小。注意,由於這裡進行了縮放,radius的取值也要比之前小得多(這裡將原始取值除以8得到近似值2)。下面是效果圖:

驚呆了有木有!!效果一樣,處理速度卻快得驚人。它相對於renderScript方案來說,節省了拷貝bitmap到Allocation中,處理完後再拷貝回來的時間開銷。

4. Warning

由於FastBlur是將整個bitmap拷貝到一個臨時的buffer中進行畫素點操作,因此,它不適合處理一些過大的背景圖(很容導致OOM有木有~)。對於開發者來說,RenderScript方案和FastBlur方案的選擇,需要你根據具體業務來衡量!

相關推薦

模糊效果實現方案效能對比

高斯模糊實現方案探究 現在越來越多的app在背景圖中使用高斯模糊效果,如yahoo天氣,效果做得很炫。 這裡就用一個demo來談談它的不同實現方式及各自的優缺點。 1. RenderScript 談到高斯模糊,第一個想到的就是RenderScript。RenderScrip

Android使用RenderScript實現圖片的模糊效果

Android使用RenderScript實現圖片的高斯模糊效果 首先來看一下什麼是高斯模糊效果呢? 高斯模糊(英語:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NET等影象處理軟體中廣泛使用的處理效果,通常用它

使用canvas實現區域性模糊效果

這個功能目的是為了模糊一些人的臉部,一些文字資訊。主要用於使用者手動操作進行模糊。 實現的功能:本人實現了再pc端上面進行拖拽模糊。 實現思路: 首先載入圖片,然後再載入完成的回撥中,建立一個高斯模糊過的圖片畫布。 接著,繫結滑鼠的互動事件,在裡面獲取到在畫布

iOS自帶實現模糊效果

引 什麼叫高斯模糊效果,通俗地說,就是毛玻璃效果,從iOS 7以來,就頻繁地被設計使用,如果用得好,效果會顯得非常的好。我們來看一個例子: 圖中下面一小部分就是高斯模糊效果。要實現也很簡單,iOS自身就支援這種效果。 iOS 7 UIToolbar

【iOS】iOS下模糊效果實現

其實有很多種實現方式,但是沒必要了解那麼多,簡單實用就行,選取一種效能相對來說比較好的方式 效果圖如下(高斯0.1): 程式碼: 需要匯入 #import <Accelerate/Accelerate.h> UIImage *ima

Android 模糊效果從319ms到3ms的優化實現

之前做過高斯模糊的的效果,不過依賴一個三方庫,今天看到了一篇文章,一個類檔案就能解決,感覺竊喜,分享給大家。 使用: Glide.with(getActivity()).load(mUser.avatarUrl).asBitmap().into(ne

關於模糊的詳細介紹python程式碼實現

講的是Gaussian Blur,講的很詳細,值得仔細閱讀! python最常用的影象處理庫是PIL(PythonImaging Library),它內建了高斯模糊方法,簡單程式碼如下: import Image import ImageFilter im=Ima

Android也能流暢實現毛玻璃效果(模糊)效果

前言 上圖就是我們在IOS裝置上經常能夠見到的毛玻璃(高斯模糊)效果。不得不說,這種效果在適合的場景下使用,能夠獲得絕佳的美感。但是鑑於Android裝置效能和相容性問題,我們通常很難在Android裝置上見到這種效果。 但這並不是IOS的專利效果,Android

CSS: filter: blur(); 實現模糊效果,不可不知的細節優化

前言 在專案中,要實現如下的效果: 頁面頂部的設計稿,前面一個卡片式的輪播,後邊的背景(是橢圓的一部分)取前面的圖片,進行一個高斯模糊的處理。 開始 前面的輪播部分,使用了第三方的輪播外掛,非常好用,推薦給大家(地址)。輪播,不作為今天的主要內容,暫時簡單描述下,

【複習筆記】 cocos2d-x 2.x 渲染特效實現模糊效果

在上文末,我們已經完成了高斯模糊橫向上的模糊效果,而且提到,縱向模糊要在橫向模糊的結果上進行,所以為了得到橫向模糊的貼圖,我們使用離屏渲染。顧名思義,現在渲染的目的地不是螢幕了~一般狀況下,gl是直接把渲染好的紋理繪製到螢幕緩衝區的,進而直接顯示在螢幕上。但是現在,我們要把

Shader2.0-模糊實現

要實現高斯模糊,大致的思路是,當某個遊戲物體渲染完成後,將該遊戲物體交給Shader進行二次渲染,從而實現高斯模糊,C#中有一個回撥函式OnRenderImage,這個函式會在渲染完成後呼叫,我們可以在這個函式中呼叫Graphics.Blit方法會把傳進來的圖片與第三個引數中的材質進行二次計算,

iOS開發-圖片模糊效果

iOS開發的時候有的時候需要將圖片設定模糊,或者通過點選下拉方法,去除模糊,一切都是為了應用更受使用者歡迎,iOS7之後半透明模糊效果得到大範圍使用的比較大,現在也可以看到很多應用區域性用到了圖片模糊效果,關於圖片實現高斯模糊效果有三種方式,CoreImage,GPUImag

模糊效果

高斯模糊可以實現模糊效果,可用於眩暈,場景動畫等效果 高斯模糊利用了卷積計算,把每個畫素和周圍的畫素混合   見程式碼實現 c#程式碼 ImageEffectBase using UnityEngine; namespace GameBase.Effe

普通模糊,動感模糊模糊演算法實現

     模糊演算法在實際應用中經常回碰到,這裡總結下幾種模糊演算法,以便將來的需要。      #ifdef GL_ES precision mediump float; #endif uniform float mode;//0普通模糊 1高斯模糊 2動感模糊 unif

圖片模糊效果簡單優化

       模糊背景現在已經很流行了,固定圖片的模糊可以讓設計師處理,那麼動態模糊,或者每個使用者個人主頁用自己頭像的圖片模糊做背景,這就需要我們程式設計師通過程式碼來實現了,實現的方案在github上已經有比較完善和得到大家公認的開源專案: Blurry 。前者主要通過

圖片處理的幾種演算法(毛玻璃效果模糊效果,舊時光效果,lomo效果,暖意效果)

毛玻璃效果:高斯模糊效果: //高斯模糊,毛玻璃 //低於Android4.2可以用Java原生程式碼實現。但是效率會低不少:這完全是一種妥協的方式,不推薦 public Bitmap fastblur(Context context, Bitmap sentBitma

Android中為網路圖片設定模糊效果

寫一個方法,用來對Bitmap進行高斯模糊: public static Bitmap blurBitmap(Bitmap bitmap ,Context context){ //Let

Android開發 模糊實現

同類參考文章:戳我 戳我 高斯模糊是什麼? 高斯模糊(英語:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NET等影象處理軟體中廣泛使用的處理效果,通常用它來減少影象噪聲以及降低細節層次。這種模糊技術生成的影象,其

Android——圖片設定為模糊效果(ImageView)

效果圖://模糊 Resources res = ShowActivity.this.getResources(); //拿到初始圖 Bitmap bmp= BitmapFactory.decodeRe

模糊實現方法

轉載;http://blog.csdn.net/markl22222/article/details/10313565   一、高斯模糊是什麼 模糊演算法,不論是使用哪種演算法,目的都是為了讓圖片看起來不如原來那麼清晰。 清晰的圖片,畫素間的過渡會較為乾脆利落,簡