將來視覺7-Android的高斯模糊方案

這段時間工做真心比較忙,而空餘時間,都在在研究補全一些opencv技術的基礎,而後近來有個業務和圖像有關,背景高斯模糊的方案了。java

可知Android可使用高斯模糊的方案也真的很多,可是最終仍是要看效果和效率的。linux

至於高斯模糊有什麼做用呢?android

模糊陰影,其原理也是使用高斯模糊的。git

在美顏磨皮這方面,使用高斯模糊是一個很好的方向。github

要學習高斯模糊基礎仍是要先知道底層原理,其原理是基於數學的正態分佈,越接近中心,權重就越大。 算法

正態分佈.png
正態分佈是一維的

如何反映出正態分佈?則須要使用高斯函數來實現。 上面的正態分佈是一維的,而對於圖像都是二維的,因此咱們須要二維的正態分佈。api

高斯函數

正態分佈的密度函數叫作"高斯函數"(Gaussian function)。它的一維形式是:數組

高斯函數

其中,μ是x的均值,σ是x的方差。由於計算平均值的時候,中心點就是原點,因此μ等於0。bash

一維高斯函數

根據一維高斯函數,能夠推導獲得二維高斯函數:框架

二維高斯函數

3*3的矩陣

3*3矩陣單位.png

爲了計算權重矩陣,須要設定σ值。現假定σ=1.5,則模糊半徑爲1的權重矩陣以下:

矩陣權重計算

這9個點的權重總和等於0.4787147,若是隻計算這9個點的加權平均,還必須讓它們的權重之和等於1,所以上面9個值還要分別除以0.4787147,獲得最終的權重矩陣。

###目的是讓濾鏡的權重總值等於1。不然的話,使用總值大於1的濾鏡會讓圖像偏亮,小於1的濾鏡會讓圖像偏暗。

image

有了權重矩陣,就能夠計算高斯模糊的值了。 假設現有9個像素點,灰度值(0-255)以下:

image

每一個點乘以本身的權重值:

image

獲得

image

將這9個值加起來,就是中心點的高斯模糊的值。 對全部點重複這個過程,就獲得了高斯模糊後的圖像。 ###對於彩色圖片來講,則須要對RGB三個通道分別作高斯模糊。

若是到達邊界的時候,還須要給邊界側補0處理

邊界處理.png

當圖像處理的時候,高斯濾波會從左到右、從上到下的處理各個點的色值合成。

一.Glide

Glide可使用一個擴展庫glide-transformations,就是本身寫Transform,而後在transform中添加高斯模糊的計算。具體代碼以下

FastBlur.java, 裏面變換的規則有點複雜,由於圖像變化是基於java上層來完成,效率和速度是最低的。

二.Genius-blur

Genius-blur

這是使用jni的方案,大小隻有20k左右。

內部blur_ARGB_8888的實現方法和Glide的FastBlur的算法方式是同樣的,可是由於使用C++底層實現,速度確定要快上不少。

三.RenderScript

使用RenderScript框架來加載渲染高斯模糊的渲染腳本,基礎仍是會使用底層的渲染Rs渲染庫。 github.com/CameraKit/b… 兼容問題 官方說明 只能api17以上才能使用,若是低版本只能使用v8版本的。網上有簡單的在build.gradle的defaultConifg添加

renderscriptTargetApi 26

renderscriptSupportModeEnabled true

添加v8的renderscript兼容包,容量加大一百多k。

可是我在AS3.3沒法使用這種方法編譯成功,提示我沒法找到RenderScript的類,結果我只能手動引入了Sdk\build-tools\27.0.3\renderscript\lib\packaged裏面的so和jar包,才能編譯經過,可是這樣打出來的aar包2.2M,只是一個模糊兼容就增大這麼大的容量,不怎麼友好啊。 radius的範圍是0~25。值越大越模糊。

public Bitmap blur(Bitmap src, int radius) {
            final Allocation input = Allocation.createFromBitmap(rs, src);
            final Allocation output = Allocation.createTyped(rs, input.getType());
            final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
            script.setRadius(radius);
            script.setInput(input);
            script.forEach(output);
            output.copyTo(src);
       
        return src;
    }
複製代碼

1.最終我採起了17以上使用renderScipt,如下的使用Genius-blur這個庫,打包出來的aar大概是20k左右,足夠兼容簡單的高斯模糊要求。

2.正常的高斯模糊,是不包含色值,有些須要會要求帶有特定色值的高斯模糊,這時候可使用ImageView把高斯模糊的圖設置爲背景,而後把帶有色值的透明圖來設置到imageView的src圖。這樣看起來就會帶有色值的高斯模糊了。

3.若是作到高斯模糊漸變消息,其實這裏是使用障眼法,設置Bitmap的alpha值來達到漸變消失的。

四.使用Opencv來處理高斯圖像

若是你框架中已經加入了Opencv的sdk,使用這種方法也是很是高效的。

Mat表明Opencv中的圖像數據

Imgproc是Opencv的工具類

Imgproc.GaussianBlur是Opencv的高斯模糊處理

public class GaussianBlur {
	public static void main(String[] args) {
		try{
			System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
			
			Mat src=Imgcodecs.imread("本地圖片地址");
			//讀取圖像到矩陣中
			if(src.empty()){
				throw new Exception("no file");
			}
			
			Mat dst = src.clone();
			//複製矩陣進入dst
			
			Imgproc.GaussianBlur(src,dst,new Size(13,13),10,10);
			//圖像模糊化處理11
			Imgcodecs.imwrite("寫入地址", dst);
			
			Imgproc.GaussianBlur(src,dst,new Size(31,5),80,3);
			//圖像模糊化處理33
			Imgcodecs.imwrite("寫入地址", dst);
		}catch(Exception e){
			System.out.println("例外:" + e);
		}
	}
}
複製代碼

五.OpenGL

以前使用Opengl,來採集圖像用於實時的美顏方案的。

使用高斯模糊是能夠給人臉皮膚模糊,作到去磨皮等效果的。

能夠看到RenderScript最高支持25範圍的卷積核來作模糊,卷積核越大越模糊,計算量越大,速度越慢。計算太大就會形成卡頓,卷積核過小,模糊效果不夠明細那。可是爲了效率問題,Opengl這邊只使用了統一幾組採集點,就是在必定範圍內只採集一些對應的點,例如周圍點附近幾組菱形頂點做爲採集點。而後使用這種採集來作配置。

/**模糊取值紋理座標**/
    blurCoordinates[0] = inputTextureCoordinate.xy + singleStepOffset * vec2(0.0, -10.0);
   ....
	blurCoordinates[19] = inputTextureCoordinate.xy + singleStepOffset * vec2(4.0, -4.0);
    
    float sampleColor = centralColor.g * 20.0;
    sampleColor += texture2D(inputImageTexture, blurCoordinates[0]).g;
    …
    /** 不一樣權重**/
    sampleColor += texture2D(inputImageTexture, blurCoordinates[19]).g * 2.0;

    /**最終模糊均值**/
    sampleColor = sampleColor / 48.0;
    /** .用原圖綠色通道值減去sampleColor,加上0.5,整個步驟是PS中的高保留反差**/
    float highPass = centralColor.g - sampleColor + 0.5;
複製代碼

人臉是偏紅色,因此紅色通道的色值比較大,而人臉細節方面是保留在綠色通道上比較多。 若是須要美白,須要使用強光處理

/**5次強光處理**/
for(int i = 0; i < 5;i++)
    {
        highPass = hardLight(highPass);
    }

float hardLight(float color)
{
    if(color <= 0.5)
        color = color * color * 2.0;
    else
        color = 1.0 - ((1.0 - color)*(1.0 - color) * 2.0);
    return color;
}
複製代碼

灰度圖生成,公式爲0.299R + 0.587G + 0.114*B

const highp vec3 W = vec3(0.299,0.587,0.114);
float luminance = dot(centralColor, W);

    float alpha = pow(luminance, params);
複製代碼

將灰度值做爲閾值,用來排除非皮膚部分

/** pow(x,y)是x的y次方**/
    float alpha = pow(luminance, params);
    /** 原圖rgb值與高反差後的結果相比,噪聲越大,二者相減後的結果越大,在原結果基礎上加上必定值,來提升亮度,消除噪聲。
pow函數中第二個參數可調(1/3~1),值越小,alpha越大,磨皮效果越明顯,修改該值可做爲美顏程度**/
    vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;

複製代碼

以灰度值做爲透明度將原圖與混合後結果進行濾色、柔光等混合,並調節飽和度

gl_FragColor = vec4(mix(smoothColor.rgb, max(smoothColor, centralColor), alpha), 1.0);
複製代碼

可是由於圖片比例問題,高斯模糊的方式是沒問題的,可是採集點的影響須要根據寬高比例調整 Cain_Huang對人臉磨皮的高斯模糊調整Android OpenGLES 實時美顏(磨皮)的優化

他在磨皮優化二的章節,提供了更高效的高斯模糊計算方式。 在頂點着色器,預先計算出周邊點保存到數組,而後傳遞到片斷着色器

uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
attribute vec4 aTextureCoord;

// 高斯算子左右偏移值,當偏移值爲5時,高斯算子爲 11 x 11
const int SHIFT_SIZE = 5;

uniform highp float texelWidthOffset;
uniform highp float texelHeightOffset;

varying vec2 textureCoordinate;
varying vec4 blurShiftCoordinates[SHIFT_SIZE];

void main() {
    gl_Position = uMVPMatrix * aPosition;
    textureCoordinate = aTextureCoord.xy;
    // 偏移步距
    vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);
    // 記錄偏移座標
    for (int i = 0; i < SHIFT_SIZE; i++) {
        blurShiftCoordinates[i] = vec4(textureCoordinate.xy - float(i + 1) * singleStepOffset,
                                       textureCoordinate.xy + float(i + 1) * singleStepOffset);
    }
}
複製代碼

片斷着色器,使用一個for循環來取得偏移座標的色值總和,而後計算平均值。這裏沒有使用高斯核權重,因此並不算標準被高斯模糊計算。

precision mediump float;
varying vec2 textureCoordinate;
uniform sampler2D inputTexture;
const int SHIFT_SIZE = 5; // 高斯算子左右偏移值
varying vec4 blurShiftCoordinates[SHIFT_SIZE];
void main() {
    // 計算當前座標的顏色值
    vec4 currentColor = texture2D(inputTexture, textureCoordinate);
    mediump vec3 sum = currentColor.rgb;
    // 計算偏移座標的顏色值總和
    for (int i = 0; i < SHIFT_SIZE; i++) {
        sum += texture2D(inputTexture, blurShiftCoordinates[i].xy).rgb;
        sum += texture2D(inputTexture, blurShiftCoordinates[i].zw).rgb;
    }
    // 求出平均值
    gl_FragColor = vec4(sum * 1.0 / float(2 * SHIFT_SIZE + 1), currentColor.a);
}
複製代碼

高斯模糊的應用和一些計算就分析到這裏,五種高斯模糊的計算和分析,但願對你們有幫助。

Opengl

Android組件化
相關文章
相關標籤/搜索