Camera2 api 图像格式。yuv_420_888 旋转图像的结果
Camera2 api Imageformat.yuv_420_888 results on rotated image
关于 camera2 api 和 RAW 图像格式的问题很多,但在网上搜索我仍然没有找到答案(顺便说一句,这就是我来这里的原因)。
我正在尝试使用 ImageReader 和前置摄像头的 setRepeatingRequest 对摄像头捕获的帧进行一些实时图像处理。正如之前一些帖子中所建议的,我正在获取 RAW 格式的图像(特别是 Imageformat。yuv_420_888)以便获得大约 30fps 的帧速率:
imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 2);
我的图像处理算法需要 RGB 图像作为输入,因此我需要将 YUV 转换为 RGB。为此,我使用 ScriptIntrinsicYuvToRGB
private static Bitmap YUV_420_888_toRGBIntrinsics(Image image) {
if (image == null) return null;
int W = image.getWidth();
int H = image.getHeight();
Image.Plane Y = image.getPlanes()[0];
Image.Plane U = image.getPlanes()[1];
Image.Plane V = image.getPlanes()[2];
int Yb = Y.getBuffer().remaining();
int Ub = U.getBuffer().remaining();
int Vb = V.getBuffer().remaining();
byte[] data = new byte[Yb + Ub + Vb];
Y.getBuffer().get(data, 0, Yb);
V.getBuffer().get(data, Yb, Vb);
U.getBuffer().get(data, Yb + Vb, Ub);
rs = RenderScript.create(context);
ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(data.length);
Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(W).setY(H);
Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
final Bitmap bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888);
in.copyFromUnchecked(data);
yuvToRgbIntrinsic.setInput(in);
yuvToRgbIntrinsic.forEach(out);
out.copyTo(bmpout);
image.close();
return bmpout ;
}
这种方法非常快,因为我可以在不到 20 毫秒的时间内转换 1080p 图像。唯一的问题是图像结果旋转了 270 度(即照片是在横向模式下拍摄的)。即使我在camera builder设置中设置了JPEG_ORIENTATION,captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION));
结果还是一样。
这是我的问题:
- 有没有办法通过 renderscript 内在函数取回旋转后的图像?
- 有没有不分配内存的“旋转”函数?
- 是否有YUV类型的图像旋转设置?
我尝试过的其他解决方案——矩阵旋转、YUV 阵列旋转——都非常慢。此外,我认为如果在拍摄后将图像旋转 90/180/270 是一件容易的事,只需要保存行而不是列(以某种方式)。
不,YUV 输出没有内置旋转。为了最大限度地减少开销,它始终由图像传感器按原样生成。您可以阅读 SENSOR_ORIENTATION 字段以确定图像传感器在设备上的放置方式;通常图像传感器的长边与 Android 设备的长边对齐,但这仍然留下两个有效的旋转。
此外,如果您的目标是获得图像 'upright',那么您还需要从加速度计读取设备的方向,并将其添加到旋转中。
您正在执行复制,已经将帧从图像获取到分配中,因此进行 90/180/270 度旋转相对简单,但会占用大量内存带宽。
您还可以查看 Google 的示例应用程序之一,HdrViewfinderDemo,它将相机数据通过管道传输到 RenderScript 中,而无需您正在执行的中间副本,然后转换为 RGB绘制到 SurfaceView。它现在没有旋转,但您可以调整通过 rsGetElementAtYuv_uchar_* 完成的查找以进行 90 次增量。
关于 camera2 api 和 RAW 图像格式的问题很多,但在网上搜索我仍然没有找到答案(顺便说一句,这就是我来这里的原因)。
我正在尝试使用 ImageReader 和前置摄像头的 setRepeatingRequest 对摄像头捕获的帧进行一些实时图像处理。正如之前一些帖子中所建议的,我正在获取 RAW 格式的图像(特别是 Imageformat。yuv_420_888)以便获得大约 30fps 的帧速率:
imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 2);
我的图像处理算法需要 RGB 图像作为输入,因此我需要将 YUV 转换为 RGB。为此,我使用 ScriptIntrinsicYuvToRGB
private static Bitmap YUV_420_888_toRGBIntrinsics(Image image) {
if (image == null) return null;
int W = image.getWidth();
int H = image.getHeight();
Image.Plane Y = image.getPlanes()[0];
Image.Plane U = image.getPlanes()[1];
Image.Plane V = image.getPlanes()[2];
int Yb = Y.getBuffer().remaining();
int Ub = U.getBuffer().remaining();
int Vb = V.getBuffer().remaining();
byte[] data = new byte[Yb + Ub + Vb];
Y.getBuffer().get(data, 0, Yb);
V.getBuffer().get(data, Yb, Vb);
U.getBuffer().get(data, Yb + Vb, Ub);
rs = RenderScript.create(context);
ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(data.length);
Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(W).setY(H);
Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
final Bitmap bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888);
in.copyFromUnchecked(data);
yuvToRgbIntrinsic.setInput(in);
yuvToRgbIntrinsic.forEach(out);
out.copyTo(bmpout);
image.close();
return bmpout ;
}
这种方法非常快,因为我可以在不到 20 毫秒的时间内转换 1080p 图像。唯一的问题是图像结果旋转了 270 度(即照片是在横向模式下拍摄的)。即使我在camera builder设置中设置了JPEG_ORIENTATION,captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION));
结果还是一样。
这是我的问题:
- 有没有办法通过 renderscript 内在函数取回旋转后的图像?
- 有没有不分配内存的“旋转”函数?
- 是否有YUV类型的图像旋转设置? 我尝试过的其他解决方案——矩阵旋转、YUV 阵列旋转——都非常慢。此外,我认为如果在拍摄后将图像旋转 90/180/270 是一件容易的事,只需要保存行而不是列(以某种方式)。
不,YUV 输出没有内置旋转。为了最大限度地减少开销,它始终由图像传感器按原样生成。您可以阅读 SENSOR_ORIENTATION 字段以确定图像传感器在设备上的放置方式;通常图像传感器的长边与 Android 设备的长边对齐,但这仍然留下两个有效的旋转。
此外,如果您的目标是获得图像 'upright',那么您还需要从加速度计读取设备的方向,并将其添加到旋转中。
您正在执行复制,已经将帧从图像获取到分配中,因此进行 90/180/270 度旋转相对简单,但会占用大量内存带宽。
您还可以查看 Google 的示例应用程序之一,HdrViewfinderDemo,它将相机数据通过管道传输到 RenderScript 中,而无需您正在执行的中间副本,然后转换为 RGB绘制到 SurfaceView。它现在没有旋转,但您可以调整通过 rsGetElementAtYuv_uchar_* 完成的查找以进行 90 次增量。