1. 高斯模糊:


高斯模糊是是圖片產生模糊效果的一種演算法,使用正態分布來平滑資料,
1. 原理:
所謂"模糊",可以理解成每一個像素都取周邊像素的平均值,下圖中,2是中間點,周邊點都是1,"中間點"取"周圍點"的平均值,就會變成1,在圖形上,就相當于產生"模糊"效果,"中間點"失去細節,


顯然,計算平均值時,取值范圍越大,"模糊效果"越強烈,下面分別是原圖、模糊半徑3像素、模糊半徑10像素的效果,模糊半徑越大,影像就越模糊,

接下來的問題就是,既然每個點都要取周邊像素的平均值,那么應該如何分配權重呢,如果使用簡單平均,顯然不是很合理,因為影像都是連續的,越靠近的點關系越密切,越遠離的點關系越疏遠,因此,加權平均更合理,距離越近的點權重越大,距離越遠的點權重越小,
2. 正態分布(高斯分布)的權重
下圖分別是正態分布一維和二維的密度曲線:


正態分布的密度函式叫做"高斯函式"(Gaussian function),它的一維形式是:

二維高斯函式:

3. 權重矩陣
假定中心點的坐標是(0,0),那么距離它最近的8個點的坐標如下,更遠的點以此類推:

為了計算權重矩陣,需要設定σ的值,假定σ=1.5,則模糊半徑為1的權重矩陣如下:

這9個點的權重總和等于0.4787147,如果只計算這9個點的加權平均,還必須讓它們的權重之和等于1,因此上面9個值還要分別除以0.4787147,得到最終的權重矩陣:

4. 計算高斯模糊:
有了權重矩陣,就可以計算高斯模糊的值了,假設某黑白圖片中現有9個像素點,灰度值(0-255)如下:

每個點乘以自己的權重值,得到:

將這9個值加起來,就是中心點的高斯模糊的值,對所有點重復這個程序,就得到了高斯模糊后的影像,如果原圖是彩色圖片,可以對RGB三個通道分別做高斯模糊,如果一個點處于圖片邊界,周邊沒有足夠的點,那會有幾種常用方式來處理,比如直接重復邊界點,這些方法的視覺上區別不明顯,
2. Android12 新增高斯模糊API:
Android 12 中,可以更輕松地將常用圖形效果應用于View上,View中增加了setRenderEffect介面:
public void setRenderEffect(@Nullable RenderEffect renderEffect) {
...
}
RenderEffect是新增的設定渲染特效的類,可將模糊、色彩濾鏡等特效直接應用于View上,如果引數傳null,則去除掉之前的特效,
RenderEffect中高斯模糊的對應靜態方法:
public static RenderEffect createBlurEffect(float radiusX, float radiusY, @NonNull TileMode edgeTreatment)
- radiusX和radiusY指在X軸和Y軸上進行高斯模糊的半徑
- edgeTreatment用于如何模糊圖片邊緣附近的內容,共有四種模式
示例:
imageView.setRenderEffect(RenderEffect.createBlurEffect(3F, 3F, Shader.TileMode.CLAMP))
即對imageView的X軸和Y軸都取半徑為3個像素點進行高斯模糊,且邊界點采用重復的方式,效果如下:
createBlurEffect還有四個引數的版本:
public static RenderEffect createBlurEffect(float radiusX, float radiusY,
@NonNull RenderEffect inputEffect, @NonNull TileMode edgeTreatment)
- inputEffect指先做一次相應的特效渲染,再進行高斯模糊,
RenderEffect還提供了很多其他特效的對應方法:

需要注意,在低于Android 12的設備上使用會導致崩潰,
3. 和以前方式的對比:
RenderScript是在Android上的高性能運行密集型運算的框架,以前實作高斯模糊通常是用這個庫,呼叫方式如下:
private fun getBlurBitmap(radius: Int, bitmap: Bitmap): Bitmap {
val renderScript = RenderScript.create(this)
val input: Allocation = Allocation.createFromBitmap(renderScript, bitmap)
val output: Allocation = Allocation.createTyped(renderScript, input.type)
val scriptIntrinsicBlur: ScriptIntrinsicBlur =
ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript))
scriptIntrinsicBlur.setRadius(radius.toFloat())
scriptIntrinsicBlur.setInput(input)
scriptIntrinsicBlur.forEach(output)
output.copyTo(bitmap)
return bitmap
}
獲取到模糊的圖片,再set到對應的View中,很明顯,Android12提供的API大大簡化了這個程序且更加靈活,
雖然官方宣稱渲染性能得到提升,但使用一張200k的圖片測驗,用兩種方式運行后,分別查看了記憶體和耗時,基本一致,可能在較大圖片上才存在差距,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/330366.html
標籤:其他
