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 数据的主要内容,如果未能解决你的问题,请参考以下文章
在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