android - 如何使用 SurfaceView android 处理来自相机的帧

标签 android bitmap android-camera surfaceview

我在项目中工作,我从 Android 相机捕获帧 fps。在将每个帧转换为位图以使用带有 opencv SDK 的 native 库之后,以及在 ImageView 中显示此位图之后。此过程会消耗堆内存并影响应用程序的性能。我在 manifest.xml 中添加下一个标记以增加堆内存:

<application
    android:name="app"
    android:largeHeap="true" />

有了这个,应用程序在 Debug模式下生成 apk 版本时工作正常,但是在 Release模式下生成 apk 版本时,应用程序非常慢并且不能正常工作,性能存在问题。

我使用 SurfaceView 组件从相机获取帧的逻辑工作,我使用 SurfaceView 因为我需要在应用程序内部的后台使用,我想问你,我如何解决这个问题,指望你帮助。

我正在使用此逻辑来获取帧:

public synchronized void onPreviewFrame(final byte[] data, final Camera camera) {
        executorService.execute(new Runnable() {
            public void run() {

      Camera.Parameters parameters = camera.getParameters();
      orientation = getOrientationDevice().getOrientation();
      orientation = normalize(orientation);

      //converter yuv to bitmap
      int width = parameters.getPreviewSize().width;
      int height = parameters.getPreviewSize().height;
      YuvImage yuv = new YuvImage(data,PreviewFormat,width, height, null);
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      yuv.compressToJpeg(new Rect(0, 0, width, height), 80, out);
      byte[] bytes = out.toByteArray();
      Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

               // rotate image 
             if (cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT){
                    matrix.setScale(-1, 1);
                    matrix.postTranslate(bitmap.getWidth(), 0);
                    matrix.postRotate(rotation + 90);
                } else {
                    matrix.postRotate(rotation + 90);
                }                        

               // process bitmap from method jni
                ....

               // to pass bitmap a ImageView to show
               mCameraFrame.onFrame(bitmap.copy(bitmap.getConfig(), false));


            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
                bitmap = null;
            }


            camera.addCallbackBuffer(data);

            return;

            });

        }

    };

在 UI 中回调接收位图以在 Imageview 中显示

@Override
    public void onFrame(final Bitmap mBitmap) {

        this.bitmapWeakReference = new WeakReference<Bitmap>(mBitmap);

        if (imageViewReference != null && bitmapWeakReference.get() != null) {
            final ImageView imageView = imageViewReference.get();
            if (imageView != null) {

                imageView.post(new Runnable() {
                    @Override
                    public void run() {
                        imageView.setImageBitmap(bitmapWeakReference.get());
                    }
                });

            }
        }

最佳答案

以高帧率使​​用相机 API 需要将相机回调推送到主 UI 线程之外,您将需要 separate Handler thread为了那个原因。摆脱 onPreviewFrame() 回调中所有不必要的处理。您可以预先计算相机参数。避免 new,即使是 Rect:垃圾收集可能会降低性能。

您可以通过 JNI 将 YUV 帧提供给基于 OpenCV 的 native JNI,并且所有转换和转换都可以更快地执行。

如果您不对每个位图都使用 OpenCV,则无需通过 JPEG 即可将 YUV 转换为 RGB。通过这种转换,可以一步完成旋转90°。

如果您在多核设备上运行,您可以使用 newFixedThreadPool() 启动 executorService,但随后释放相机缓冲区(调用 camera.addCallbackBuffer())可能需要精细的管理,尤其是当您希望帧速率统一时。

如果只是想显示两份预览流,可以使用OpenGL,CPU根本不会参与旋转和YUV到RGB的转换。您甚至可以对通过 OpenGL 显示的纹理应用一些高级图像处理。

关于android - 如何使用 SurfaceView android 处理来自相机的帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34420104/

相关文章:

android - 在圆形 ImageView 外创建边框

android - 使用 drawBitmap 和矩形缩放位图 - Android

java - Android 存储位图数组

android - 如何在 INTENT_ACTION_STILL_IMAGE_CAMERA 中为新照片指定目录

android - Camera.takePicture 抛出 RunTimeException

java - 将文件路径更改为更常见的文件夹

android - 在房间数据库中更新 List<Boolean> 时 TypeConverter 不工作

android - 取消选中自定义 ListView 中的所有复选框

android - 当 View 大于图像时,Fresco Debug Overlay 显示红色

android - 哪个 View 是 android 相机预览的最佳选择?