Android 使用camera2 API获取单个图像并用ImageView显示

Android 使用camera2 API获取单个图像并用ImageView显示,android,android-camera2,Android,Android Camera2,我想使用Camera2 API从相机获取一帧,并使用ImageView显示它。 我发现了一些密切相关的问题,比如 我也看过Camera2的基本示例,但它太复杂了,不完全是我需要的 我写的代码,是基于我在网上看到的一些例子,应该可以做到,但它不起作用,我不知道为什么 该应用程序不会崩溃,但不会在ImageView上显示任何内容。 我在任何函数调用中都使用日志消息,以便尝试保持logcat的清晰 另外,应用程序是logcat,它说“应用程序可能在后台做了太多的工作……”我不明白这怎么可能,因为我只

我想使用Camera2 API从相机获取一帧,并使用ImageView显示它。 我发现了一些密切相关的问题,比如

我也看过Camera2的基本示例,但它太复杂了,不完全是我需要的

我写的代码,是基于我在网上看到的一些例子,应该可以做到,但它不起作用,我不知道为什么

该应用程序不会崩溃,但不会在ImageView上显示任何内容。 我在任何函数调用中都使用日志消息,以便尝试保持logcat的清晰

另外,应用程序是logcat,它说“应用程序可能在后台做了太多的工作……”我不明白这怎么可能,因为我只做了一个
captureRequest
,而不是一个
repeatingCaptureRequest

以下是代码和日志: 代码:

谢谢,
Noam

尝试这种方式,以便在后台线程中更好地处理它

 public void onImageAvailable(ImageReader reader) {
        new ImageSaver(reader.acquireLatestImage());
    } 

   private class ImageSaver implements Runnable {

        private final Image mImage;

        public ImageSaver(Image image) {
            mImage = image;
        }

        @Override
        public void run() {
            File mImageFileName = null;
            if (mImage != null) {

                ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer();
                byte[] bytes = new byte[byteBuffer.remaining()];
                byteBuffer.get(bytes);

                FileOutputStream fileOutputStream = null;
                try {
                    mImageFileName = createImageFileName();
                    fileOutputStream = new FileOutputStream(mImageFileName);
                    fileOutputStream.write(bytes);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    mImage.close();
                    if (mImageFileName != null) {
                        Intent mediaStoreUpdateIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                        mediaStoreUpdateIntent.setData(Uri.fromFile(mImageFileName));
                        sendBroadcast(mediaStoreUpdateIntent);
                        loadImageFromStorage(mImageFileName);
                    }
                    if (fileOutputStream != null) {
                        try {
                            fileOutputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }

        private void loadImageFromStorage(File mImageFileName) {
            imageView.setImageBitmap(BitmapFactory.decodeFile(mImageFileName.getAbsolutePath()));
        }
    }

    private File createImageFileName() throws IOException {
        String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String prepend = "IMAGE_" + timestamp + "_";
        File imageFile = File.createTempFile(prepend, ".jpg", createImageFolder());
        return imageFile;
    }

    private File createImageFolder() {
        File imageFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File mImageFolder = new File(imageFile, "myFolder");
        if (!mImageFolder.exists()) {
            mImageFolder.mkdirs();
        }
        return mImageFolder;
    }

RGB_565是否从CameraManager.getCameraCharacteristics(id).get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputFormats()中列为此相机设备支持的格式

如果没有,这通常不起作用,尽管它会导致会话创建失败。保证支持的唯一格式是ImageFormat.JPEG和ImageFormat.YUV_420_888

前者可能更容易处理(虽然效率稍低)-将JPEG平面[0]ByteBuffer复制到字节[]中,并使用BitmapFactory.decodeByteArray()从中创建位图以显示

但是,对于您的特定情况,您似乎从未调用过imageReader.setOnImageAvailableListener(imageReaderListener),因此您永远不会收到关于捕获缓冲区的通知

编辑: 此外,您从相机接收到的前几张图像可能曝光不良(如果您在光线不好的位置,则可能全部为黑色),并且白平衡、焦距等较差。您需要让相机运行几帧,以便在拍摄最终图像之前,它可以将自动曝光/焦距/etc调整为正确的值


通常,使用带有模板预览的重复请求并等待至少看到捕获结果中聚合的控制状态是一个好主意;这仍然会使focus处于一种潜在的糟糕状态,但是您是否想要处理focus取决于用例和输出分辨率。

因为这个问题有点老了,不确定它是否仍然是热门话题,但我会尝试回答

您正在创建
ImageRader
的实例,即
ImageReader.OnImageAvailableListener
,但未将侦听器分配给您拥有的ImageReader实例

setupCamera
方法中,实例化新的ImageReader后,将侦听器设置为:

/**
 * Sets the cameraId with the front camera id and sets imageReader properties.
 */
public void setupCamera(int width, int height) {
    imageReader = ImageReader.newInstance(width, height, ImageFormat.RGB_565, 30);
    // this line is missing
    imageReader.setOnImageAvailableListener(imageReaderListener, handler);
...

希望这有助于您或其他人试用您的代码作为示例。

感谢您的回答,但您是否测试了您的代码?它包含一些错误,而且我真的不需要将帧保存在手机存储器中,我只想在imageView上显示..简单的想法是,您可以从字节[]创建位图而不保存它。
 public void onImageAvailable(ImageReader reader) {
        new ImageSaver(reader.acquireLatestImage());
    } 

   private class ImageSaver implements Runnable {

        private final Image mImage;

        public ImageSaver(Image image) {
            mImage = image;
        }

        @Override
        public void run() {
            File mImageFileName = null;
            if (mImage != null) {

                ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer();
                byte[] bytes = new byte[byteBuffer.remaining()];
                byteBuffer.get(bytes);

                FileOutputStream fileOutputStream = null;
                try {
                    mImageFileName = createImageFileName();
                    fileOutputStream = new FileOutputStream(mImageFileName);
                    fileOutputStream.write(bytes);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    mImage.close();
                    if (mImageFileName != null) {
                        Intent mediaStoreUpdateIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                        mediaStoreUpdateIntent.setData(Uri.fromFile(mImageFileName));
                        sendBroadcast(mediaStoreUpdateIntent);
                        loadImageFromStorage(mImageFileName);
                    }
                    if (fileOutputStream != null) {
                        try {
                            fileOutputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }

        private void loadImageFromStorage(File mImageFileName) {
            imageView.setImageBitmap(BitmapFactory.decodeFile(mImageFileName.getAbsolutePath()));
        }
    }

    private File createImageFileName() throws IOException {
        String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String prepend = "IMAGE_" + timestamp + "_";
        File imageFile = File.createTempFile(prepend, ".jpg", createImageFolder());
        return imageFile;
    }

    private File createImageFolder() {
        File imageFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File mImageFolder = new File(imageFile, "myFolder");
        if (!mImageFolder.exists()) {
            mImageFolder.mkdirs();
        }
        return mImageFolder;
    }
/**
 * Sets the cameraId with the front camera id and sets imageReader properties.
 */
public void setupCamera(int width, int height) {
    imageReader = ImageReader.newInstance(width, height, ImageFormat.RGB_565, 30);
    // this line is missing
    imageReader.setOnImageAvailableListener(imageReaderListener, handler);
...