Jaa*_*a-c 14 java camera android preview android-camera
我需要做的很简单,我想使用相机回调手动显示来自相机的预览,我想在真实设备上获得至少15fps.我甚至不需要颜色,我只需要预览灰度图像.来自相机的图像是YUV格式,你必须以某种方式处理它,这是主要的性能问题.我正在使用API 8.
在所有情况下,我都使用camera.setPreviewCallbackWithBuffer(),它比camera.setPreviewCallback()更快.如果我没有显示预览,我似乎无法在这里获得大约24 fps.所以没有问题.
我试过这些解决方案:
1.在SurfaceView上将相机预览显示为位图.它有效,但性能约为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);
Run Code Online (Sandbox Code Playgroud)
2.在GLSurfaceView上将相机预览显示为纹理.这里我只显示亮度数据(灰度图像),这非常简单,每帧只需要一个arraycopy().我可以得到大约12fps,但我需要在预览中应用一些过滤器,看起来,它无法在OpenGL ES 1中快速完成.所以我不能使用这个解决方案.另一个问题中的一些细节.
3.使用NDK在(GL)SurfaceView上显示相机预览以处理YUV数据.我在这里找到了一个使用一些C函数和NDK 的解决方案.但我没有设法使用它,这里有更多细节.但无论如何,这个解决方案是为了返回ByteBuffer在OpenGL中将其显示为纹理,并且它不会比之前的尝试更快.所以我必须修改它以返回int []数组,可以使用canvas.drawBitmap()绘制,但我不理解C足以执行此操作.
那么,我有没有其他方法可以避免或尝试一些改进?
我正在研究完全相同的问题,但还没有达到你的目标.
您是否考虑过将像素直接绘制到画布而不先将其编码为JPEG?在OpenCV工具包里面http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.3.1/OpenCV-2.3.1-android-bin.tar.bz2/download(实际上并没有使用opencv;不用担心),有一个名为tutorial-0-androidcamera的项目,演示如何将YUV像素转换为RGB,然后将它们直接写入位图.
相关代码基本上是:
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();
}
Run Code Online (Sandbox Code Playgroud)
当然,你必须调整它以满足你的需求(例如,不是每帧分配rgba),但它可能是一个开始.我很想知道它是否适合你 - 我现在还在与你的问题正交.
这不是你想要的吗?只需在布局中使用 SurfaceView,然后在 init 中的某个位置使用,例如onResume():
SurfaceView surfaceView = ...
SurfaceHolder holder = surfaceView.getHolder();
...
Camera camera = ...;
camera.setPreviewDisplay(holder);
Run Code Online (Sandbox Code Playgroud)
它只是在帧到达时将其直接发送到视图。
如果想要灰度,用 修改相机参数setColorEffect("mono")。
| 归档时间: |
|
| 查看次数: |
16948 次 |
| 最近记录: |