摘要:今天就來研究一下如何在上實現高斯模糊效果。平時我們對圖片縮小,必然會帶來很明顯的清晰度的損失,但高斯模糊本身的目的就是要實現模糊的效果,因此實際上的效果差別不大,幾乎可以忽略。
前言
從 iOS 7 開始 Apple 從 擬物化 過渡到了 扁平化 的設計風格,同時也搭配使用了 毛玻璃風格 當做背景效果,不得不說十分驚艷,頗有當時pc上 Widows Vista 和 OS X Yosemite 的味道,在那之后,Google 也從 Android L(5.0)開始使用了 原質化設計(Material Design) 設計語言,與 Microsoft 的 Metro 那種純扁平化風格看似很相像,但實則因為引用了 Z軸 的概念,使其有了陰影和立體感,傳達了 響應式交互 的設計理念。說到這里有一些跑題,因為筆者對設計美學很感興趣,所以對這些平臺都稍微了解一些皮毛。今天就來研究一下如何在 Android 上實現高斯模糊效果。
目前 Android 上實現高斯模糊效果的方式有:Java : FastBlur.java ,應用非常廣泛的 StackBlur 模糊算法實現代碼,效率最低
C++ :兩種實現,1:標準高斯模糊算法 2:均值模糊,效率中等
Android : RenderScript ,用來在 Android 上編寫高性能代碼的一種語言(使用C99標準,運行時機器再次優化編譯, 可以均衡的運行在多個CPU 和 GPU上,有一個半徑限制小于25的限制),效率最高
簡單聊聊 FastBlur因為效果的實現是基于 Java 的,所以有必要先來了解一下方法如何使用。
public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap)
可以看出,使用方法非常簡單,傳入待虛化的bitmap、虛化程度(一般為8)、是否重用flag,最后返回模糊后的bitmap。
但如果直接把一張大圖傳入進行虛化,很容易就會產生OOM內存溢出,那就意味著我只能虛化小圖,這樣才能防止內存溢出。但是我并不想換其他圖,那么,我們就應該把這張圖縮小。
平時我們對圖片縮小,必然會帶來很明顯的清晰度的損失,但高斯模糊本身的目的就是要實現模糊的效果,因此實際上的效果差別不大,幾乎可以忽略。
同時由于圖片縮小后再進行模糊處理,需要處理的像素點和半徑都變小,從而使得模糊處理速度加快。
ReScalepublic static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) {}
我們可以利用Bitmap的 createScaledBitmap() 方法來進行bitmap的縮放。其中前三個參數很明顯,其中寬高我們可以選擇為原圖尺寸的1/5;第四個filter是指縮放的效果,filter為true則會得到一個邊緣平滑的bitmap,反之,則會得到邊緣鋸齒、pixelrelated的bitmap。這里我們要對縮放的圖片進行虛化,所以無所謂邊緣效果,filter=false。
所以,我們要使用
int scaleRatio = 5;// 縮放比例 此處代表1/5 int blurRadius = 8;// 虛化程度 Bitmap scaledBitmap = Bitmap.createScaledBitmap(originBitmap, originBitmap.getWidth() / scaleRatio, originBitmap.getHeight() / scaleRatio, false); Bitmap blurBitmap = FastBlur.doBlur(scaledBitmap, blurRadius, true); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setImageBitmap(blurBitmap);
可以得到如下效果:
從圖中可以看出,首先可以確定思路是對的;然后,可以看出毛玻璃效果還不是特別的明顯。為了得到如iOS那樣的虛化效果,我們有兩種方法:
增大scaleRatio縮放比,使用更小的bitmap去虛化可以得到更好的模糊效果,而且有利于占用內存的減小;
增大blurRadius,可以得到更高程度的虛化,不過會導致CPU更加intensive
這里筆者通過增大縮放比來實驗。
scaleRatio = 10
scaleRatio = 20
通過上面對比圖我們可以找出最適合自己的虛化效果。
再來聊聊 RenderScriptRenderScript 主要 在Android中的對圖形進行處理,RenderScript 采用C99語法進行編寫,主要優勢在于性能較高。在 API 11 的時候被加入到 Android 中。同時,Google提供了android.support.v8.renderscript兼容包,能夠實現更低版本的兼容。
RenderScript 提供了一個用于實現高斯模糊的封裝類 ScriptIntrinsicBlur ,因為在 API 17 后才正式適配到 Android ,所以在不使用兼容包的情況下只能兼容到4.2的設備。但是,我們有兼容包啊向下兼容不是夢。
準備階段 引入兼容包方法很簡單,只需在build.gradle中加入:
defaultConfig { .... // 就是這么簡單 renderscriptTargetApi 19 renderscriptSupportModeEnabled true }
另外由于一些廠商會深度定制Android系統,所以一些必要的依賴文件會被他們直接去掉,這導致一些型號的設備上調用RenderScriptd的部分方法時會報錯。遇到這種兼容問題的話,需要加上這些可能丟失的文件。
其實也簡單,打開android_sdk/build-tools/選擇19以上版本/renderscript/lib/packaged我們可以看見3個包含.so文件的文件夾。
直接復制這三個文件加到項目工程的 jniLibs 包下,沒有的話去建一個。
如果首次創建 jniLibs 文件夾,還需要在 build.gradle 的 android{} 中加入:
sourceSets { main { jniLibs.srcDirs = ["jniLibs"] } }
針對使用的混淆的同學,需要在混淆中加入:
-keep class android.support.v8.renderscript.** { *; }實現高斯模糊
將核心實現方法 ScriptIntrinsicBlur 封裝成工具類。
import android.support.v8.renderscript.*; // 需要導入v8包,否則無法向下兼容 public class BlurBitmapUtil { /*** * 圖片縮放比例 (例如 1/10) */ private static int scaleRatio = 10; /** * 對圖片進行高斯模糊 * * @param context 上下文對象 * @param image 需要模糊的圖片 * @param blurRadius 模糊半徑,由于性能限制,這個值的取值區間為(0至25f) * @return 模糊處理后的圖片 */ public static Bitmap blurBitmap(Context context, Bitmap image, @FloatRange(from = 1, to = 25) float blurRadius) { // 計算圖片縮小后的長寬 int width = Math.round(image.getWidth() / scaleRatio); int height = Math.round(image.getHeight() / scaleRatio); // 創建一張縮小后的圖片做為渲染的圖片 Bitmap bitmap = Bitmap.createScaledBitmap(image, width, height, false); // 創建RenderScript內核對象 RenderScript rs = RenderScript.create(context); // 創建一個模糊效果的RenderScript的工具對象,第二個參數Element相當于一種像素處理的算法,高斯模糊的話用這個就好 ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); // 由于RenderScript并沒有使用VM來分配內存,所以需要使用Allocation類來創建和分配內存空間 // 創建Allocation對象的時候其實內存是空的,需要使用copyTo()將數據填充進去 Allocation input = Allocation.createFromBitmap(rs, bitmap); // 創建相同類型的Allocation對象用來輸出 Type type = input.getType(); Allocation output = Allocation.createTyped(rs, type); // 設置渲染的模糊程度, 25f是最大模糊度 blurScript.setRadius(blurRadius); // 設置blurScript對象的輸入內存 blurScript.setInput(input); // 將輸出數據保存到輸出內存中 blurScript.forEach(output); // 將數據填充到bitmap中 output.copyTo(bitmap); // 銷毀它們釋放內存 input.destroy(); output.destroy(); blurScript.destroy(); rs.destroy(); type.destroy(); return bitmap; }
使用 RenderScript 增加虛化程度的方法和 FastBlur 一樣,有兩種方法:
增大scaleRatio縮放比,使用更小的bitmap去虛化可以得到更好的模糊效果,而且有利于占用內存的減小;
增大blurRadius,可以得到更高程度的虛化,不過會導致虛化時間變長
但因為 RenderScript 的天然優勢(低級語言, 運行時機器再次優化編譯, 可以均衡的運行在多個CPU 和 GPU上),所以這里筆者通過增大虛化程度來實驗,縮放比例為 1/10,實際運用時可以根據需求在對虛化程度和縮放比例上采取一個合適的數值。
blurRadius = 5
blurRadius = 15
blurRadius = 25
通過上面對比圖我們可以找出最適合自己的虛化效果。
目前來看,為何 Google 設置這個25的限制, 原因應該有兩個 :
半徑大于25的話耗時就成為了一個瓶頸;
如果想實現大于25的模糊效果,可以通過縮小原圖,模糊,再放大來達到同樣的效果
總結以上就是如何用 FastBlur 和 RenderScript 在 Android 上實現和 iOS 一樣的高斯模糊效果的簡單介紹,雖然在性能上毋庸置疑是 RenderScript 上最好,但是在一些使用場景上 FastBlur 耗時會更短,所以我們各取所需,根據實際需求去選擇使用。
另一種可能性上面說的2種解決方案都是從性能和效率出發的產物,但如果我的需求就是從網絡上加載一張圖片(比如頭像),然后再高斯模糊化當背景,走一遍轉換成bitma再將其轉換成高斯模糊的流程或許會有一點點麻煩,這里我再提供一種簡單快捷的解決方案 —— 基于Glid加載框架去實現一鍵 加載網絡圖片→高斯模糊化→展示。
引入兼容包首先在build.gradle中加入圖片框架需要的庫和圖片工具庫:
defaultConfig { .... compile "com.yutianran.maven:super-adapter:1.0.0" compile "jp.wasabeef:glide-transformations:2.0.2" }然后就開寫,一行代碼即可
Glide.with(this).load(url).bitmapTransform(new BlurTransformation(this,25)).into(imageView);
需要的參數很分別是
上下文對象
圖片url
上下文對象,虛化數值
imageView控件
效果如上,可以看出 glide-transformations 庫的虛化效果也是十分不錯的,但對圖片本身做的縮放應該不是很多,所以在加載速度上會弱于 FastBlur 和 RenderScript ,但作為輕量級圖片而言足夠了。
Code相關代碼已上傳至Github:BlurView,歡迎Star,Fork。
參考文獻[[譯] RenderScript:簡單而快速的圖像處理](https://toutiao.io/posts/44zw...
圖片高斯模糊效果簡單優化
高斯模糊效果實現方案及性能對比
Android:簡單靠譜的動態高斯模糊效果
教你一分鐘實現動態模糊效果
什么?IOS的專利?Android也能流暢實現毛玻璃效果(高斯模糊)效果
Android 高斯模糊總結
Android RenderScript 簡單高效實現圖片的高斯模糊效果
干貨 一種快速毛玻璃虛化效果實現--Android
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66982.html
摘要:毛玻璃效果相信很多朋友都眼紅很久了,隔壁系統對高斯模糊早就大范圍使用了,咱們卻絲毫不為所動,于是就只能靠廣大開發者咯。 毛玻璃效果相信很多朋友都眼紅很久了,隔壁ios系統對高斯模糊早就大范圍使用了,咱們Android卻絲毫不為所動,于是就只能靠廣大開發者咯。 這是目前市面上性能最高的方案,也不知道最初是哪位大神寫的,我也只是拿來封裝一下,變得更簡單、更好用,加上了陰影遮罩的效果。 先來...
閱讀 914·2019-08-30 15:54
閱讀 1474·2019-08-30 15:54
閱讀 2404·2019-08-29 16:25
閱讀 1298·2019-08-29 15:24
閱讀 755·2019-08-29 12:11
閱讀 2513·2019-08-26 10:43
閱讀 1233·2019-08-26 10:40
閱讀 473·2019-08-23 16:24