OpenGLES:glReadPixels()獲取相機GLSurfaceView預覽數據并保存

Android現行的Camera API2機制可以通過onImageAvailable(ImageReader reader)回調從底層獲取到Jpeg、YuvRaw三種格式的Image,然后通過保存Image實現拍照功能,但是卻并沒有Api能直接在上層直接拿到實時預覽的數據。

Android Camera預覽的實現是上層下發SurfaceCameraHAL,由CameraHAL也就是android.hardware.camera.provider@2.4-service進程往Surface對應的Buffer中填充預覽數據,然后再copySurfaceFling中由OpenGL進行渲染顯示。

實際相機開發中,不僅僅只是要實現預覽,還經常需要拿到預覽數據做一些特效處理,那么問題來了,怎么在相機App獲取到實時預覽數據呢?

這跟上層Camera App用于顯示SurfaceView控件有關:

  • 如果上層使用的是GLSurfaceView,可以直接通過OpenGLESglReadPixels()獲取到copy到顯存中的預覽數據
  • 如果上層使用的不是GLSurfaceView,可以通過自己搭建EGL環境,然后在EGL環境中調用OpenGLESglReadPixels()獲取到預覽數據。

GLSurfaceView其實就是Android封裝好的EGL+SufaceView控件,Android的所有渲染最終都是通過OpenGL來實現的,所以萬變不離其宗,本質上上層Camera App都只能通過OpenGLESglReadPixels()實現預覽數據的獲取。

一個SurfaceAndroid EGL中對應一個FrameBuffer,學習過OpenGL的應該都知道,一個FrameBuffer會有多個附著(attachment),其中必須且只能有一個ColorBuffer附著,有一個或多個StencilBufferDepthBuffer附著

glReadPixels()僅限于讀取ColorBuffer,無法讀取DepthBufferStencilBuffer,它可以將圖像內容從顯存讀取到內存中,將ColorBuffer中的像素值保存到預分配的內存緩沖區。

前面關于OpenGLES的博文中,有兩篇是使用OpenGLES實現相機的相關功能,一篇是《OpenGLES:GLSurfaceView實現Android Camera預覽》,一篇是《OpenGLES:相機實時濾鏡四宮格、九宮格》,今天就在這兩篇博文基礎上實現相機預覽數據的獲取和保存。

相機實現部分在此不做過多講解,有興趣的可以參看前面兩篇博文,有詳細的講解
本文主要展示glReadPixels()對相機預覽數據獲取的實現

代碼實現其實很簡單
GLSurfaceView.Renderer實現類的onDrawFrame(GL10 gl)函數中新增如下代碼段:

if (shouldTakePic) {//預覽尺寸int w = 1080;int h = 1440;//預覽數據保存成照片的目錄String savePath = Environment.getExternalStorageDirectory().getPath() + "/DCIM/MyCamera/";int[] iat = new int[w * h];IntBuffer ib = IntBuffer.allocate(w * h);//(0,580)距離屏幕左下角的距離,與glViewport(0, 580,...)保持一致glReadPixels(0, 580, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ib);int[] ia = ib.array();//glReadPixels 讀取的內容是上下翻轉的,要處理一下for (int i = 0; i < h; i++) {for (int j = 0; j < w; j++) {iat[(h - i - 1) * w + j] = ia[i * w + j];}}Bitmap inBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);inBitmap.copyPixelsFromBuffer(IntBuffer.wrap(iat));ByteArrayOutputStream bos = new ByteArrayOutputStream();inBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bos);byte[] bitmapData = bos.toByteArray();File tempDir = new File(savePath);tempDir.mkdirs();String fileName = "temp_" + System.currentTimeMillis() + ".jpeg";File imgFile = new File(savePath, fileName);try {FileOutputStream output = new FileOutputStream(imgFile);output.write(bitmapData);output.flush();output.close();Log.v(TAG, "ImageReader X");} catch (Exception e) {e.printStackTrace();} finally {inBitmap.recycle();}
}

glReadPixels讀取的內容上下翻轉處理還有另外一種實現,
原理都是一樣的,實現起來大同小異

if (shouldTakePic) {//預覽尺寸int w = 1080;int h = 1440;//預覽數據保存成照片的目錄String savePath = Environment.getExternalStorageDirectory().getPath() + "/DCIM/MyCamera/";int b[] = new int[(int) (w * h)];int bt[] = new int[(int) (w * h)];IntBuffer buffer = IntBuffer.wrap(b);buffer.position(0);//(0,580)距離屏幕左下角的距離,與glViewport(0, 580,...)保持一致glReadPixels(0, 580, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);for (int i = 0; i < h; i++) {for (int j = 0; j < w; j++) {int pix = b[i * w + j];int pb = (pix >> 16) & 0xff;int pr = (pix << 16) & 0x00ff0000;int pix1 = (pix & 0xff00ff00) | pr | pb;bt[(h - i - 1) * w + j] = pix1;}}Bitmap inBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);inBitmap.copyPixelsFromBuffer(buffer);inBitmap = Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);ByteArrayOutputStream bos = new ByteArrayOutputStream();inBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bos);byte[] bitmapData = bos.toByteArray();ByteArrayInputStream fis = new ByteArrayInputStream(bitmapData);String tempPicFile = "temp_" + System.currentTimeMillis() + ".jpeg";File tempDir = new File(savePath);tempDir.mkdirs();try {File tmpFile = new File(tempDir, tempPicFile);FileOutputStream fos = new FileOutputStream(tmpFile);byte[] buf = new byte[1024];int len;while ((len = fis.read(buf)) > 0) {fos.write(buf, 0, len);}fis.close();fos.close();inBitmap.recycle();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}
}

驗證下效果,抓兩張預覽照試試:

抓一張普通預覽:

抓一張四宮格濾鏡預覽:

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/212337.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/212337.shtml
英文地址,請注明出處:http://en.pswp.cn/news/212337.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java學習筆記——instanceof關鍵字

instanceof關鍵字&#xff1a; 作用&#xff1a;保證對象向下轉型的安全性在對象向下轉型前判斷某一對象實例是否屬于某個類 判斷時&#xff0c;如果對象是null&#xff0c;則 instanceof 判斷結果為 false

Spring Boot 整合kafka:生產者ack機制和消費者AckMode消費模式、手動提交ACK

目錄 生產者ack機制消費者ack模式手動提交ACK 生產者ack機制 Kafka 生產者的 ACK 機制指的是生產者在發送消息后&#xff0c;對消息副本的確認機制。ACK 機制可以幫助生產者確保消息被成功寫入 Kafka 集群中的多個副本&#xff0c;并在需要時獲取確認信息。 Kafka 提供了三種…

ei源刊和ei會議的幾個區別

1、含義不同 公開發表論文&#xff0c;可以在期刊上刊登&#xff0c;也可以在會議上宣讀。ei源刊對應的是期刊&#xff0c;是指被ei檢索收錄的工程類的期刊。ei會議對應的是會議&#xff0c;是指被ei檢索收錄的會議。 2、檢索類型不同 期刊和會議都能被ei檢索&#xff0c;但…

Tr0ll

信息收集 探測主機存活信息&#xff1a; nmap -sn --min-rate 10000 192.168.182.0/24Starting Nmap 7.94 ( https://nmap.org ) at 2023-11-14 15:45 CST Nmap scan report for 192.168.182.1 Host is up (0.00026s latency). MAC Address: 00:50:56:C0:00:08 (VMware) Nmap…

qt 雙緩沖機制

在圖形編程中&#xff0c;雙緩沖機制是一種常用的技術&#xff0c;用于減少圖形繪制時的閃爍和抖動。它的基本思想是將圖形繪制到一個后臺緩沖中&#xff0c;然后一次性將后臺緩沖的內容顯示到屏幕上。 在 Qt 中&#xff0c;雙緩沖機制可以通過QPainter的begin()和end()方法來實…

Linux環境下socket本地通信

最近項目有用到了socket本地通信&#xff0c;故復習一下。之前都是基于本地虛擬機的ip地址通信的&#xff0c;現在項目&#xff0c;Linux單板上面有2個進程需要通信&#xff0c;故用到了本地socket通信&#xff0c;主要其實就是用了sockfd,文件描述符&#xff0c;也叫句柄。 服…

java接入gpt開發

前情提要 本次文章使用編譯器為IDEA2020 使用GPT模型為百度旗下的千帆大模型 如果是個人用或者不流傳出去&#xff0c;可以無腦入&#xff0c;因為會免費送20塊錢&#xff08;夠用上萬次&#xff09; 代金卷查看 正式教程&#xff1a; 百度智能云控制臺 (baidu.com) 按照步…

JMS(Java Message Service)使用指南

介紹 JMS即Java消息服務&#xff08;Java Message Service&#xff09;應用程序接口&#xff0c;是一個Java平臺中關于面向消息中間件&#xff08;MOM&#xff09;的API&#xff0c;用于在兩個應用程序之間&#xff0c;或分布式系統中發送消息&#xff0c;進行異步通信。它是一…

基于單片機智能病床呼叫系統設計

**單片機設計介紹&#xff0c;基于單片機智能病床呼叫系統設計 文章目錄 一 概要二、功能設計設計思路 三、 軟件設計原理圖 五、 程序六、 文章目錄 一 概要 基于單片機的智能病床呼叫系統是一種利用單片機技術設計的醫療設備&#xff0c;它能夠幫助病人在住院期間快速、方便…

國內大廠機器人賽道產品

大疆 大疆無人機自然不必說&#xff0c;除此之外大疆搞機甲大師&#xff0c;教育機器人。 字節 當前字節在機器人領域只是初步探索階段&#xff0c;目前尚未發布相關產品&#xff08;截止至23.12&#xff09;。 管理層想法&#xff1a; 跟已有業務做結合&#xff0c;服務好…

Java設計模式分類

java的設計模式大體上分為三大類&#xff1a; 創建型模式&#xff08;5種&#xff09;&#xff1a;工廠方法模式&#xff0c;抽象工廠模式&#xff0c;單例模式&#xff0c;建造者模式&#xff0c;原型模式。 結構型模式&#xff08;7種&#xff09;&#xff1a;適配器模式&am…

傳感器(一) :IMU / 陀螺儀模塊

IMU / 陀螺儀模塊 一、概述二、注意參數2.1 陀螺儀芯片標準&#xff08;MPU6050)2.2 參數說明 三、IMU模式使用注意事項3.1 IMU模塊安裝注意事項3.2 為什么IMU要安裝在機器中心位置 四、常見陀螺儀芯片品牌 一、概述 IMU全稱為慣性測量單元&#xff0c;可以通過測量物體在三維空…

Linux實用操作

一、各類小技巧&#xff08;快捷鍵&#xff09; 1.1 ctrl c 強制停止 Linux某些程序的運行&#xff0c;如果想要強制停止它&#xff0c;可以使用快捷鍵ctrl c 命令輸入錯誤&#xff0c;也可以通過快捷鍵ctrl c&#xff0c;退出當前輸入&#xff0c;重新輸入 1.2 ctrl d…

Leetcode刷題筆記——摩爾投票法

摩爾投票法的核心思想為對拼消耗。 摩你媽&#xff0c;學不會&#xff01;&#xff01;&#xff01;&#xff01; 229. 多數元素 II - 力扣&#xff08;LeetCode&#xff09;

ReLU(Rectified Linear Unit)和Sigmoid激活函數

ReLU&#xff08;Rectified Linear Unit&#xff09;和Sigmoid都是神經網絡中常用的激活函數。 特點&#xff1a; ReLU是一種簡單而有效的激活函數。它對于正數部分直接返回輸入&#xff0c;對于負數部分返回零。這種非線性轉換有助于網絡學習更復雜的表示。ReLU在許多深度學習…

自治調優!人大金倉解放DBA雙手

數據庫系統的性能是確保整個應用系統高效運轉的關鍵因素&#xff0c;因此數據庫性能調優工作至關重要。KingbaseES通過將人工調優過程內化為數據庫內核&#xff0c;成功實現了自治調優。這種創新的調優方案為DBA提供了更高效且準確的性能調優途徑&#xff0c;同時也顯著降低了數…

23秋 操作系統真題回憶

總結&#xff1a; 量大 綜合性強 結合實驗很緊密具體的題目 不是很記得了 只記了大概希望有人可以一起參與把這個題的答案做出來&#xff0c;有可以的 可以私信我謝謝 需要你們的想法因為可能涉及學校內部的試題&#xff0c;禁止轉載 2013題目 真題 2023題目 進程 代碼執…

構建VREP和MATLAB聯合仿真實驗平臺,控制機械臂末端按照固定軌跡移動

構建VREP和MATLAB聯合仿真實驗平臺&#xff0c;控制機械臂末端按照固定軌跡移動。主要工作如下&#xff1a; &#xff08;1&#xff09;solidworks構建機械臂模型&#xff1b; &#xff08;2&#xff09;將solidworks中構建的模型導入VREP中建立機械臂的多體動力學模型&#xf…

【Unity動畫】什么是任意狀態(Any state)

&#xff08;Any state&#xff09;可以從某個狀態A直接切換到另一個狀態 B\C\D\E\F 比如A到C的過渡&#xff0c;直接設置從Any state 到C的過渡線觸發參數即可。而不需要讓A到C直接在連接&#xff0c;同樣&#xff0c;B到C之間也無需直接鏈接。 這樣設計是在每一個動畫之間都…

HP-UNIX 系統安全基線 安全加固操作

目錄 賬號管理、認證授權 賬號 ELK-HP-UX-01-01-01 ELK -HP-UX-01-01-02 ELK -HP-UX-01-01-03 ??????? ELK-HP-UX-01-01-04 ???????ELK-HP-UX-01-01-05 ???????口令 ELK-HP-UX-01-02-01 ??????? ELK-HP-UX-01-02-02 ??????? ELK-HP…