将来视觉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组件化
相关文章
相关标签/搜索