Android OpenGL ES開發(fā)(八)利用OpenGL進(jìn)行圖片簡單色彩處理

使用過PS的朋友應(yīng)該都知道乏德,PS利用濾鏡可以非常方便的更改圖片整體色彩鳍怨。用過諸如美圖秀秀之類的傻瓜式圖片處理工具也應(yīng)該記得蒿柳,他們可以直接選擇圖片的風(fēng)格改為冷色調(diào)、暖色調(diào)岳枷、復(fù)古芒填、黑白等等。這些是怎么實(shí)現(xiàn)的呢空繁?
在Android應(yīng)用當(dāng)中殿衰,我們設(shè)置文字的顏色,控件的背景色盛泡,會在資源文件中進(jìn)行諸如<color name="bg_color">#FF88269F</color>之類的定義闷祥。這個#FF88269F就是我們期望的色彩,我們可以把這個色彩分為4部分,每兩位組成一部分凯砍,分別表示A(透明通道)箱硕、R(紅色通道)、G(綠色通道)悟衩、B(藍(lán)色通道)剧罩。每一部分都由兩位十六進(jìn)制的數(shù)表示,也就是取值范圍都是0-255座泳,根據(jù)各個通道的比率不同惠昔,顯示出來的最終色彩也就不同了。
在其他的編程語言中挑势,也是和這種方式大同小異镇防。在GLSL中,顏色是用包含四個浮點(diǎn)的向量vec4表示潮饱,四個浮點(diǎn)分別代表RGBA四個通道来氧,取值范圍為0.0-1.0。我們先讀取圖片每個像素的色彩值饼齿,再對讀取的色彩紙進(jìn)行調(diào)整饲漾,這樣可以完成對圖片的色彩處理了。
我們應(yīng)該都知道缕溉,黑白圖片上考传,每個像素的RGB三個通道值應(yīng)該是相等的。知道這個证鸥,將彩色圖片處理成黑白圖片就非常簡單了僚楞。我們直接算出像素點(diǎn)的RGB三個通道,相加后除以3作為處理后每個通道的值就可以得到一個黑白圖片了枉层。這均值的方式是常見黑白圖片處理的一種方法泉褐。類似的還有權(quán)值方法(給予RGB三個通道不同的比例)、只取綠色通道等等方式鸟蜡。
與之類似的膜赃,冷色調(diào)的處理就是好單一增加藍(lán)色通道的值,暖色調(diào)的處理可以增加紅綠通道的值揉忘。還有其他復(fù)古跳座、浮雕等處理也差不多。

黑白

我們計(jì)算出像素點(diǎn)RGB三個通道泣矛,然后對應(yīng)相乘再相加疲眷。如下的片元著色器代碼:

頂點(diǎn)著色器

private final String vertextShaderCode =
        "attribute vec4 vPosition;" +
        "uniform mat4 vMatrix;" +
        "attribute vec2 vCoordinate;" +
        "varying vec2 aCoordinate;" +
        "void main() {" +
        "   gl_Position = vMatrix * vPosition;" +
        "   aCoordinate=vCoordinate;" +
        "}";

片元著色器

計(jì)算出像素點(diǎn)RGB三個通道,然后對應(yīng)相乘再相加

private final String fragmentShaderCode =
        "precision mediump float;" +
        "uniform sampler2D vTexture;" +
        "uniform vec3 vChangeColor;" +
        "varying vec2 aCoordinate;" +
        "void main() {" +
        "   vec4 nColor=texture2D(vTexture,aCoordinate);" +
        "   float c=nColor.r*vChangeColor.r+nColor.g*vChangeColor.g+nColor.b*vChangeColor.b;" +
        "   gl_FragColor=vec4(c,c,c,nColor.a);" +
        "}";

頂點(diǎn)坐標(biāo)

private float[] shapePos = {
        -1.0f, 1.0f,    //左上角
        -1.0f, -1.0f,   //左下角
        1.0f, 1.0f,     //右上角
        1.0f, -1.0f     //右下角
};

紋理坐標(biāo)

private float[] sCoord = {
        0.0f, 0.0f,
        0.0f, 1.0f,
        1.0f, 0.0f,
        1.0f, 1.0f
};

完整代碼:

public class MyTenthRender implements GLSurfaceView.Renderer
{

    private final String vertextShaderCode =
            "attribute vec4 vPosition;" +
            "uniform mat4 vMatrix;" +
            "attribute vec2 vCoordinate;" +
            "varying vec2 aCoordinate;" +
            "void main() {" +
            "   gl_Position = vMatrix * vPosition;" +
            "   aCoordinate=vCoordinate;" +
            "}";
    private final String fragmentShaderCode =
            "precision mediump float;" +
            "uniform sampler2D vTexture;" +
            "uniform vec3 vChangeColor;" +
            "varying vec2 aCoordinate;" +
            "void main() {" +
            "   vec4 nColor=texture2D(vTexture,aCoordinate);" +
            "   float c=nColor.r*vChangeColor.r+nColor.g*vChangeColor.g+nColor.b*vChangeColor.b;" +
            "   gl_FragColor=vec4(c,c,c,nColor.a);" +
            "}";
    private final Context context;

    private int program;
    private FloatBuffer vertexBuffer;
    //正交矩陣
    private final float[] mProjectMatrix = new float[16];
    //相機(jī)位置矩陣
    private final float[] mViewMatrix = new float[16];
    //計(jì)算變換矩陣
    private final float[] mMVPMatrix = new float[16];
    private float[] shapePos = {
            -1.0f, 1.0f,    //左上角
            -1.0f, -1.0f,   //左下角
            1.0f, 1.0f,     //右上角
            1.0f, -1.0f     //右下角
    };
    private float[] sCoord = {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            1.0f, 1.0f
    };

    private Bitmap mBitmap;
    private FloatBuffer coordBuffer;
    private int[] texture;
    private float gray[] = new float[]{0.299f,0.587f,0.114f};

    public MyTenthRender(Context context)
    {
        this.context = context;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
//        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
        //將背景設(shè)置為灰色
        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        //申請底層空間
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(shapePos.length * 4);
        byteBuffer.order(ByteOrder.nativeOrder());
        //將坐標(biāo)數(shù)據(jù)轉(zhuǎn)換為FloatBuffer您朽,用以傳入給OpenGL ES程序
        vertexBuffer = byteBuffer.asFloatBuffer();
        //將三角形坐標(biāo)傳入FloatBuffer
        vertexBuffer.put(shapePos);
        vertexBuffer.position(0);

        //申請底層空間
        ByteBuffer coordByteBuffer = ByteBuffer.allocateDirect(sCoord.length * 4);
        coordByteBuffer.order(ByteOrder.nativeOrder());
        //將坐標(biāo)數(shù)據(jù)轉(zhuǎn)換為FloatBuffer狂丝,用以傳入給OpenGL ES程序
        coordBuffer = coordByteBuffer.asFloatBuffer();
        //將紋理坐標(biāo)傳入FloatBuffer
        coordBuffer.put(sCoord);
        coordBuffer.position(0);


        //創(chuàng)建頂點(diǎn)著色器程序
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertextShaderCode);
        //創(chuàng)建片元著色器程序
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

        if (vertexShader == 0 || fragmentShader == 0)
        {
            return;
        }
        //創(chuàng)建一個空的OpenGL ES程序
        program = GLES20.glCreateProgram();
        //將頂點(diǎn)著色器加入程序
        GLES20.glAttachShader(program, vertexShader);
        //將片元著色器加入程序
        GLES20.glAttachShader(program, fragmentShader);
        //連接到著色器程序中
        GLES20.glLinkProgram(program);
        //使用程序
        GLES20.glUseProgram(program);


        texture = new int[1];
        //生成一個紋理,紋理ID放在int[] texture
        GLES20.glGenTextures(1, texture, 0);


        mBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.bg);

    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
        GLES20.glViewport(0, 0, width, height);
        int w = mBitmap.getWidth();
        int h = mBitmap.getHeight();
        float sWH = w / (float) h;
        float sWidthHeight = width / (float) height;
        if (width > height)
        {
            if (sWH > sWidthHeight)
            {
                //設(shè)置正交矩陣
                Matrix.orthoM(mProjectMatrix, 0, -sWidthHeight * sWH, sWidthHeight * sWH, -1, 1, 3, 7);
            } else
            {
                //設(shè)置正交矩陣
                Matrix.orthoM(mProjectMatrix, 0, -sWidthHeight / sWH, sWidthHeight / sWH, -1, 1, 3, 7);
            }
        } else
        {
            if (sWH > sWidthHeight)
            {
                //設(shè)置正交矩陣
                Matrix.orthoM(mProjectMatrix, 0, -1, 1, -1 / sWidthHeight * sWH, 1 / sWidthHeight * sWH, 3, 7);
            } else
            {
                //設(shè)置正交矩陣
                Matrix.orthoM(mProjectMatrix, 0, -1, 1, -sWH / sWidthHeight, sWH / sWidthHeight, 3, 7);
            }
        }
        //設(shè)置相機(jī)位置
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        //計(jì)算變換矩陣
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectMatrix, 0, mViewMatrix, 0);


    }

    @Override
    public void onDrawFrame(GL10 gl)
    {
        if (program == 0)
            return;

        //獲取變換矩陣vMatrix成員句柄
        int vMatrix = GLES20.glGetUniformLocation(program, "vMatrix");
        //設(shè)置vMatrix的值
        GLES20.glUniformMatrix4fv(vMatrix, 1, false, mMVPMatrix, 0);
        //獲取頂點(diǎn)著色器的vPosition成員句柄
        int vPosition = GLES20.glGetAttribLocation(program, "vPosition");
        //啟用vPosition句柄
        GLES20.glEnableVertexAttribArray(vPosition);
        //傳的圓筒面的所有坐標(biāo)數(shù)據(jù)
        GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 2 * 4, vertexBuffer);

        //獲取頂點(diǎn)著色器的vCoordinate成員句柄
        int vCoordinate = GLES20.glGetAttribLocation(program, "vCoordinate");
        //啟用vPosition句柄
        GLES20.glEnableVertexAttribArray(vCoordinate);
        //傳的紋理坐標(biāo)數(shù)據(jù)
        GLES20.glVertexAttribPointer(vCoordinate, 2, GLES20.GL_FLOAT, false, 2 * 4, coordBuffer);

        //傳入rgb顏色用于與圖片的rgb計(jì)算
        int vChangeColor = GLES20.glGetUniformLocation(program,"vChangeColor");
        GLES20.glUniform3fv(vChangeColor,1,gray,0);

        //將已經(jīng)創(chuàng)建并命名的紋理綁定到一個紋理目標(biāo)(GL_TEXTURE_2D)上
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);

        //設(shè)置縮小過濾為使用紋理中坐標(biāo)最接近的一個像素的顏色作為需要繪制的像素顏色
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        //設(shè)置放大過濾為使用紋理中坐標(biāo)最接近的若干個顏色,通過加權(quán)平均算法得到需要繪制的像素顏色
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        //設(shè)置環(huán)繞方向S:指定橫向模式為GL_CLAMP_TO_EDGE
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
        //設(shè)置環(huán)繞方向T:指定橫向模式為GL_CLAMP_TO_EDGE
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
        //將圖片數(shù)據(jù)傳到上面創(chuàng)建的紋理中
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmap, 0);

        //繪制
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        //禁止頂點(diǎn)數(shù)組的句柄
        GLES20.glDisableVertexAttribArray(vPosition);

    }

    public int loadShader(int type, String shaderCode)
    {
        //創(chuàng)建空的著色器
        int shader = GLES20.glCreateShader(type);
        //將著色器程序加到著色器中
        GLES20.glShaderSource(shader, shaderCode);
        //編譯色器程序
        GLES20.glCompileShader(shader);

        return shader;

    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末几颜,一起剝皮案震驚了整個濱河市倍试,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌菠剩,老刑警劉巖易猫,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異具壮,居然都是意外死亡准颓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門棺妓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來攘已,“玉大人,你說我怎么就攤上這事怜跑⊙” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵性芬,是天一觀的道長峡眶。 經(jīng)常有香客問我,道長植锉,這世上最難降的妖魔是什么辫樱? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮俊庇,結(jié)果婚禮上狮暑,老公的妹妹穿的比我還像新娘。我一直安慰自己辉饱,他們只是感情好搬男,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著彭沼,像睡著了一般缔逛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上姓惑,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天译株,我揣著相機(jī)與錄音,去河邊找鬼挺益。 笑死,一個胖子當(dāng)著我的面吹牛乘寒,可吹牛的內(nèi)容都是我干的望众。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼烂翰!你這毒婦竟也來了夯缺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤甘耿,失蹤者是張志新(化名)和其女友劉穎踊兜,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佳恬,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捏境,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了毁葱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垫言。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖倾剿,靈堂內(nèi)的尸體忽然破棺而出筷频,到底是詐尸還是另有隱情,我是刑警寧澤前痘,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布凛捏,位于F島的核電站,受9級特大地震影響芹缔,放射性物質(zhì)發(fā)生泄漏坯癣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一乖菱、第九天 我趴在偏房一處隱蔽的房頂上張望坡锡。 院中可真熱鬧,春花似錦窒所、人聲如沸鹉勒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽禽额。三九已至,卻和暖如春皮官,著一層夾襖步出監(jiān)牢的瞬間脯倒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工捺氢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留藻丢,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓摄乒,卻偏偏與公主長得像悠反,于是被迫代替她去往敵國和親残黑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容