设为首页 加入收藏

TOP

android camera2 拍摄yuv图片,并将yuv 保存成Bitmap的方法(一)
2023-07-23 13:29:30 】 浏览:44
Tags:android camera2 拍摄 yuv 图片 并将 Bitmap 方法

一、yuv简介
yuv420p和yuv420sp
yuv420p(例如yv12):每两行的4个字节对应一个像素的y,每两行的2个字节(uv)对应前面的一个像素的y
yuv420sp(例如nv21):每两行的4个字节对应一个像素的y,每一行两个字节(uv)对应前面的一个像素的y
例如yv12 格式6*4
YYYYYY
YYYYYY
YYYYYY
YYYYYY
VVVVVV
UUUUUU
例如nv21 格式6*4
YYYYYY
YYYYYY
YYYYYY
YYYYYY
VUVUVU
VUVUVU

二、camera2 Android回调imagereader返回的 YUV_420_888 数据,存储方式
image = reader.acquireLatestImage();
Image.Plane[] planes = image.getPlanes(); //获取yuv图像的平面个数,plane0返回的是y分量
Image.Plane plane = planes[i];
Buffer buffer = plane.getBuffer();
1.buffer.remaining() 获取对应平面字节个数,
2.plane.getPixelStride() 获取对应平面的字节步长
3.plane.getRowStride() 获取对应平面的行步长
预览分辨率为:1280*720,这是获取的 YUV_420_888格式对应的yuv数据log日志,从log看看plane1和plane2 的getPixelStride 是2, 说明间隔的原色才是有效的元素
即plane1的行内索引为0,2,4,6..对应的是u分量中间插入的是v分量,且数组长度是1280*720/2 -1
即plane2的行内索引为0,2,4,6..对应的是v分量中间插入的是u分量,
2023-03-06 10:36:54.068 31203-31258 Camera2Fragment I getByteFromYuvReader() planes.length:3
2023-03-06 10:36:54.068 31203-31258 Camera2Fragment I getByteFromYuvReader() i:0 buffer.remaining:921600 getPixelStride:1 getRowStride:1280
2023-03-06 10:36:54.068 31203-31258 Camera2Fragment I getByteFromYuvReader() i:1 buffer.remaining:460799 getPixelStride:2 getRowStride:1280
2023-03-06 10:36:54.068 31203-31258 Camera2Fragment I getByteFromYuvReader() i:2 buffer.remaining:460799 getPixelStride:2 getRowStride:1280

三、拍摄yuv 并转换为bitmap 保存的代码实现
1.拍摄yuv格式图片的方法
mImageReader = ImageReader.newInstance(Config.SHOOT_PIC_WIDTH,
Config.SHOOT_PIC_HEIGHT, ImageFormat.YUV_420_888, 1);

ps:Android官方 Android camera api1 默认是:NV21,Android camera api2建议使用YUV_420_888

2.在 imagereader.onImageAvailable 回调处理
if (ImageFormat.YUV_420_888 == reader.getImageFormat()) {
Bitmap bitmap = getBitmapFromYuvReader(reader);
}

//从ImageReader中读取yuv并转成bitmap
private synchronized Bitmap getBitmapFromYuvReader(ImageReader reader) {
if (null == reader) {
Logger.i(TAG, "getBitmapFromYuvReader() reader is null return null");
return null;
}

Image image = null;
try {
byte[] plane0Y = null;
byte[] plane1WithU = null; //plane1 包含u
byte[] plane2WithV = null; //plane2 包含v
byte[] u = null;//真实的u
byte[] v = null;//真实的u
// fos = new FileOutputStream(file);
//获取捕获的照片数据
image = reader.acquireLatestImage();
if (null == image) {
Logger.w(TAG, "getBitmapFromYuvReader() image is null");
return null;
}
Image.Plane[] planes = image.getPlanes();
Logger.i(TAG, "getBitmapFromYuvReader() planes.length:" + planes.length);
if (planes.length != 3) {
return null;
}
// 重复使用同一批byte数组,减少gc频率
if (plane0Y == null || plane1WithU == null || plane2WithV == null) {
plane0Y = new byte[planes[0].getBuffer().limit() - planes[0].getBuffer().position()];
plane1WithU = new byte[planes[1].getBuffer().limit() - planes[1].getBuffer().position()];
plane2WithV = new byte[planes[2].getBuffer().limit() - planes[2].getBuffer().position()];
}
for (int i = 0; i < planes.length; i++) {
Image.Plane plane = planes[i];
Buffer buffer = plane.getBuffer();
//1280*720
Logger.i(TAG, "getBitmapFromYuvReader() i:" + i + " buffer.remaining:" + buffer.remaining()
+ " getPixelStride:" + plane.getPixelStride() + " getRowStride:" + plane.getRowStride());
}
if (image.getPlanes()[0].getBuffer().remaining() == plane0Y.length) {
planes[0].getBuffer().get(plane0Y);
planes[1].getBuffer().get(plane1WithU);
pla

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇集成华为运动健康服务干货总览 下一篇关于RecycleView的子元素锁定吸顶..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目