poi*_*oae 16 camera android opengl-es filter
如何将自定义滤镜应用于相机输出中的单个帧,并显示它们.
到目前为止我尝试过的:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
虽然它的名字包含"绿色",但我实际上只是想以某种方式修改这些值(在这种情况下,颜色会稍微加强一些).长话短说,它不起作用.
我发现字节数组'data'是摄像头输出的副本; 但这并没有真正帮助,因为我需要'真正的'缓冲区.
我听说你可以用openGL来实现它.这听起来很复杂.
有没有更简单的方法?否则,这个openGL-surfaceView映射将如何工作?
Jaa*_*a-c 38
好的,有几种方法可以做到这一点.但是性能存在严重问题.来自摄像机的byte []采用YUV格式,如果要显示,必须将其转换为某种RGB格式.这种转换是非常昂贵的操作,并且显着降低了输出fps.
这取决于您实际想要对相机预览做什么.因为最好的解决方案是在没有回调的情况下绘制相机预览,并对相机预览进行一些效果.这是做有争议的reallity东西的常用方法.
但是如果你真的需要手动显示输出,有几种方法可以做到这一点.您的示例由于多种原因不起作用.首先,您根本不显示图像.如果你这样称呼:
mCamera.setPreviewCallback(new CameraGreenFilter());
mCamera.setPreviewDisplay(null);
Run Code Online (Sandbox Code Playgroud)
如果您的相机根本没有显示预览,则必须手动显示.并且你不能在onPreviewFrame方法中做任何昂贵的操作,因为数据的生命周期是有限的,它会在下一帧被覆盖.一个提示,使用setPreviewCallbackWithBuffer,它更快,因为它重用一个缓冲区而不必在每个帧上分配新的内存.
所以你必须做这样的事情:
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
}
Run Code Online (Sandbox Code Playgroud)
要使其工作,您需要在类构造函数或某个地方调用setWillNotDraw(false).
在onDraw中,您可以例如应用paint.setColorFilter(filter),如果要修改颜色.如果你愿意,我可以发布一些例子.
所以这会起作用,但性能会很低(小于8fps),因为BitmapFactory.decodeByteArray很慢.你可以尝试使用本机代码和android NDK将数据从YUV转换为RGB,但这非常复杂.
另一种选择是使用openGL ES.您需要GLSurfaceView,将相机框架绑定为纹理(在GLSurfaceView中实现Camera.previewCallback,因此您使用onPreviewFrame的方式与常规表面相同).但是存在同样的问题,需要转换YUV数据.有一次机会 - 您可以非常快速地显示预览(灰度图像)中的亮度数据,因为YUV中字节数组的前半部分只是没有颜色的亮度数据.所以在onPreviewFrame上你使用arraycopy来复制数组的前半部分,而不是像这样绑定纹理:
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);
Run Code Online (Sandbox Code Playgroud)
你不能以这种方式获得大约16-18 fps,你可以使用openGL来制作一些过滤器.如果你愿意,我可以给你发一些代码,但是这里放的时间太长了......
有关更多信息,您可以看到我的simillar问题,但也没有一个好的解决方案......
| 归档时间: |
|
| 查看次数: |
26288 次 |
| 最近记录: |