近日消息,科學家們一直在探索老化是不是一種疾病,並且試圖治癒人類老化。從增強那些保護細胞老化的蛋白質,到延長染色體終端,科學家們已經嘗試了各種阻止老化的方法。研究人員提出,解決老化帶來的一種問題,其它問題就會變得糟糕。比如說,阻止老化需要增加健康細胞,但是這可能意味著癌細胞將更猛烈的增長。研究的負責人Paul Nelson稱,如果你去除那些功能退化的老化細胞,那麼就會讓癌細胞數量激增。如果你消除或者減少那些癌細胞,那麼老化細胞數量就會增加。
各位小夥伴們大家好,新的一周又開始了,希望大家都能有個好心情迎接新的一周。
本篇來自 lb377463323 的投稿,分享了Android平臺濾鏡的實現方式,希望大家喜歡!
lb377463323 的博客地址:
http://blog.csdn.net/lb377463323
首先講一下,本文不使用 Camera 的PreviewCallback預覽回調接口,因為onPreviewFrame()獲取的數據格式只能是NV21或NV12,除非修改HAL層代碼,一般情況下NV21或NV12需要轉成RGB格式然後進行處理,這樣太耗時了,所以本文使用SurfaceTexture來獲取預覽圖像。
偽代碼如下,這個不細講了,可以參考我之前的博客 Android 初始化 OpenGL ES ,並且分析 Renderer 子線程原理。
mGLSurfaceView = new GLSurfaceView(this); mGLSurfaceView.setEGLContextClientVersion(2); mGLSurfaceView.setRenderer(new GLSurfaceView.Renderer()); setContentView(mGLSurfaceView);
本文只使用後置攝像頭:mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK; mCamera = Camera.open(mCameraId) Camera.Parameters parameters = mCamera.getParameters(); parameters.set("orientation", "portrait"); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); parameters.setPreviewSize(1280, 720); mCamera.setDisplayOrientation(90) setCameraDisplayOrientation(mActivity, mCameraId, mCamera); mCamera.setParameters(parameters);
GLSurfaceView 創建好 OpenGL ES 的環境後,在 Renderer 的 onSurfaceCreated() 中,創建一個外部紋理用於接收預覽數據:public static int createOESTextureObject() { int[] tex = new int[1]; GLES20.glGenTextures(1, tex, 0); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0]); GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); return tex[0]; }
有了外部紋理,現在可以實例化一個 SurfaceTexture 了,之後即可開啟 Camera 預覽:
public boolean initSurfaceTexture() { mSurfaceTexture = new SurfaceTexture(mOESTextureId); mSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { @Override public void onFrameAvailable(SurfaceTexture surfaceTexture) { mGLSurfaceView.requestRender(); } }); mCamera.setPreviewTexture(mSurfaceTexture); mCamera.startPreview(); return true; }
接著在 onDrawFrame 中更新 SurfaceTexture 綁定的外部紋理圖像,使其獲取的是最新的預覽數據:
if (mSurfaceTexture != null) { mSurfaceTexture.updateTexImage(); mSurfaceTexture.getTransformMatrix(transformMatrix); }
到這裡相機已經可以將預覽數據發送到 SurfaceTexture 上,並且此預覽數據實際上是填充到了 SurfaceTexture 綁定的外部紋理中,之後就可以操作此紋理為我們所用了。
現在開始 OpenGL ES 部分代碼編寫,首先編寫最重要的 Shader 代碼:private static final String VERTEX_SHADER = "" + "attribute vec4 aPosition;\n" + "uniform mat4 uTextureMatrix;\n" + "attribute vec4 aTextureCoordinate;\n" + "varying vec2 vTextureCoord;\n" + "void main()\n" + "{\n" + " vTextureCoord = (uTextureMatrix * aTextureCoordinate).xy;\n" + " gl_Position = aPosition;\n" + "}\n";
private static final String FRAGMENT_SHADER = "" + "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES uTextureSampler;\n" + "varying vec2 vTextureCoord;\n" + "void main() \n" + "{\n" + " vec4 vCameraColor = texture2D(uTextureSampler, vTextureCoord);\n" + " float fGrayColor = (0.3*vCameraColor.r + 0.59*vCameraColor.g + 0.11*vCameraColor.b);\n" + " gl_FragColor = vec4(fGrayColor, fGrayColor, fGrayColor, 1.0);\n" + "}\n";
private static final float[] vertexData = { 1f, 1f, 1f, 1f, -1f, 1f, 0f, 1f, -1f, -1f, 0f, 0f, 1f, 1f, 1f, 1f, -1f, -1f, 0f, 0f, 1f, -1f, 1f, 0f };
因為屏幕為四邊形,所以需要兩個三角形,其坐標系(此時是物體坐標系)如下圖所示,左上角為第一個三角形,序號為(1,2,3),右下角為第二個三角形,序號為(4,5,6)
三角形的顏色使用紋理進行填充,所以每個三角形的頂點需要與紋理坐標進行匹配,紋理坐標系如下,頂點在紋理的左下角。
將頂點和紋理坐標數據使用FloatBuffer來存儲,防止內存回收:
public FloatBuffer createBuffer(float[] vertexData) { FloatBuffer buffer = ByteBuffer.allocateDirect(vertexData.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); buffer.put(vertexData, 0, vertexData.length).position(0); return buffer; }
vertexShader = loadShader(GL_VERTEX_SHADER, VERTEX_SHADER); fragmentShader = loadShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER); mShaderProgram = linkProgram(vertexShader, fragmentShader); public int loadShader(int type, String shaderSource) { int shader = glCreateShader(type); if (shader == 0) { throw new RuntimeException("Create Shader Failed!" + glGetError()); } glShaderSource(shader, shaderSource); glCompileShader(shader); return shader; } public int linkProgram(int verShader, int fragShader) { int program = glCreateProgram(); if (program == 0) { throw new RuntimeException("Create Program Failed!" + glGetError()); } glAttachShader(program, verShader); glAttachShader(program, fragShader); glLinkProgram(program); glUseProgram(program); return program; }
現在需要將頂點坐標和紋理坐標傳輸給Shader,在onDrawFrame方法中執行下述碼:
aPositionLocation = glGetAttribLocation(mShaderProgram, "aPosition"); aTextureCoordLocation = glGetAttribLocation(mShaderProgram, "aTextureCoordinate"); uTextureMatrixLocation = glGetUniformLocation(mShaderProgram, "uTextureMatrix"); uTextureSamplerLocation = glGetUniformLocation(mShaderProgram, "uTextureSampler"); glActiveTexture(GLES20.GL_TEXTURE0); glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mOESTextureId); glUniform1i(uTextureSamplerLocation, 0); glUniformMatrix4fv(uTextureMatrixLocation, 1, false, transformMatrix, 0); if (mDataBuffer != null) { mDataBuffer.position(0); glEnableVertexAttribArray(aPositionLocation); glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, false, 16, mDataBuffer); mDataBuffer.position(2); glEnableVertexAttribArray(aTextureCoordLocation); /紋理坐標每次讀取兩個頂點值,之後間隔16(每行4個值 * 4個字節)的字節繼續讀取兩個頂點值 glVertexAttribPointer(aTextureCoordLocation, 2, GL_FLOAT, false, 16, mDataBuffer); } glDrawArrays(GL_TRIANGLES, 0, 6);
至此運行此程序 Camera 預覽就會顯示為黑白濾鏡,如下圖所示。
總結一下:首先創建 GLSurfaceView 和開啟相機,之後創建一個外部紋理,根據此紋理ID創建一個 SurfaceTexture,Camera 將預覽數據輸出至此 SurfaceTexture 上,執行 SurfaceTexture.updateTexImage() 就會將一幀預覽數據推送給外部紋理上。之後 OpenGL ES 就可以操作此紋理,比如加濾鏡,濾鏡就是對紋理的 RGBA 通道進行處理,處理後的數據就通過 OpenGL ES 繪製出來,其實對於 OpenGL ES 來說,最終就是畫兩個三角形,三角形的顏色取自紋理對應的位置。
代碼地址(順手給個 Star 啊):
http://github.com/lb377463323/GraphicsTestBed
歡迎長按下圖 -> 識別圖中二維碼
或者 掃一掃 關注我的公眾號