使用過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;
}
}