java - 使用 OpenGL 将每个相机帧处理为位图
问题描述
我有一个应用程序,我想在其中处理来自相机的每个给定帧来做一些 ARCore 的事情。所以我有一个实现的类GLSurfaceView.Renderer
,在这个类中我有onDrawFrame(GL10 gl)
方法。在此方法中,我想使用 Android 位图,因此我调用此代码以从当前帧获取位图:
private Bitmap getTargetImageBitmapOpenGL(int cx, int cy, int w, int h) {
try {
if (currentTargetImageBitmap == null) {
currentTargetImageBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
byteBuffer = ByteBuffer.allocateDirect(w * h * 4);
byteBuffer.order(ByteOrder.nativeOrder());
}
// cy = height - cy;
if ((cx + w / 2) > width) {
Log.e(TAG, "TargetImage CenterPoint invalid A: " + cx + " " + cy);
cx = width - w / 2;
}
if ((cx - w / 2) < 0) {
Log.e(TAG, "TargetImage CenterPoint invalid B: " + cx + " " + cy);
cx = w / 2;
}
if ((cy + h / 2) > height) {
Log.e(TAG, "TargetImage CenterPoint invalid C: " + cx + " " + cy);
cy = height - h / 2;
}
if ((cy - h / 2) < 0) {
Log.e(TAG, "TargetImage CenterPoint invalid D: " + cx + " " + cy);
cy = h / 2;
}
int x = cx - w / 2;
int y = cy - h / 2;
GLES20.glReadPixels(x, y, w, h, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,
byteBuffer);
IntBuffer currentTargetImagebuffer = byteBuffer.asIntBuffer();
currentTargetImagebuffer.rewind();
currentTargetImageBitmap.copyPixelsFromBuffer(currentTargetImagebuffer);
return currentTargetImageBitmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
这种方法大约需要 90 毫秒,这对于实时处理每个传入的帧来说肯定太慢了,我需要这样做,因为该onDrawFrame(GL10 gl)
方法还会将此帧绘制到表面视图。知道为什么这么慢吗?如果我只能读取每隔一帧的像素,但将每一帧都绘制到我的 SurfaceView 上,这也足够了。我试图在 中调用显示的方法AsyncTask.execute()
,但另一个线程无法通过该GLES20.glReadPixels()
方法读取,因为它不是 GL 线程。
解决方案
许多现代 GPU 可以原生解码 YUV;问题是如何让 YUV 表面进入 OpenGL ES,因为这通常不是 Open GL ES 所做的事情。大多数操作系统(包括 Android)允许您通过EGL_image_external
扩展将外部表面直接导入 OpenGL ES,并且这些外部表面可以标记为具有自动颜色转换的 YUV。
更好的是,这一切都是零拷贝处理的;相机缓冲区可以直接被GPU导入和访问。
这种导入的Android机制是通过SurfaceTexture
类,必要的用法在这里描述:https ://source.android.com/devices/graphics/arch-st
推荐阅读
- python - RecursionError:最大递归深度超出了python属性getter setter
- android - 如何将我的 Recycler View 设计为与 Chanel App 的此设计相似?
- css - v-expansion-panel-header 中的图标占用了太多空间
- azure - Azure SQL——实际上什么是 vCore
- ios - 在范围内找不到“BGTaskScheduler”
- java - Java中的简单座位预订
- python - 预期的 str、bytes 或 os.PathLike 对象,而不是 QuerySet
- java - 如何在 Mac 上添加“关于”选项卡
- laravel - 如何在 laravel 中执行此操作 - 单个查询
- sql-server - Azure Sql FireWall 规则允许 azure 服务和资源使用命令行访问此服务器