Android實現動態高斯模糊效果_Android

來源:互聯網
上載者:User

高斯模糊是什嗎?

高斯模糊(英語:Gaussian Blur),也叫高斯平滑,是在Adobe Photoshop、GIMP以及Paint.NET等影像處理軟體中廣泛使用的處理效果,通常用它來減少映像雜訊以及降低細節層次。這種模糊技術產生的映像,其視覺效果就像是經過一個半透明螢幕在觀察映像,這與鏡頭焦外成像效果散景以及普通照明陰影中的效果都明顯不同。

什嗎?看不明白?沒關係,我也看不明白,維基百科複製回來的嘛。我們直接放一些圖片來瞭解以下這個高斯模糊是怎麼樣的。因為高斯模糊在iOS中最常見,這裡抓了幾張iOS網易雲的圖片:

可以看到這個介面中的背景,其實就是通過圖1中間那個小圖片模糊得到的,這樣做的好處就是整體性很好,並且不會因為圖片過渡突兀而影響介面內容的閱讀。

那麼,究竟在Android上怎麼去實現這個效果呢?這裡推薦使用官方提供在Support Library中的一個工具來做,就是RenderScript。這個RenderScript的功能其實不止有這一個,而其他的一些功能,可以在官方文檔中閱讀學習,這裡不給出。

使用這個工具的原因其實很簡單,就是效能。因為涉及到繪圖,所以如果效能不行,那麼無論對於高品質圖片或者是變化較多的需求都是很吃力的,而這個工具則會充分發揮裝置的計算能力(CPU和GPU)來進行計算,並且是使用C99衍生語言進行指令碼編寫的,相較於Java效能是大大的提升。

說到這裡,有些同學就開始方了,C99衍生?What?這個不需要擔心,對於高斯模糊這個實現,Google官方已經給出了對應的解決方案,我們並不需要編寫對應的指令碼就可以使用了,所以無需擔心。

 我們把整個問題分為兩個部分:

    ①高斯模糊實現;

    ②動態高斯模糊實現 

① 高斯模糊實現

首先要說明,我們要使用Support Library,所以版本是有要求的:

     Android SDK Tools 版本必須大於等於22.2

     Android SDK Build-tools 版本必須大於等於18.1.0

如果沒有達到,請使用SDK Manager升級一下。

接著建立我們的工程,並且在對應Module(預設建立的是app)的build.gradle檔案中加入如下代碼:

defaultConfig {    ...    renderscriptTargetApi 18    renderscriptSupportModeEnabled true  }

renderscriptTargetApi:這個一般和App支援的最低版本相同即可。

package com.fndroid.renderscriptdemo;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.renderscript.Allocation;import android.renderscript.Element;import android.renderscript.RenderScript;import android.renderscript.ScriptIntrinsicBlur;import android.support.v7.app.AppCompatActivity;import android.widget.ImageView;public class MainActivity extends AppCompatActivity {  private ImageView mImageView;  private Bitmap sampleImg;  private Bitmap gaussianBlurImg;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    mImageView = (ImageView) findViewById(R.id.iv);    sampleImg = BitmapFactory.decodeResource(getResources(), R.drawable.icon); // 擷取原圖    gaussianBlurImg = blur(sampleImg, 25f);    mImageView.setImageBitmap(gaussianBlurImg);  }  private Bitmap blur(Bitmap bitmap,float radius) {    Bitmap output = Bitmap.createBitmap(bitmap); // 建立輸出圖片    RenderScript rs = RenderScript.create(this); // 構建一個RenderScript對象    ScriptIntrinsicBlur gaussianBlue = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); // 建立高斯模糊指令碼    Allocation allIn = Allocation.createFromBitmap(rs, bitmap); // 建立用於輸入的指令碼類型    Allocation allOut = Allocation.createFromBitmap(rs, output); // 建立用於輸出的指令碼類型    gaussianBlue.setRadius(radius); // 設定模糊半徑,範圍0f<radius<=25f    gaussianBlue.setInput(allIn); // 設定輸入指令碼類型    gaussianBlue.forEach(allOut); // 執行高斯模糊演算法,並將結果填入輸出指令碼類型中    allOut.copyTo(output); // 將輸出記憶體編碼為Bitmap,圖片大小必須注意    rs.destroy(); // 關閉RenderScript對象,API>=23則使用rs.releaseAllContexts()    return output;  }}

這裡說明都注釋在代碼中了。需要瞭解的是RenderScript有兩個版本,分別是:

     android.renderscript

     android.support.v8.renderscript

上面代碼使用了第一個,第二個的用法類似,可以自行嘗試。

我們來理一下思路,因為RenderScript是依賴於Script的,而上文也說到了,Script是由C99衍生語言編寫,而代碼中的ScriptIntrinsicBlur就是對應於高斯模糊演算法的指令碼。而Allocation對象則是將Java中的對象轉換為Script指令碼所需類型的幫手,代碼中建立了兩個Allocation對象分別用來充當輸入和輸出。接著設定了高斯模糊的半徑(radius)。當調用forEach時,指令碼會被執行,並且將執行結果填入輸出對應的Allocation中,最後調用copyTo來轉換為Bitmap對象返回。

效果圖:

 

② 動態高斯模糊

很多時候,我們可能會需要一個圖片以不同的模糊程度展現出來。你可能已經注意到上面方法中的模糊半徑了,我們可以做一個實驗,就是通過一個SeekBar來動態改變這個值看看效果:

 

由動圖可以看到,我們拖動SeekBar的時候,SeekBar已經跟不上我們的拖動了。這是為什嗎?原因就是這個渲染工具雖然效能比較優異,但是如果圖片的品質和尺寸都較高的時候,我們直接進行修改模糊半徑重新渲染的做法往往時不可取的。

做法是,先建立一張模糊的圖片載入在ImageView中,接著在這個ImageView的上面再放置一個載入原圖ImageView,使用FrameLayout可以讓這兩個ImageView重疊再一起,接著當我們需要動態改變模糊程度的時候,改變上層的ImageViewBitmapAlpha就可以了。我們先看看效果圖:

 

使用了這個方法,滑動起來就會比較流暢了。(GIF載入完才是會是正常速度哦

這裡給一下代碼參考吧:

public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener {  private ImageView mImageView;  private ImageView mImageViewCover;  private Bitmap sampleImg;  private Bitmap gaussianBlurImg;  private SeekBar mSeekBar;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    mImageView = (ImageView) findViewById(R.id.iv);    mSeekBar = (SeekBar) findViewById(R.id.sb);    mImageViewCover = (ImageView) findViewById(R.id.iv_cover);    sampleImg = BitmapFactory.decodeResource(getResources(), R.drawable.icon); // 擷取原圖    gaussianBlurImg = blur(sampleImg, 25f);    mImageView.setImageBitmap(gaussianBlurImg);    mSeekBar.setOnSeekBarChangeListener(this);  }  private Bitmap blur(Bitmap bitmap, float radius) {    Bitmap output = Bitmap.createBitmap(bitmap); // 建立輸出圖片    RenderScript rs = RenderScript.create(this); // 構建一個RenderScript對象    ScriptIntrinsicBlur gaussianBlue = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); //    // 建立高斯模糊指令碼    Allocation allIn = Allocation.createFromBitmap(rs, bitmap); // 開闢輸入記憶體    Allocation allOut = Allocation.createFromBitmap(rs, output); // 開闢輸出記憶體    gaussianBlue.setRadius(radius); // 設定模糊半徑,範圍0f<radius<=25f    gaussianBlue.setInput(allIn); // 設定輸入記憶體    gaussianBlue.forEach(allOut); // 模糊編碼,並將記憶體填入輸出記憶體    allOut.copyTo(output); // 將輸出記憶體編碼為Bitmap,圖片大小必須注意    rs.destroy(); // 關閉RenderScript對象,API>=23則使用rs.releaseAllContexts()    return output;  }  @Override  public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {    int alpha = 255 - progress;    mImageViewCover.setImageAlpha(alpha);  }  @Override  public void onStartTrackingTouch(SeekBar seekBar) {  }  @Override  public void onStopTrackingTouch(SeekBar seekBar) {  }}

布局檔案:

<?xml version="1.0" encoding="utf-8"?><LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:app="http://schemas.android.com/apk/res-auto"  xmlns:tools="http://schemas.android.com/tools"  android:id="@+id/activity_main"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical"  tools:context="com.fndroid.renderscriptdemo.MainActivity">  <FrameLayout    android:layout_width="match_parent"    android:layout_height="0dp"    android:layout_weight="1">    <ImageView      android:id="@+id/iv"      android:layout_width="match_parent"      android:layout_height="match_parent"/>    <ImageView      android:id="@+id/iv_cover"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:src="@drawable/icon"/>  </FrameLayout>  <SeekBar    android:id="@+id/sb"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:max="255"/></LinearLayout>

總結

以上就是在Android中實現動態高斯模糊的全部內容,本文先是介紹了如何?高斯模糊,而後才介紹實現動態效果,這樣讓大家更容易理解學習,希望本文對大家開發Android有所協助。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.