Android的:如何与回调显示摄像机preVIEW?回调、摄像机、Android、preVIEW

2023-09-12 22:47:39 作者:朕要上房揭瓦

首先 - 我已经工作了一段时间,尝试了几种解决方案,所以不要给我,你觉得在谷歌的第一个环节

First - I've been working on this for some time and tried several solutions, so do not send me the first link that you find on google.

我需要做的很简单,我想用相机回调手动显示来自摄像头preVIEW,我希望得到至少每秒15帧真实设备上。我甚至都不需要的颜色,我只需要preVIEW灰度图像。 从相机中的图像是YUV格式,你必须以某种方式处理它,这是主要的性能问题。我使用的API 8。

What I need to do is quite simple, I want to manually display preview from camera using camera callback and I want to get at least 15fps on a real device. I don't even need the colors, I just need to preview grayscale image. Images from camera are in YUV format and you have to process it somehow, which is the main performance problem. I'm using API 8.

在我使用camera.set previewCallbackWithBuffer()所有的情况下,比camera.set previewCallback快()。看来,我不能让约24 fps的这里,如果我不显示preVIEW。所以不存在这个问题。

In all cases I'm using camera.setPreviewCallbackWithBuffer(), that is faster than camera.setPreviewCallback(). It seems that I cant get about 24 fps here, if I'm not displaying the preview. So there is not the problem.

我曾尝试以下解决方案:

I have tried these solutions:

1。显示相机preVIEW在SurfaceView为位图。它的工作原理,但性能大约是6fps的。

1. Display camera preview on a SurfaceView as a Bitmap. It works, but the performance is about 6fps.

baos = new ByteOutputStream();
yuvimage=new YuvImage(cameraFrame, ImageFormat.NV21, prevX, prevY, null);

yuvimage.compressToJpeg(new Rect(0, 0, prevX, prevY), 80, baos);
jdata = baos.toByteArray();

bmp = BitmapFactory.decodeByteArray(jdata, 0, jdata.length); // Convert to Bitmap, this is the main issue, it takes a lot of time

canvas.drawBitmap(bmp , 0, 0, paint);

2。在GLSurfaceView显示相机preVIEW作为纹理。在这里,我只显示亮度数据(灰度图像),这是很容易,只需要一个arraycopy()对每一帧。我可以得到约12fps的,但我需要一些过滤器适用于preVIEW,似乎,它不能快速在OpenGL ES 1.这样做,我不能使用此解决方案。这在another问题。

2. Display camera preview on a GLSurfaceView as a texture. Here I was displaying only luminance data (greyscale image), which is quite easy, it requires only one arraycopy() on each frame. I can get about 12fps, but I need to apply some filters to the preview and it seems, that it can't be done fast in OpenGL ES 1. So I can't use this solution. Some details of this in another question.

3。显示相机preVIEW使用NDK 处理YUV数据(GL)SurfaceView。我找到一个解决办法这里使用一些C函数和NDK。但我没使用它,这里一些细节。但无论如何,这种解决方案是为了返回的ByteBuffer来显示它在OpenGL纹理,它不会比previous尝试更快。因此,我将不得不修改其返回INT []数组,可以与canvas.drawBitmap()可以得出,但我不知道ç足以做到这一点。

3. Display camera preview on a (GL)SurfaceView using NDK to process the YUV data. I find a solution here that uses some C function and NDK. But I didn't manage to use it, here some more details. But anyway, this solution is done to return ByteBuffer to display it as a texture in OpenGL and it won't be faster than the previous attempt. So I would have to modify it to return int[] array, that can be drawn with canvas.drawBitmap(), but I don't understand C enough to do this.

那么,有没有说我失踪或其他任何方式的一些改进,我试过吗?

So, is there any other way that I'm missing or some improvement to the attempts I tried?

感谢您的答复!

推荐答案

我的工作完全一样的问题,但没有得到很远,你有。

I'm working on exactly the same issue, but haven't got quite as far as you have.

你有没有考虑直接绘制像素到画布不用先将编码为JPEG?里面OpenCV的套件http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.3.1/OpenCV-2.3.1-android-bin.tar.bz2/download (这实际上并未使用OpenCV的,不用担心),有一个叫教程0 androidcamera项目演示转换YUV像素RGB,然后直接将它们写为位图

Have you considered drawing the pixels directly to the canvas without encoding them to JPEG first? Inside the OpenCV kit http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.3.1/OpenCV-2.3.1-android-bin.tar.bz2/download (which doesn't actually use opencv; don't worry), there's a project called tutorial-0-androidcamera that demonstrates converting the YUV pixels to RGB and then writing them directly to a bitmap.

相关code基本上是:

The relevant code is essentially:

public void onPreviewFrame(byte[] data, Camera camera, int width, int height) {
    int frameSize = width*height;
    int[] rgba = new int[frameSize+1];

    // Convert YUV to RGB
    for (int i = 0; i < height; i++)
        for (int j = 0; j < width; j++) {
            int y = (0xff & ((int) data[i * width + j]));
            int u = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 0]));
            int v = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 1]));
            y = y < 16 ? 16 : y;

            int r = Math.round(1.164f * (y - 16) + 1.596f * (v - 128));
            int g = Math.round(1.164f * (y - 16) - 0.813f * (v - 128) - 0.391f * (u - 128));
            int b = Math.round(1.164f * (y - 16) + 2.018f * (u - 128));

            r = r < 0 ? 0 : (r > 255 ? 255 : r);
            g = g < 0 ? 0 : (g > 255 ? 255 : g);
            b = b < 0 ? 0 : (b > 255 ? 255 : b);

            rgba[i * width + j] = 0xff000000 + (b << 16) + (g << 8) + r;
        }

    Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    bmp.setPixels(rgba, 0/* offset */, width /* stride */, 0, 0, width, height);
    Canvas canvas = mHolder.lockCanvas();
    if (canvas != null) {
        canvas.drawBitmap(bmp, (canvas.getWidth() - width) / 2, (canvas.getHeight() - height) / 2, null);
        mHolder.unlockCanvasAndPost(canvas);
    } else {
        Log.w(TAG, "Canvas is null!");
    }
    bmp.recycle();
}

当然,你必须去适应它,以满足您的需求(例如:不分配RGBA每帧),但也可能是一个开始。我很想看看它是否适合你或不 - 。我仍然在目前战斗的问题正交到你的

Of course you'd have to adapt it to meet your needs (ex. not allocating rgba each frame), but it might be a start. I'd love to see if it works for you or not -- i'm still fighting problems orthogonal to yours at the moment.