Android Camera對預覽進行黑白濾鏡處理

2021-02-20 郭霖

近日消息,科學家們一直在探索老化是不是一種疾病,並且試圖治癒人類老化。從增強那些保護細胞老化的蛋白質,到延長染色體終端,科學家們已經嘗試了各種阻止老化的方法。研究人員提出,解決老化帶來的一種問題,其它問題就會變得糟糕。比如說,阻止老化需要增加健康細胞,但是這可能意味著癌細胞將更猛烈的增長。研究的負責人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

歡迎長按下圖 -> 識別圖中二維碼

或者 掃一掃 關注我的公眾號

相關焦點

  • Android利用SurfaceView顯示Camera圖像爬坑記(四)
    最近幾天沒啥事研究了下,android自定義相機的實現,主要實現了通過surfaceview跟camera實現拍照,預覽,圖片的保存。能夠進行前後攝像頭的切換,自動和手動聚焦,設置閃光燈模式 ,人臉識別等。
  • PS第二十課:濾鏡——camera raw濾鏡調色
    camera raw濾鏡調色cameraraw濾鏡調色縮放工具和抓手工具②:是調節顯示的大小和位置,以便細節的調節。,可調節大小,可對色溫、顏色、對比度、飽和度、雜色進行調節漸變濾鏡⑩:拉出一個選區對起點和終點進行調節,對顏色對比度徑向漸變⑩拉出一個圓圈可以對四周的 點進行調節打開時候基本的頁面、色調曲線、
  • Android壓力測試Monkey工具
    它向系統發送偽隨機的用戶事件流(如按鍵輸入、觸控螢幕輸入、手勢輸入等),實現對正在開發的應用程式進行壓力測試。Monkey測試是一種為了測試軟體的穩定性、健壯性的快速有效的方法。二、 Monkey的特徵1、測試的對象僅為應用程式包,有一定的局限性。2、 Monky測試使用的事件流數據流是隨機的,不能進行自定義。
  • Camera Raw濾鏡在高質感人像後期調色的實戰應用
    1、對原圖複製一層,打開濾鏡--camera raw濾鏡,由於原畫面偏暖,通過色溫把畫面調冷些,降一點曝光,提高一些對比度以調整畫面的整體光線。通過調整高光和陰影部分,讓畫面突出更多的細節;通過調整黑白色增加畫面的明暗度。加一點自然飽和度讓畫面色彩更豐富,飽和度降低一些可以讓自然飽和度更加的自然。
  • Photoshop中用Camera Raw濾鏡進行人像修圖 - 藝術與創意
    濾鏡>Camera Raw濾鏡,到這裡,會彈出大家都很熟悉的Adobe Camera Raw中的對話方塊。第四步:首先先做一些一般性修圖操作。右邊面板上有曝光、白平衡和透明度等選項。我們可以調整滑塊位置進行闡述調整。這裡,筆者將圖片的透明度調整為+10,以彰顯影像細節。第五步:在詳細信息選項卡,我們要對圖片進行那個銳化和降噪處理。一般默認情況下,銳化設置為+25。
  • UV偏振ND都是什麼 10大相機濾鏡詳細解讀
    不過相信購買這些濾鏡的朋友很多對於濾鏡都是很迷茫,這一個小小玻璃片為何要賣那麼多錢,為何又有那麼多種,每種都是幹啥用的呢?其實濾鏡是攝影附件當中最為常見的一種,在過去後期處理只屬於少數人的時代,有相當多的攝影師和文藝青年選擇用濾鏡來實現平時我們肉眼所看不到的效果。
  • 修圖必看 Camera Raw中的「隱藏」功能
    Camera Raw是大家最熟悉不過的RAW文件處理工具了,隨著近幾次更新,Camera Raw的功能越來越豐富,除了原有的調節內容,Camera Raw的調節獨立性也越來越強,一些原來藉助於PS實現的功能現在在Camera Raw中也有體現。
  • 一個Camera Raw濾鏡就可以讓你的朋友圈旅行照高大上起來
    把原片Ctrl+j複製一份,打開Camera Raw濾鏡,在基本中調整。由於原片偏灰偏暗,這裡主要是解決這個問題,色溫向左拉一點,加曝光、清晰度,整個畫面突然就清晰明亮了很多;然後拉低高光、提高陰影,讓畫面呈現出更多的細節;加一點自然飽和度,讓畫面色彩更豐富,降一點飽和度,讓畫面增加一點柔和感。
  • 濾鏡到底有什麼用處
    紅色濾鏡的拍攝效果    色彩鏡由於主要用在黑白攝影之中,現在的黑白攝影更加偏向於藝術性,不像是以前只能拍攝黑白時期的攝影,增加色彩鏡之後能夠讓黑白攝影的光比和反差更大,能夠提升黑白照片的質感,但是色彩鏡掌控上卻是比較難的。
  • 如何使用ImageJ工具軟體對圖片進行反轉負片特效處理
    我們大家在編輯整理一些圖片素材時,可能會遇到需要對圖片進行反轉的負片特效處理的問題。那麼,我們該如何進行操作呢?通常,我們需要使用第三方專業圖像處理工具軟體的濾鏡特效來處理。本期,小編要介紹分享的是如何使用ImageJ工具軟體來對圖片進行負片特效處理的具體操作步驟。
  • 濾鏡|Volumetrics(PS光束大師)
    【效果預覽】原圖:
  • Android P 行為變更
    加密變更 Android P 就加密算法的實現及處理引入了幾項變更。 ICU 可將公開 API 遷移至 android.icu 軟體包,同時 ICU 也供 Android 平臺內部使用,用於支持國際化開源項目,譬如說,開發者可以利用 ICU 在 java.util、 java.text 和 android.text.format 中實現 Android 類。
  • 體驗「異界」風光 麥莎IR760紅外濾鏡評測
    ,不僅僅是變成了黑白的而已,照片在各個細節之處都透露著一種詭異的感覺,尤其是人的眼睛。普通相機沒有安裝濾鏡的黑白效果照片  為了能夠充分的進行對比,筆者放上一張使用常規相機拍攝的黑白照片,這張照片看起來就正常很多
  • App推薦:有趣可愛的LINE Camera攝影App
    Never推出的LINE通訊軟體,以可愛的表情符號擁有很多用戶,而這次推出的LINE Camera主打拍攝,不僅有攝影App都有的濾鏡功能LINE Camera界面以及簡介    在LINE Camera中包含進600種表情貼圖和100多種相框來幫助用戶裝飾照片,讓照片更可愛;可微調效果的濾鏡能夠幫助用戶製作出富有魅力的照片
  • Camera Raw中的調色利器 學習漸變濾鏡的用法 為攝影照片分區調整
    在前面亮節教程的內容中,我們通過照片示例,知道了攝影照片可以在後期處理中,去做光影重構,局部增強照片中的明暗細節。當然,這些重構與增強,也只是"微調"性質,因為照片拍攝結果就是基礎,我們能做的,只是在基礎上稍加美化。
  • 給圖片加閃電加能量光線,只用這一個PS濾鏡就夠了
    嗯,胡謅一首開場打油詩,然後,阿隨君要說的是一個小技巧,用外星人濾鏡套裝旗下的「Eye Candy 7」濾鏡,來為天空設計閃電效果,以及做能量光線效果。老習慣,開始教程之前 ,先來感受一下案例圖的魅力吧。
  • 在PS中如何利用Camera Raw濾鏡給圖片添加暗角
    PS CC版本相比之前的PS版本功能更多,而Camera Raw濾鏡就是其他版本所沒有的,那麼我們可以利用Camera Raw濾鏡功能來實現給圖片添加暗角達到產生暈影的效果。先看看原圖和效果圖的對比,接下來我們開始動學習這一效果吧。
  • 體驗「異界」風光 麥莎IR760紅外濾鏡評測_MASSA 77mm 超薄紅外鏡...
    850nm、950nm的紅外攝影濾鏡拍攝的則是純粹的紅外照片,適合後期轉換為黑白效果。今天我們的這塊麥莎紅外濾鏡是760nm的,原則上說它正好能完全阻隔可見光,而只讓紅外光通過。  ·紅外濾鏡使用效果展示  在使用紅外濾鏡之前,我們要做一些準備工作。
  • PS使用Camera Raw濾鏡快速調色,你還不知道在哪裡嗎?
    step 1:打開圖片,找到Camera Raw濾鏡,如果你沒有的話,就設置吧step 2:在編輯—首選項—CameraRaw,進行設置step 3:設置好了的話,我們重新打開圖片,直接選擇 濾鏡—Camera Raw濾鏡,或者按快捷鍵:Shift+ctrl+Astep 4:我們直接調,色溫,色調,陰影,黑色step 5:調好之後,