camera2 如何从图像读取器侦听器中的 YUV_420_888 图像中获取 Exif 数据

Posted

技术标签:

【中文标题】camera2 如何从图像读取器侦听器中的 YUV_420_888 图像中获取 Exif 数据【英文标题】:camera2 How to get Exif data from YUV_420_888 image in image reader listener 【发布时间】:2019-11-16 16:08:14 【问题描述】:

我正在尝试从 YUV_420_888 图像中获取 Exif 数据,但它不起作用。我尝试了几种解决方案,例如将图像作为 jpeg 保存到磁盘,将其转换为输入流,但似乎没有任何效果。

我使用 android camera2 api 捕获 YUV_420_888 图像。然后在 OnImageAvailableListener 中,我获取图像并尝试使用 ExifInterface API 读取其 EXIF 数据。但它总是空的。我尝试了 link 中的所有方法来获取正确的字节数组。

这是我的代码:

@Override
public void onImageAvailable(ImageReader imageReader) 
    if (!isRecording) 
        return;
    
    Image image = imageReader.acquireNextImage();
    File file = Util.getImagePath(context);

    OutputStream outputStream = null;
    try 
        outputStream = new FileOutputStream(file);
        outputStream.write(data); 
//// This byte array I am making using all the approaches given in this link 
https://***.com/questions/44022062/converting-yuv-420-888-to-jpeg-and-saving-file-results-distorted-image

     catch (Exception e) 
        e.printStackTrace();
     finally 
        try 
            outputStream.close();
         catch (IOException e) 
            e.printStackTrace();
        
    


    try 
        ExifInterface exifInterface = new ExifInterface(file.getAbsolutePath()); /// This is always empty
        int currentIso = (int)exifInterface.getAttributeDouble(ExifInterface.TAG_ISO_SPEED_RATINGS, 0); /// Always 0
     catch (Exception e) 
        e.printStackTrace();
    
    image.close();

编辑:捕获图像的代码:

captureRequest = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequest.addTarget(preview);
captureRequest.addTarget(imageReader.getSurface());
captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
captureRequest.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
captureRequest.set(CaptureRequest.SENSOR_SENSITIVITY, <MANUAL_ISO>);
captureRequest.set(CaptureRequest.SENSOR_EXPOSURE_TIME, <MANUAL_EXPOSURE>);
mSession.capture(captureRequest.build(), new CameraCaptureSession.CaptureCallback() 
        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) 
            int capturedISO = result.get(CaptureResult.SENSOR_SENSITIVITY);
            long timeStamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
/// Save somewhere to be used later
            super.onCaptureCompleted(session, request, result);
        
    , backgroundHandler);

【问题讨论】:

我认为YUV_420_888 格式不支持Exif 数据。在某些情况下,帧的第一行中有一些元数据,但这因相机而异。您使用的相机型号是什么? @Rotem 感谢您的回答。我也有同样的怀疑。我实际上是在使用 Android 的 Camera2 API 在 android 设备中捕捉照片。当我捕获 jpeg 但不能使用 YUV 时,我可以获得 exif 数据。我什至尝试将 YUV 保存为 jpeg 以希望获得 exif 数据,但它没有帮助。如果您可以添加任何输入,那将有很大帮助 我没有任何使用 Camera2 API 的经验,也没有使用 android 编程。我确实知道文件系统中的图像(如 JPEG、DNG、Tiff)支持 exif 数据,而不是像YUV_420_888 这样的 RAM 中的 RAW 帧。当将帧捕获到内存而不是磁盘时,可能还有其他 API 用于接收数据。根据文档,您可以使用TotalCaptureResult 类。 是的,我可以并且我确实使用了它,但是 TotalCaptueResult 没有满足我的用例。我必须以某种方式从图像中获取 exif 数据。 @Shivam 您正在尝试做的是,在新一代移动设备中几乎是不可能的。 Camera2 API 的开发考虑到现在的移动设备使用多个摄像头来捕捉单张图片。在这种情况下,将不提供元数据,因为图像不是直接来自物理相机而是来自逻辑平面。如果您捕获此图像,您可以在通过 ExifInterface 保存后在 onImageAvailable 中手动设置元数据 exif = new ExifInterface(mFile.getAbsolutePath()); exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, "10"); exif.saveAttributes(); 【参考方案1】:

Exif 信息放在CaptureResult 中,在CaptureCallback 中可用,在onCaptureCompleted 方法中 - 你应该“记住”你的类之一。当您的图像在onImageAvailableListener 中可用时,您应该保存图像,并“转换”结果以适应 exif 格式。同样,您可以查看DngCreator 类,它使用来自CaptureResult 的exif 数据保存图像。如果你是爆发,那就更复杂了。

【讨论】:

是的,我的做法完全相同,您可以在问题本身中看到我的代码,但问题是当我捕获大量图像时,如何比较 onImageAvailableListener 和 onCaptureCompleted 中的回调。仅供参考,我使用了时间戳,但没有成功,给出了错误的结果。 如果您发布 10 个捕获请求,那么您将以相同的顺序获得 10 个图像。如果您发布请求突发,那么您将获得每个图像的图像。这可以使用队列来完成。

以上是关于camera2 如何从图像读取器侦听器中的 YUV_420_888 图像中获取 Exif 数据的主要内容,如果未能解决你的问题,请参考以下文章

如何保存 YUV_420_888 图像?

在Android camera2下将YUV_420_888转换为位图的图像不正确

使用新的 Android camera2 api 从 YUV_420_888 进行 JPEG 编码时的绿色图像

Android Camera2 ImageReader 图像格式 YUV

在YUV_420_888中将图像从Android发送到OpenCV Mat中的JNI的最有效方式

当我将我的 rgb 位图转换为 yuv 时,它会产生红色图像。我想以 YUV 格式从图库中读取图像或将 RGB 位图转换为 YUV