移动端滤镜开发(四)滤镜初尝试

2016-12-02  本文已影响1937人  前世小书童

写在前面的话

<p>
前面几个章节分别介绍了关于OpenGL实现图片显示,相机预览,视频播放这些功能,使用滤镜的载体这里我们算是造好了,接下来就是展开我的滤镜开发之旅了,然而OpenGL自带的媒体效果框架就可以实现滤镜的效果,What? 还有这等好事,那么接下来下这个自带的媒体效果框架。

一.媒体效果框架实现滤镜

媒体效果框架介绍

<p>

这个媒体效果框架主要包含Effect,EffectFactory与EffectContex类,Effect类实现其实也是通过Shader的方式来完成的,这些Shader程序内置在Android中,我们只需要按照一定的方式来调用就行了

当然当我们设置了不同的效果时候有些影响可能并不适用于所有平台,因此造成一定的影响之前,应用程序应该通过isEffectSupported(String)来判断是否支持该平台

接下来我们看下支持的效果

Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_AUTOFIX);
//调整的区间为0到1,0表示不调整,1为最大值
mEffect.setParameter("scale", 0.5f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_BACKDROPPER);
//选择Vedio的source
mEffect.setParameter("source", Uri.toString);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_BITMAPOVERLAY);
//设置覆盖的bitmap
mEffect.setParameter("bitmap", bitmap);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_BLACKWHITE);
//最大色彩像素范围,调整的区间为0到1
mEffect.setParameter("white", 0.5f);
//最小色彩像素范围,调整的区间为0到1
mEffect.setParameter("black", 0.5f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_BRIGHTNESS);
//1.0表示没有变化,增大表示增加亮度。
mEffect.setParameter("brightness", 2f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_CONTRAST);
//1.0表示没有变化,增大表示增加对比度。
mEffect.setParameter("contrast", 2f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_CROP);
//起点位置区间为0到宽/高度
mEffect.setParameter("xorigin", 0);
mEffect.setParameter("yorigin", 0);
//宽高,区间为1之间和图像减去xorigin/yorigin的距离。
mEffect.setParameter("width", mWidth / 2);
mEffect.setParameter("height", mHeight / 2);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_CROSSPROCESS);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_DOCUMENTARY);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_DUOTONE);
//设置第一颜色
mEffect.setParameter("first_color", Color.YELLOW);
//设置第二颜色
mEffect.setParameter("second_color", Color.DKGRAY);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_FILLLIGHT);
//设置背光强度,0到1之间
mEffect.setParameter("strength", 0.5f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_FISHEYE);
//设置扭曲程度,0到1之间
mEffect.setParameter("scale", 0.5f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_FLIP);
//设置垂直/水平方向是否反转
mEffect.setParameter("vertical", true);
mEffect.setParameter("horizontal", true);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_GRAIN);
//设置颗粒强度,区别为0到1
mEffect.setParameter("strength",0.5f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_GRAYSCALE);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_LOMOISH);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_NEGATIVE);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_POSTERIZE);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_REDEYE);
//float类型数组,其中(F [2 * I]中,f [2 * I + 1]),用于指定第i眼睛中心的数组,区间为0到1之间
mEffect.setParameter("centers",new float[]{0.5f,0.6f});
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_REDEYE);
//旋转角度
mEffect.setParameter("angle",180);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_REDEYE);
//色彩饱和度的比例,区间为-1到1,0表示没有变化,而-1表示完全饱和度,即灰度
mEffect.setParameter("scale",0.5f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_SEPIA);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_SHARPEN);
//锐利程度,区间为0到1,0表示没有变化
mEffect.setParameter("scale",0.5f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_STRAIGHTEN);
//旋转角度,区间为-45f到45f
mEffect.setParameter("scale",45f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_TEMPERATURE);
//色温值,区间为0到1,0为冷色温,1为暖色温,0.5表示无变化
mEffect.setParameter("scale",1f);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_TINT);
//特殊颜色
mEffect.setParameter("tint",Color.RED);
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_TINT);
//边缘消失程度,区间为0到1,0表示无变化
mEffect.setParameter(""scale",1f);

到这里所以的框架提供的效果就介绍完毕了,接下来我们把它应用看一下效果

媒体效果框架应用

<p>

这里就以之前的显示图片的OpenGl程序为例子,简单改写一下就可以将效果应用上去了

其实只用在onDrawFrame中加入相关代码就可以了

如下,以设置图片亮度为例子

@Override
public void onDrawFrame(GL10 gl) {
  ...
if(mEffectContext==null) {
    mEffectContext = EffectContext.createWithCurrentGlContext();
}
if(mEffect!=null){
    mEffect.release();
}

EffectFactory factory = mEffectContext.getFactory();
mEffect = factory.createEffect(EffectFactory.EFFECT_BRIGHTNESS);
mEffect.setParameter("brightness", 2f);
mEffect.apply(mTexNames[0], mWidth, mHeight, mTexNames[1]);
  ...
}

很简单也没有什么好解释的

运行呢?

如下

图1 亮度效果

接下来我们再尝试下另外几种

鱼眼镜头扭曲效果

图2 鱼眼镜头扭曲效果

LOMO效果

图3 LOMO效果

更多的效果就不做演示了,参考上面的代码自己去尝试就好了

上面对OpenGL自带媒体模块实现滤镜效果进行了讲解,但是由于效果相对比较单一并且比较简单,并不能够满足于我们一些业务上面的需求,所以接下来就开启我们真正的滤镜实现之旅了,上面所提到Effect类实现其实也是通过Shader的方式来完成的,这些Shader程序内置在Android中,所以后面我们自己自己编写的滤镜其实也是用同样的方法。

二.简单滤镜开发

(1).图像基本属性

<p>

工欲善其事必先利其器,所以对于数字图像的基本属性进行了解是很有必要的

(2).简单滤镜的实现

<p>

这里其实就是实现几种比较简单的滤镜效果,让大家对于滤镜相关有一个从浅到深的了解过程,

1.Brightness滤镜

<p>

图片亮度指图像色彩的明暗程度,所以图片亮度是和RGB三色的值是有关联的
除了亮度还有色差I,信号值Q也是与RGB色有关联,下面是他们的计算公式

| Y | |0.31 0.59 0.11 | | R |
| I | = |0.60 -0.28 -0.32 | * | G |
|Q | |0.21 -0.52 -0.31 | | B |

所以只要我们对图片中每一个点的RGB值进行等比增大或者降低就可以达到对图片亮度进行修改的目的

亮度的取值在0到1之间,所以RGB三色的取值在也在0到1之间,所以这个增大和降低的取值在-1到1之间,当取-1时候图片亮度为0,此时图片为黑色,取1时候图片亮度为100%,此时图片为白色,取0时候则图片没有任何变化

我们还是以之前的OpenGl显示图片为例子,这里我们需要做的改动只有FRAGMENT_SHADER,因为我们只能在片段着色器中才可以取到每个一点的颜色值,通过对这个颜色值进行修改从而达到我们需要的效果

这里我就直接贴上来了,应该比较简单,

 FRAGMENT_SHADER = "precision mediump float;" +
                "varying highp vec2 v_texCoord;\n" +
                " \n" +
                " uniform sampler2D s_texture;\n" +
                " \n" +
                " void main()\n" +
                " {\n" +
                "     lowp vec4 textureColor = texture2D(s_texture, v_texCoord);\n" +
                "     \n" +
                "     gl_FragColor = vec4((textureColor.rgb + vec3(0.5f)), textureColor.w);\n" +
                " }";

可以看到这里我们是将取出来的颜色RGB值都增加了0.5f,那么接下来我们看下运行的结果

图1 亮度增量为0.5f效果

接下来将亮度降低0.5f继续看下效果

运行如下

图2 亮度增量为-0.5f效果

到这里我们实现的第一个滤镜就完成了,虽然很简单,但是还是很有意义的嘛,哈哈

2.灰度效果滤镜

<p>

RGB转换为单色的[0 ~256]之间的灰度,最常用的转换公式如下:

Gray = 0.299 * red + 0.587 * green + 0.114 * blue;

所以我们修改下片段着色器程序

 FRAGMENT_SHADER = "precision mediump float;" +
                "varying highp vec2 v_texCoord;\n" +
                " \n" +
                " uniform sampler2D s_texture;\n" +
                " \n" +
                " void main()\n" +
                " {\n" +
                "     lowp vec4 textureColor = texture2D(s_texture, v_texCoord);\n" +
                "     \n" +
                "     float gray = textureColor.r * 0.299 + textureColor.g * 0.587 + textureColor.b * 0.114;\n" +
                "     gl_FragColor = vec4(gray, gray, gray, textureColor.w);\n" +
                " }";

其实就是将上面的公式通过着色器语言表示出来

运行如下

图3 灰度图片
3.底片效果滤镜

<p>

底片效果其实是对图像的逆反处理

将对应的(R, G, B)像素替换成(255 - R, 255 - G, 255 - B)

所以我们修改下片段着色器程序

FRAGMENT_SHADER = "precision mediump float;" +
        "varying highp vec2 v_texCoord;\n" +
        " \n" +
        " uniform sampler2D s_texture;\n" +
        " \n" +
        " void main()\n" +
        " {\n" +
        "     lowp vec4 textureColor = texture2D(s_texture, v_texCoord);\n" +
        "     \n" +
        "     gl_FragColor = vec4((vec3(1.0f) - textureColor.rgb), textureColor.w);\n" +
        " }";

运行如下

图4 底片效果
4.浮雕效果滤镜

<p>

前面几个滤镜效果相对较为简单,这个浮雕效果呢,相对稍微复杂一点,但是其实也是对RGB的值去进行修改,算法步骤也相对多一些

浮雕图象效果是指图像的前景前向凸出背景。常见于一些纪念碑的雕刻上,要实现浮雕效果步骤如下:我们把图象的一个象素和左上方的象素进行求差运算,并加上一个灰度。这个灰度就是表示背景颜色。这里我们设置这个插值为128 (图象RGB的值是0-255)。同时,我们还应该把这两个颜色的差值转换为亮度信息.否则浮雕图像会出现彩色。

取左上方像素的方法则需要根据图片的宽高来进行计算,我这里为了方便就直接设置为一个定值

接下来看下代码的实现

#extension GL_OES_EGL_image_external : require

varying highp vec2 v_texCoord;
uniform sampler2D s_texture;
const vec2 texSize = vec2(1920,1080);

void main() {

    vec2 tex = v_texCoord;
    vec2 upLeftUV = vec2(tex.x - 1.0/texSize.x, tex.y - 1.0/texSize.y);
    vec4 curColor = texture2D(s_texture,v_texCoord);
    vec4 upLeftColor = texture2D(s_texture,upLeftUV);
    vec4 delColor = curColor - upLeftColor;
    float h = 0.3*delColor.x + 0.59*delColor.y + 0.11*delColor.z;
    vec4 bkColor = vec4(0.5, 0.5, 0.5, 1.0);
     gl_FragColor = vec4(h,h,h,0.0) +bkColor;
}

这里和前面的片段着色器程序一样,只是为了书写方便,所以写在raw文件夹下

读取raw下面文件方法如下

 public String readShaderFromRawResource(final int resourceId){
        final InputStream inputStream = MagicParams.context.getResources().openRawResource(
                resourceId);
        final InputStreamReader inputStreamReader = new InputStreamReader(
                inputStream);
        final BufferedReader bufferedReader = new BufferedReader(
                inputStreamReader);

        String nextLine;
        final StringBuilder body = new StringBuilder();

        try{
            while ((nextLine = bufferedReader.readLine()) != null){
                body.append(nextLine);
                body.append('\n');
            }
        }
        catch (IOException e){
            return null;
        }
        return body.toString();
    }

接下来运行如下

图5 浮雕效果图

这个效果看起来就还不错,算法其实也是很简单的

那么到这里就不对其他的滤镜效果进行概述了,后面的文章还会对复杂的效果进行讲解

写在后面的话

<p>

OpenGL自带的媒体框架其实效果还是可以的,但是大多还是比较简单的图片渲染,在实际开发中,其实还是不能够满足我们的业务需求的,所以后面我们会自己去写shader来实现不同的滤镜效果,peace~~~

上一篇 下一篇

猜你喜欢

热点阅读