如何在Java中获取OpenGL ES 2.0 for Android中相机纹理的RGB颜色

如何在Java中获取OpenGL ES 2.0 for Android中相机纹理的RGB颜色,java,android,opengl-es,android-camera,histogram,Java,Android,Opengl Es,Android Camera,Histogram,我正在尝试将一个.NET应用程序移植到Android上,在Android上我从相机中捕获每一帧,然后在显示之前根据用户设置对其进行相应的修改。在.NET中做这件事很简单,因为我可以简单地在相机上查询下一幅图像,然后得到一个位图,我可以随意访问它 许多处理选项之一要求应用程序获取每个捕获图像的强度直方图,然后在显示结果(基于用户设置)之前对捕获图像进行一些修改。我试图做的是在Android中捕获和修改相机预览 我知道实现某种实时ish相机处理的“最佳”方法是使用OpenGL作为预览框架,使用GLE

我正在尝试将一个.NET应用程序移植到Android上,在Android上我从相机中捕获每一帧,然后在显示之前根据用户设置对其进行相应的修改。在.NET中做这件事很简单,因为我可以简单地在相机上查询下一幅图像,然后得到一个位图,我可以随意访问它

许多处理选项之一要求应用程序获取每个捕获图像的强度直方图,然后在显示结果(基于用户设置)之前对捕获图像进行一些修改。我试图做的是在Android中捕获和修改相机预览

我知道实现某种实时ish相机处理的“最佳”方法是使用OpenGL作为预览框架,使用
GLES11Ext.GL\u纹理\u外部纹理

我能够捕捉预览,并在片段着色器中进行一些处理,如改变图像灰度、修改片段颜色、阈值剪裁等,但要进行更强大的处理,如计算直方图或应用快速傅立叶变换,我需要(快速)访问(读/写)在显示纹理之前,以RGB格式显示纹理中包含的捕获图像中的所有像素

我将Java与OpenGLES2.0一起用于Android

我当前的绘图代码执行以下操作:

private int mTexture; // texture handle created to hold the captured image
...

// Called for every captured frame
public void onDraw()
{
    int mPositionHandle;
    int mTextureCoordHandle;

    GLES20.glUseProgram(mProgram);

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexture);

    // TODO:
    //  Obtain RGB pixels of the texture and manipulate here.

    // TODO:
    //  Put the resulting RGB pixels in a texture for display.


    // prepare for drawing
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "position");
    GLES20.glEnableVertexAttribArray(mPositionHandle);
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false,vertexStride, vertexBuffer);

    mTextureCoordHandle = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate");
    GLES20.glEnableVertexAttribArray(mTextureCoordHandle);
    GLES20.glVertexAttribPointer(mTextureCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false,vertexStride, textureVerticesBuffer);

    // draw the texture
    GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
            GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
}
我的顶点和片段着色器非常简单:

顶点着色器:

attribute vec4 position;
attribute vec2 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
    gl_Position = position;
    textureCoordinate = inputTextureCoordinate;
}
片段着色器(直接访问捕获的图像):

如果我能够获得捕获纹理的宽度和高度,并能够获得和修改(或能够写入另一个纹理)捕获中每个像素的RGB值(例如在字节数组中,每个字节表示一个颜色通道),以便在显示之前进行处理,这将是理想的


我开始学习OpenGL ES,我在路上得到了这个项目。任何帮助都是非常感谢的,谢谢。

如果你想直接从java或C++访问,你需要用 GLReDexPixels]()/Cuffe读取像素。不幸的是,您无法通过FBO直接访问“外部”纹理。您可以在摄影机帧上使用RenderScript以获得良好效果。在着色器中执行所有操作都将产生最佳性能,但它们有一定的限制,并且在Android上调试时可能会很烦人。我用3x3卷积滤波器内核做了一个类似的项目;此处的示例输出:@fadden感谢您的建议。Android中的摄像头图像处理非常落后,而且不直观。如何使用
glReadPixels()
在程序上下文中获取这些RGB值?特别是在我标记为“TODO”的部分中。创建一个屏幕外pbuffer,渲染纹理,并使用
glReadPixels()
读取值。Grafika()有一些有用的类(例如,请参见纹理上载速度测试,它渲染到pbuffer,并通过读取像素将一帧保存到磁盘)。我认为大多数在YUV空间中进行图像处理的人,使用ImageReader()在API 19中变得更容易。它允许通过ByteBuffer从Java直接访问相机帧。
/* Shader: Gray Scale*/
#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 textureCoordinate;
uniform samplerExternalOES s_texture;
void main()
{
    float clr = dot(texture2D(s_texture, textureCoordinate), vec4(0.299, 0.587, 0.114, 0.0));
    gl_FragColor = vec4(clr, clr, clr, 1.0);
}