Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/205.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 将自定义过滤器应用于摄影机输出_Android_Opengl Es_Filter_Camera - Fatal编程技术网

Android 将自定义过滤器应用于摄影机输出

Android 将自定义过滤器应用于摄影机输出,android,opengl-es,filter,camera,Android,Opengl Es,Filter,Camera,如何将自定义过滤器应用于相机输出中的单个帧,并显示它们 到目前为止,我所尝试的: mCamera.setPreviewCallback(new CameraGreenFilter()); public class CameraGreenFilter implements PreviewCallback { @Override public void onPreviewFrame(byte[] data, Camera camera) { final int l

如何将自定义过滤器应用于相机输出中的单个帧,并显示它们

到目前为止,我所尝试的:

mCamera.setPreviewCallback(new CameraGreenFilter());

public class CameraGreenFilter implements PreviewCallback {

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        final int len = data.length;
        for(int i=0; i<len; ++i){
            data[i] *= 2;
        }
    }
}
mCamera.setPreviewCallback(新的CameraGreenFilter());
公共类CameraGreenFilter实现PreviewCallback{
@凌驾
预览帧上的公共无效(字节[]数据,摄像头){
最终整数长度=data.length;

对于(int i=0;iOK),有几种方法可以做到这一点。但性能方面存在一个严重问题。摄像头中的字节[]位于中,如果要显示它,必须将其转换为某种RGB格式。这种转换操作非常昂贵,并且显著降低了输出fps

这取决于你实际想对相机预览做什么。因为最好的解决方案是在不回调的情况下绘制相机预览,并在相机预览上产生一些效果。这是进行论证真实性的常用方法

但是,如果您确实需要手动显示输出,有几种方法可以做到这一点。您的示例不起作用的原因有几个。首先,您根本不显示图像。如果您将其称为:

mCamera.setPreviewCallback(new CameraGreenFilter());
mCamera.setPreviewDisplay(null);
如果你的相机根本不显示预览,你就必须手动显示它。而且你不能在onPreviewFrame方法中执行任何昂贵的操作,因为数据的生命周期有限,它会在下一帧被覆盖。提示一下,使用,它会更快,因为它会重用一个缓冲区,并且不必在每一帧上分配新内存。

所以你必须这样做:

private byte[] cameraFrame;
private byte[] buffer;
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    cameraFrame = data;
    addCallbackBuffer(data); //actually, addCallbackBuffer(buffer) has to be called once sowhere before you call mCamera.startPreview();
}


private ByteOutputStream baos;
private YuvImage yuvimage;
private byte[] jdata;
private Bitmap bmp;
private Paint paint;

@Override //from SurfaceView
public void onDraw(Canvas canvas) {
    baos = new ByteOutputStream();
    yuvimage=new YuvImage(cameraFrame, ImageFormat.NV21, prevX, prevY, null);

    yuvimage.compressToJpeg(new Rect(0, 0, width, height), 80, baos); //width and height of the screen
    jdata = baos.toByteArray();

    bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length);

    canvas.drawBitmap(bmp , 0, 0, paint);
    invalidate(); //to call ondraw again
}
gl.glGenTextures(1, cameraTexture, 0);
int tex = cameraTexture[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, tex);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_LUMINANCE, 
    this.prevX, this.prevY, 0, GL10.GL_LUMINANCE, 
    GL10.GL_UNSIGNED_BYTE, ByteBuffer.wrap(this.cameraFrame)); //cameraFrame is the first half od byte[] from onPreviewFrame

gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
要实现这一点,您需要调用类构造函数或其他地方

例如,在onDraw中,如果您想修改颜色,您可以应用。如果您愿意,我可以发布一些这样的示例

所以这是可行的,但性能会很低(低于8fps),因为BitmapFactory.decodeByteArray速度很慢。您可以尝试使用本机代码和android NDK将数据从YUV转换为RGB,但这相当复杂

另一个选项是使用openGL ES。您需要GLSURFACHEVIEW,将相机帧绑定为纹理(在GLSURFACHEVIEW实现camera.previewCallback中,使用onPreviewFrame的方式与在常规曲面中相同)。但也存在同样的问题,您需要转换YUV数据。有一种可能性-您只能显示预览中的亮度数据(灰度图像)非常快,因为YUV中字节数组的前半部分只是没有颜色的亮度数据。因此,在PreviewFrame上,使用arraycopy复制数组的前半部分,然后像这样绑定纹理:

private byte[] cameraFrame;
private byte[] buffer;
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    cameraFrame = data;
    addCallbackBuffer(data); //actually, addCallbackBuffer(buffer) has to be called once sowhere before you call mCamera.startPreview();
}


private ByteOutputStream baos;
private YuvImage yuvimage;
private byte[] jdata;
private Bitmap bmp;
private Paint paint;

@Override //from SurfaceView
public void onDraw(Canvas canvas) {
    baos = new ByteOutputStream();
    yuvimage=new YuvImage(cameraFrame, ImageFormat.NV21, prevX, prevY, null);

    yuvimage.compressToJpeg(new Rect(0, 0, width, height), 80, baos); //width and height of the screen
    jdata = baos.toByteArray();

    bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length);

    canvas.drawBitmap(bmp , 0, 0, paint);
    invalidate(); //to call ondraw again
}
gl.glGenTextures(1, cameraTexture, 0);
int tex = cameraTexture[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, tex);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_LUMINANCE, 
    this.prevX, this.prevY, 0, GL10.GL_LUMINANCE, 
    GL10.GL_UNSIGNED_BYTE, ByteBuffer.wrap(this.cameraFrame)); //cameraFrame is the first half od byte[] from onPreviewFrame

gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
你不能用这种方式获得16-18 fps,你可以使用openGL制作一些过滤器。如果你愿意,我可以给你发送更多的代码,但是放在这里太长了


有关更多信息,您可以查看我的,但也没有一个好的解决方案…

您说YUV数据需要转换为RGB数据才能显示,这将提供大约8fps。android框架如何获得如此高的显示率(没有应用过滤器)?你认为他们正在将所有内容包装到openGL ES以获得大约20 fps的速度吗?:)更有可能的是,他们没有使用Android API:)它可能是用本机代码或类似的东西编写的(这只是一个猜测)…但是Android是开源的,所以你可以试着找到他们的代码是如何工作的:)Jaa-c,我想知道你是否可以用上面写的代码(而不是openGL)发布一个例子。我不知道如何将它们全部添加到一起才能正确工作,我知道这是一个较老的问题,但我在谷歌上找不到多少。或者你可以制作一个关于实现这一点的类的迷你教程吗?@JustinWarner:基本想法:但你至少应该在另一个线程中处理数据。请注意,这是可能的要使用OpenGL获得彩色显示,请使用片段着色器,例如。必须修改此代码,以说明Cb和Cr交错的NV21预览格式(而不是示例中的YUV420P)。