移動(dòng)端濾鏡開發(fā)(四)濾鏡初嘗試

寫在前面的話

<p>
前面幾個(gè)章節(jié)分別介紹了關(guān)于OpenGL實(shí)現(xiàn)圖片顯示,相機(jī)預(yù)覽,視頻播放這些功能,使用濾鏡的載體這里我們算是造好了,接下來(lái)就是展開我的濾鏡開發(fā)之旅了,然而OpenGL自帶的媒體效果框架就可以實(shí)現(xiàn)濾鏡的效果,What? 還有這等好事,那么接下來(lái)下這個(gè)自帶的媒體效果框架。

一.媒體效果框架實(shí)現(xiàn)濾鏡

媒體效果框架介紹

<p>

這個(gè)媒體效果框架主要包含Effect,EffectFactory與EffectContex類,Effect類實(shí)現(xiàn)其實(shí)也是通過(guò)Shader的方式來(lái)完成的,這些Shader程序內(nèi)置在Android中,我們只需要按照一定的方式來(lái)調(diào)用就行了

當(dāng)然當(dāng)我們?cè)O(shè)置了不同的效果時(shí)候有些影響可能并不適用于所有平臺(tái),因此造成一定的影響之前,應(yīng)用程序應(yīng)該通過(guò)isEffectSupported(String)來(lái)判斷是否支持該平臺(tái)

接下來(lái)我們看下支持的效果

  • EFFECT_AUTOFIX 基于直方圖均衡嘗試自動(dòng)修正圖像
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_AUTOFIX);
//調(diào)整的區(qū)間為0到1,0表示不調(diào)整,1為最大值
mEffect.setParameter("scale", 0.5f);
  • EFFECT_BACKDROPPER 替換輸入幀為從所選視頻的視頻幀
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_BACKDROPPER);
//選擇Vedio的source
mEffect.setParameter("source", Uri.toString);
  • EFFECT_BITMAPOVERLAY 在源圖像基礎(chǔ)上覆蓋新的圖像
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_BITMAPOVERLAY);
//設(shè)置覆蓋的bitmap
mEffect.setParameter("bitmap", bitmap);
  • EFFECT_BLACKWHITE 調(diào)整最小和最大色彩像素強(qiáng)度的范圍
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_BLACKWHITE);
//最大色彩像素范圍,調(diào)整的區(qū)間為0到1
mEffect.setParameter("white", 0.5f);
//最小色彩像素范圍,調(diào)整的區(qū)間為0到1
mEffect.setParameter("black", 0.5f);
  • EFFECT_BRIGHTNESS 調(diào)整圖片亮度
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_BRIGHTNESS);
//1.0表示沒有變化,增大表示增加亮度。
mEffect.setParameter("brightness", 2f);
  • EFFECT_CONTRAST 調(diào)整圖像的對(duì)比度
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_CONTRAST);
//1.0表示沒有變化,增大表示增加對(duì)比度。
mEffect.setParameter("contrast", 2f);
  • EFFECT_CROP 從圖片中裁剪一塊矩形區(qū)域,如果裁剪區(qū)域落在圖像邊界之外,其結(jié)果是不確定的
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_CROP);
//起點(diǎn)位置區(qū)間為0到寬/高度
mEffect.setParameter("xorigin", 0);
mEffect.setParameter("yorigin", 0);
//寬高,區(qū)間為1之間和圖像減去xorigin/yorigin的距離。
mEffect.setParameter("width", mWidth / 2);
mEffect.setParameter("height", mHeight / 2);
  • EFFECT_CROSSPROCESS 限制圖片藍(lán)色通道,增強(qiáng)紅色和綠色通道
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_CROSSPROCESS);
  • EFFECT_DOCUMENTARY 實(shí)現(xiàn)圖片黑白紀(jì)實(shí)風(fēng)格的效果
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_DOCUMENTARY);
  • EFFECT_DUOTONE 用兩個(gè)色調(diào)表示照片
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_DUOTONE);
//設(shè)置第一顏色
mEffect.setParameter("first_color", Color.YELLOW);
//設(shè)置第二顏色
mEffect.setParameter("second_color", Color.DKGRAY);
  • EFFECT_FILLLIGHT 為圖片填充背光
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_FILLLIGHT);
//設(shè)置背光強(qiáng)度,0到1之間
mEffect.setParameter("strength", 0.5f);
  • EFFECT_FISHEYE 魚眼鏡頭扭曲效果
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_FISHEYE);
//設(shè)置扭曲程度,0到1之間
mEffect.setParameter("scale", 0.5f);
  • EFFECT_FLIP 垂直或水平翻轉(zhuǎn)圖像
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_FLIP);
//設(shè)置垂直/水平方向是否反轉(zhuǎn)
mEffect.setParameter("vertical", true);
mEffect.setParameter("horizontal", true);
  • EFFECT_GRAIN 為圖片添加電影顆粒效果
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_GRAIN);
//設(shè)置顆粒強(qiáng)度,區(qū)別為0到1
mEffect.setParameter("strength",0.5f);
  • EFFECT_GRAYSCALE 圖片轉(zhuǎn)為灰度圖
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_GRAYSCALE);
  • EFFECT_LOMOISH 圖片添加LOMO相機(jī)的風(fēng)格效果
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_LOMOISH);
  • EFFECT_NEGATIVE 反轉(zhuǎn)圖像的顏色,也就是底片效果
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_NEGATIVE);
  • EFFECT_POSTERIZE 圖片添加多色調(diào)分色效果
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_POSTERIZE);
  • EFFECT_REDEYE 刪除圖片指定區(qū)域的紅眼
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_REDEYE);
//float類型數(shù)組,其中(F [2 * I]中,f [2 * I + 1]),用于指定第i眼睛中心的數(shù)組,區(qū)間為0到1之間
mEffect.setParameter("centers",new float[]{0.5f,0.6f});
  • EFFECT_ROTATE 旋轉(zhuǎn)圖像
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_REDEYE);
//旋轉(zhuǎn)角度
mEffect.setParameter("angle",180);
  • EFFECT_SATURATE 調(diào)整圖像色彩飽和度
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_REDEYE);
//色彩飽和度的比例,區(qū)間為-1到1,0表示沒有變化,而-1表示完全飽和度,即灰度
mEffect.setParameter("scale",0.5f);
  • EFFECT_SEPIA 圖像轉(zhuǎn)換為深褐色調(diào)
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_SEPIA);
  • EFFECT_SHARPEN 使圖像變的銳利
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_SHARPEN);
//銳利程度,區(qū)間為0到1,0表示沒有變化
mEffect.setParameter("scale",0.5f);
  • EFFECT_STRAIGHTEN 根據(jù)指定的角度旋轉(zhuǎn)圖像,并且裁剪圖像,是可見區(qū)域沒有非圖片覆蓋部分
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_STRAIGHTEN);
//旋轉(zhuǎn)角度,區(qū)間為-45f到45f
mEffect.setParameter("scale",45f);
  • EFFECT_TEMPERATURE 調(diào)整圖像的色溫
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_TEMPERATURE);
//色溫值,區(qū)間為0到1,0為冷色溫,1為暖色溫,0.5表示無(wú)變化
mEffect.setParameter("scale",1f);
  • EFFECT_TINT 通過(guò)設(shè)定的特殊顏色為圖片調(diào)整
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_TINT);
//特殊顏色
mEffect.setParameter("tint",Color.RED);
  • EFFECT_VIGNETTE 添加消失外圖像邊緣效果
Effect mEffect = effectContext.getFactory().createEffect(EffectFactory.EFFECT_TINT);
//邊緣消失程度,區(qū)間為0到1,0表示無(wú)變化
mEffect.setParameter(""scale",1f);

到這里所以的框架提供的效果就介紹完畢了,接下來(lái)我們把它應(yīng)用看一下效果

媒體效果框架應(yīng)用

<p>

這里就以之前的顯示圖片的OpenGl程序?yàn)槔?,?jiǎn)單改寫一下就可以將效果應(yīng)用上去了

其實(shí)只用在onDrawFrame中加入相關(guān)代碼就可以了

如下,以設(shè)置圖片亮度為例子

@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]);
  ...
}

很簡(jiǎn)單也沒有什么好解釋的

運(yùn)行呢?

如下

圖1 亮度效果

接下來(lái)我們?cè)賴L試下另外幾種

魚眼鏡頭扭曲效果

圖2 魚眼鏡頭扭曲效果

LOMO效果

圖3 LOMO效果

更多的效果就不做演示了,參考上面的代碼自己去嘗試就好了

上面對(duì)OpenGL自帶媒體模塊實(shí)現(xiàn)濾鏡效果進(jìn)行了講解,但是由于效果相對(duì)比較單一并且比較簡(jiǎn)單,并不能夠滿足于我們一些業(yè)務(wù)上面的需求,所以接下來(lái)就開啟我們真正的濾鏡實(shí)現(xiàn)之旅了,上面所提到Effect類實(shí)現(xiàn)其實(shí)也是通過(guò)Shader的方式來(lái)完成的,這些Shader程序內(nèi)置在Android中,所以后面我們自己自己編寫的濾鏡其實(shí)也是用同樣的方法。

二.簡(jiǎn)單濾鏡開發(fā)

(1).圖像基本屬性

<p>

工欲善其事必先利其器,所以對(duì)于數(shù)字圖像的基本屬性進(jìn)行了解是很有必要的

  • 圖像的像素?cái)?shù)目(Pixel dimensions),是指在位圖圖像的寬度和高度方向上含有的像素?cái)?shù)目。一幅圖像在顯示器上的顯示效果由像素?cái)?shù)目和顯示器的設(shè)定共同決定

  • 圖像的分辨率(Image resolution) 圖像的分辨率是指單位打印長(zhǎng)度上的圖像像素的數(shù)目,表示圖像數(shù)字信息的數(shù)量或密度,它決定了圖像的清晰程度。在同樣大小的面積上,圖像的分辨率越高,則組成圖像的像素點(diǎn)越多,像素點(diǎn)越小,圖像的清晰度越高。

  • 圖像的大小(File Size) 圖像文件的大小首先決定了圖像文件所需的磁盤存儲(chǔ)空間,它一般以字節(jié)(byte)來(lái)度量,其計(jì)算公式為: 字節(jié)數(shù)=(位圖高×位圖寬×圖像深度)/8 從計(jì)算公式可以看出來(lái),圖像文件的大小與像素?cái)?shù)目直接相關(guān)。

  • 圖像顏色(Image Color) 圖像顏色是指一幅圖像中所具有的最多的顏色種類,通過(guò)圖像處理軟件,可以很容易地改變?nèi)谋壤?,混合成任意一種顏色。

  • 圖像深度(Image Depth) 圖像深度也稱圖像的位深,是指描述圖像中每個(gè)像素的數(shù)據(jù)所占的位數(shù)。圖像的每一個(gè)像素對(duì)應(yīng)的數(shù)據(jù)通??梢允?位(bit)或多位字節(jié),用于存放該像素的顏色、亮度等信息,數(shù)據(jù)位數(shù)越多,對(duì)應(yīng)的圖像顏色種類越多。

  • 色調(diào)(Tone) 色調(diào)就是各種圖像色8彩模式下圖像的原色(例如,RGB模式的圖像的原以為R、G、B3種)的明暗度,色調(diào)的調(diào)整也就是對(duì)明暗度的調(diào)整。色調(diào)的范圍為0—255,總共包括256種色調(diào)。

  • 飽和度(Saturation) 飽和度是指圖像顏色的深度,它表明了色彩的純度,決定于物體反射或投射的特性。飽和度用與色調(diào)成一定比便的灰度數(shù)量來(lái)表示,取值范圍通常為0%(飽和度最低)--100%(飽和度最高)。調(diào)整圖像的飽和度也就是調(diào)整圖像的色度,當(dāng)將一幅圖像的飽和度降低到0%時(shí),就會(huì)變成為一個(gè)灰色的圖偈,增加飽和度應(yīng)付增加其色調(diào)。

  • 色相(Hue) 色相就是色彩顏色,對(duì)色相的調(diào)整也就是在多種顏色之間的變化。例如,光由紅、橙、黃、綠、青、藍(lán)、紫7色組成,每一種顏色即代表一種色相。

  • 亮度(Brightness) 亮度是指圖像色彩的明暗程度,是人眼對(duì)物本明暗強(qiáng)度的感覺,取值為0%--100%。

  • 對(duì)比度(Contrast) 對(duì)比度是指圖像中不同顏色或明暗度的對(duì)比。對(duì)比度越大,兩種顏色之間的差別也就越大,反之,就越相近。

  • 圖像的色彩通道 圖像三原色按不同的比例進(jìn)行混合可以產(chǎn)生許多種顏色,保存每一種原色信息及對(duì)其可進(jìn)行調(diào)整處理所提供的方式或途徑就是相應(yīng)顏色的色彩通道。

(2).簡(jiǎn)單濾鏡的實(shí)現(xiàn)

<p>

這里其實(shí)就是實(shí)現(xiàn)幾種比較簡(jiǎn)單的濾鏡效果,讓大家對(duì)于濾鏡相關(guān)有一個(gè)從淺到深的了解過(guò)程,

1.Brightness濾鏡

<p>

圖片亮度指圖像色彩的明暗程度,所以圖片亮度是和RGB三色的值是有關(guān)聯(lián)的
除了亮度還有色差I(lǐng),信號(hào)值Q也是與RGB色有關(guān)聯(lián),下面是他們的計(jì)算公式

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

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

所以只要我們對(duì)圖片中每一個(gè)點(diǎn)的RGB值進(jìn)行等比增大或者降低就可以達(dá)到對(duì)圖片亮度進(jìn)行修改的目的

亮度的取值在0到1之間,所以RGB三色的取值在也在0到1之間,所以這個(gè)增大和降低的取值在-1到1之間,當(dāng)取-1時(shí)候圖片亮度為0,此時(shí)圖片為黑色,取1時(shí)候圖片亮度為100%,此時(shí)圖片為白色,取0時(shí)候則圖片沒有任何變化

我們還是以之前的OpenGl顯示圖片為例子,這里我們需要做的改動(dòng)只有FRAGMENT_SHADER,因?yàn)槲覀冎荒茉谄沃髦胁趴梢匀〉矫總€(gè)一點(diǎn)的顏色值,通過(guò)對(duì)這個(gè)顏色值進(jìn)行修改從而達(dá)到我們需要的效果

這里我就直接貼上來(lái)了,應(yīng)該比較簡(jiǎn)單,

 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" +
                " }";

可以看到這里我們是將取出來(lái)的顏色RGB值都增加了0.5f,那么接下來(lái)我們看下運(yùn)行的結(jié)果

圖1 亮度增量為0.5f效果

接下來(lái)將亮度降低0.5f繼續(xù)看下效果

運(yùn)行如下

圖2 亮度增量為-0.5f效果

到這里我們實(shí)現(xiàn)的第一個(gè)濾鏡就完成了,雖然很簡(jiǎn)單,但是還是很有意義的嘛,哈哈

2.灰度效果濾鏡

<p>

RGB轉(zhuǎn)換為單色的[0 ~256]之間的灰度,最常用的轉(zhuǎn)換公式如下:

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" +
                " }";

其實(shí)就是將上面的公式通過(guò)著色器語(yǔ)言表示出來(lái)

運(yùn)行如下

圖3 灰度圖片
3.底片效果濾鏡

<p>

底片效果其實(shí)是對(duì)圖像的逆反處理

將對(duì)應(yīng)的(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" +
        " }";

運(yùn)行如下

圖4 底片效果
4.浮雕效果濾鏡

<p>

前面幾個(gè)濾鏡效果相對(duì)較為簡(jiǎn)單,這個(gè)浮雕效果呢,相對(duì)稍微復(fù)雜一點(diǎn),但是其實(shí)也是對(duì)RGB的值去進(jìn)行修改,算法步驟也相對(duì)多一些

浮雕圖象效果是指圖像的前景前向凸出背景。常見于一些紀(jì)念碑的雕刻上,要實(shí)現(xiàn)浮雕效果步驟如下:我們把圖象的一個(gè)象素和左上方的象素進(jìn)行求差運(yùn)算,并加上一個(gè)灰度。這個(gè)灰度就是表示背景顏色。這里我們?cè)O(shè)置這個(gè)插值為128 (圖象RGB的值是0-255)。同時(shí),我們還應(yīng)該把這兩個(gè)顏色的差值轉(zhuǎn)換為亮度信息.否則浮雕圖像會(huì)出現(xiàn)彩色。

取左上方像素的方法則需要根據(jù)圖片的寬高來(lái)進(jìn)行計(jì)算,我這里為了方便就直接設(shè)置為一個(gè)定值

接下來(lái)看下代碼的實(shí)現(xiàn)

#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();
    }

接下來(lái)運(yùn)行如下

圖5 浮雕效果圖

這個(gè)效果看起來(lái)就還不錯(cuò),算法其實(shí)也是很簡(jiǎn)單的

那么到這里就不對(duì)其他的濾鏡效果進(jìn)行概述了,后面的文章還會(huì)對(duì)復(fù)雜的效果進(jìn)行講解

寫在后面的話

<p>

OpenGL自帶的媒體框架其實(shí)效果還是可以的,但是大多還是比較簡(jiǎn)單的圖片渲染,在實(shí)際開發(fā)中,其實(shí)還是不能夠滿足我們的業(yè)務(wù)需求的,所以后面我們會(huì)自己去寫shader來(lái)實(shí)現(xiàn)不同的濾鏡效果,peace~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容