歡迎你們前往雲+社區,獲取更多騰訊海量技術實踐乾貨哦~git
由 每天P圖攻城獅 發佈在雲+社區程序員
做者簡介:damonxia(夏正冬),每天P圖Android工程師github
高斯模糊是圖像處理中幾乎每一個程序員都或多或少聽過的名詞,可是對其原理你們可能並不瞭解,只知道經過高斯模糊能實現圖像毛玻璃效果。算法
本文首先介紹圖像處理中最基本的概念:卷積;隨後介紹高斯模糊的核心內容:高斯濾波器;接着,咱們從頭實現了一個Java版本的高斯模糊算法,以及實現RenderScript版本。因爲咱們本身實現的Java版本的高斯模糊算法的效率過低,所以最後介紹比較有名的高斯模糊的開源項目:Blurry以及BlurKit-Android。框架
BlurDemo是本文的配套Demo:異步
本文只討論圖像,而圖像能夠表示爲二維矩陣,其中每一個元素爲ARGB像素值,所以這裏討論二維矩陣的卷積操做。卷積(Convolution)是圖像處理中最基本的操做,就是一個二維矩陣A(M*N)和一個二維矩陣B(m*n)作若干操做,生成一個新的二維矩陣C(M*N),其中m和n遠小於M和N,B稱爲卷積核(kernel),又稱濾波器矩陣或模板。函數
這裏舉個卷積的例子,如圖:性能
上圖中,最左邊的是源矩陣(8*8),中間是卷積核(3*3,半徑爲1),最右邊是經過對前面兩個矩陣作卷積生成的結果矩陣。圖中,若是咱們要求出結果矩陣中第二行第二列的元素的值,則把卷積核的中心元素(值爲0)和源矩陣的第二行第二列(值爲6)對齊,而後求加權和,即圖中的公式,最後獲得-3。gradle
咱們再舉一個例子:優化
上圖也展現瞭如何作卷積的過程,好比要求出結果矩陣中第一行第一列的值,則把卷積核的中心對準源矩陣的第一行第一列,發現部分區域超出源矩陣的範圍了(圖中紅色部分),解決方法有不少,這裏的方案是:用邊界值填充。接着作加權和,結果爲-5。接着用一樣的方法依次計算結果矩陣的每一個元素便可。
一般來講卷積核須要知足:
均值濾波器(Mean Filter)是最簡單的一種濾波器,它是最粗糙的一種模糊圖像的方法,高斯濾波是均值濾波的高級版本。實際上不一樣的濾波器就是經過改變卷積核(濾波器),從而改變最後的結果矩陣,中間步驟都同樣,都是求加權和。均值濾波器的卷積核一般是m*m的矩陣,其中每一個元素爲1/(m^2),能夠看出卷積核的元素總和爲1。好比3*3的均值濾波器,卷積核的每一個元素就是1/9。
高斯濾波器是均值濾波器的高級版本,惟一的區別在於,均值濾波器的卷積核的每一個元素都相同,而高斯濾波器的卷積核的元素服從高斯分佈。
高斯濾波器是基於二維的高斯分佈函數,所以首先介紹二維高斯分佈函數。二維高斯分佈函數和圖以下:
其中x和y表示卷積核中某個元素橫座標和縱座標距離中心點的距離。sigma控制曲線的平緩程度,值越大,越平緩,最高點越低。咱們能夠輕易看出當x=0且y=0時值最大,即卷積核的中心點權重最大。
好比卷積核中一個元素距離中心點,橫向距離2,縱向距離1,那麼x=2,y=1,就能求出該元素的值。固然爲了保證卷積核元素總和爲1,最後每一個元素都須要除以卷積核中全部元素之和。
怎麼肯定卷積核的大小呢?肯定sigma以後,雖然無論距離中心點多遠,該元素的高斯分佈函數值總爲非負數,可是根據經驗,卷積核的半徑定爲3*sigma,所以寬高爲6*sigma+1。
若是高斯濾波器的卷積核是二維的(m*n),則算法複雜度爲O(m*n*M*N),複雜度較高,所以接下來咱們對算法複雜度進行優化。
一維的高斯分佈函數和圖以下:
實際上,二維高斯分佈函數能夠分解爲兩個一維高斯分佈函數相乘,以下:
所以本來的源矩陣和二維卷積核作卷積等價於源矩陣先與1*m的一維卷積核作卷積,再與m*1的一維卷積核作卷積。一維卷積核的半徑仍定爲3*sigma。此時算法複雜度變爲O(2*m*M*N)。
這裏實現了簡單版本的高斯模糊,經過使用橫向和縱向的一維高斯濾波器分別對源矩陣卷積,經過設置sigma的大小能控制圖片的模糊程度,值越大越模糊。可是算法速度仍比較慢,建議直接使用RenderScript版本或直接使用成熟的開源項目。
因爲代碼過長,不能截圖,所以直接給出Gist地址:https://gist.github.com/xiazdong/d57bf5441f56db197163a5de69dfa65f
效果以下:
RenderScript是Android提出的一個計算密集型任務的高性能框架,能並行的處理任務,他能夠充分利用多核CPU和GPU,你不須要管怎麼調度你的任務,只須要管任務具體作什麼。這裏不深刻介紹RenderScript,由於RenderScript已經提供了一個實現高斯模糊的類:ScriptIntrinsicBlur。
實現起來很是簡單:
開源項目
關於Android圖像模糊的開源項目有不少,好比Blurry是專門針對Bitmap或View作模糊,能夠設置模糊的基底色,並且還能對模糊操做異步化;BlurKit-Android也能對Bitmap作高斯模糊(內部經過RenderScript實現),但最吸引人的是實現了毛玻璃的遮罩,效果以下:
BlurKit-Android支持的最低版本是Android 4.1(API 16),所以若是應用須要支持的最低版本是4.0,則不能使用該庫,Blurry支持的最低版本是3.0。
配置過程以下:
compile 'com.wonderkiln:blurkit:1.0.0'
,並在defaultConfig中設置renderscriptTargetApi 24
和renderscriptSupportModeEnabled true
。BlurKit.init(this);
。配置完成後,經過調用BlurKit.getInstance().blur(Bitmap src, int radius);
實現高斯模糊,並會把高斯模糊的結果圖寫入src,其中0<radius<=25。
該庫還提供了fastBlur()
實現速度更快的高斯模糊,和blur()
的區別在於,fastBlur()
在高斯模糊以前對圖片採樣,使得圖片大小縮小好幾倍,從而加快高斯模糊的速度。這種加快速度的方法是合理的,由於高斯模糊並不須要原圖像很精確的信息。
BlurKit-Android最吸引人的是提供高斯模糊的遮罩(BlurLayout),隨着遮罩下面的內容的變化,高斯模糊效果也會隨之改變。使用以下:
該Layout可以實現實時的對該Layout下面的內容作高斯模糊。
配置方法:在build.gradle中添加compile 'jp.wasabeef:blurry:2.1.1'
。
使用方法以下:
總的來講,這兩個庫都使用起來很是方便。
此文已由做者受權雲加社區發佈,轉載請註明文章出處