背景
在Android开发中我们有时候会需要拿到相机预览数据转成bitmap自己做处理。
常用方式
在Android API中提供了 一套转换方式:
private Bitmap convertBitmap(byte[] data) {
try {
Camera.Size size = mCameraParameters.getPreviewSize();
YuvImage img = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length);
img.compressToJpeg(new Rect(0, 0, size.width, size.height), 100, baos);
byte[] bytes = baos.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
baos.close();
return bitmap ;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//logcat
2022-07-21 11:07:36.389 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:199
2022-07-21 11:07:36.813 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:228
2022-07-21 11:07:37.181 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:199
2022-07-21 11:07:37.552 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:199
2022-07-21 11:07:37.951 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:207
2022-07-21 11:07:38.352 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:201
2022-07-21 11:07:38.750 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:207
2022-07-21 11:07:39.174 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:232
2022-07-21 11:07:39.542 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:199
2022-07-21 11:07:39.907 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:200
2022-07-21 11:07:40.277 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:200
2022-07-21 11:07:40.675 18675-18675/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:201
通过日志看到这种方式转换耗时约200ms
优化方案1
在上述转换过程中img.compressToJpeg()函数中第2个参数表示转换图像的质量,参数范围在0-100,100表示最高质量,我们可以把质量降低一些,这里改成80:
private Bitmap convertBitmap2(byte[] data) {
try {
Camera.Size size = mCameraParameters.getPreviewSize();
YuvImage img = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length);
img.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, baos);
byte[] bytes = baos.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
baos.close();
return bitmap ;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//logcat
2022-07-21 11:12:33.946 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:112
2022-07-21 11:12:34.074 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:111
2022-07-21 11:12:34.378 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:113
2022-07-21 11:12:34.505 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:111
2022-07-21 11:12:34.815 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:118
2022-07-21 11:12:34.942 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:114
2022-07-21 11:12:35.248 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:117
2022-07-21 11:12:35.544 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:118
2022-07-21 11:12:35.675 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:115
2022-07-21 11:12:35.981 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:116
2022-07-21 11:12:36.280 19171-19171/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:117
通过日志看到耗时约110ms,优化空间还是很大的,但是牺牲了图像的质量,不过通过在设备中的观察,降低到80的质量与100质量的图像看起来差别不大,因此也还可以用。
下面继续将质量降低到40
private Bitmap convertBitmap2(byte[] data) {
try {
Camera.Size size = mCameraParameters.getPreviewSize();
YuvImage img = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length);
img.compressToJpeg(new Rect(0, 0, size.width, size.height), 40, baos);
byte[] bytes = baos.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
baos.close();
return bitmap ;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//logcat
2022-07-21 11:15:48.097 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:104
2022-07-21 11:15:48.226 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:104
2022-07-21 11:15:48.530 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:107
2022-07-21 11:15:48.656 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:103
2022-07-21 11:15:48.927 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:104
2022-07-21 11:15:49.059 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:103
2022-07-21 11:15:49.364 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:108
2022-07-21 11:15:49.488 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:104
2022-07-21 11:15:49.757 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:105
2022-07-21 11:15:49.888 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:104
2022-07-21 11:15:50.191 19529-19529/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:104
查看日志看到质量40时耗时约100,这个优化空间是很小的,并且图像的质量已经很差了,因此不推荐。
优化方案2
使用Android的RenderScript来转换
private Bitmap convertBitmap4RenderScript(byte[] data) {
Camera.Size size = mCameraParameters.getPreviewSize();
if (yuvType == null) {
yuvType = new Type.Builder(rs, Element.U8(rs)).setX(data.length);
in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
}
if (rgbaType == null) {
rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(size.width).setY(size.height);
out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
}
in.copyFrom(data);
yuvToRgbIntrinsic.setInput(in);
yuvToRgbIntrinsic.forEach(out);
Bitmap bitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.ARGB_8888);
out.copyTo(bitmap);
return bitmap;
}
//logcat
2022-07-21 11:21:01.082 19879-19879/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:25
2022-07-21 11:21:01.147 19879-19879/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:24
2022-07-21 11:21:01.215 19879-19879/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:25
2022-07-21 11:21:01.280 19879-19879/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:23
2022-07-21 11:21:01.348 19879-19879/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:25
2022-07-21 11:21:01.414 19879-19879/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:24
2022-07-21 11:21:01.480 19879-19879/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:23
2022-07-21 11:21:01.548 19879-19879/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:25
2022-07-21 11:21:01.610 19879-19879/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:22
2022-07-21 11:21:01.680 19879-19879/org.venus.ar.ocr I/System.out: 相机数据转换bitmap时间:23
通过日志可以看出使用RenderScript的内联函数转换bitmap耗时约25ms,相较于使用BitmapFactory.decodeByteArray()函数转换耗时少了很多。
其中使用到RenderScript相关变量的定义和初始化:
//相机预览数据byte[]转bitmap耗时优化方案对象
private RenderScript rs;
private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
private Type.Builder yuvType;
private Type.Builder rgbaType;
private Allocation in;
private Allocation out;
private void initRender() {
rs = RenderScript.create(this);
yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
}
在使用yuvToRgbIntrinsic对象之前执行initRender()函数初始化即可,一般放在onCreate()函数中。
网友评论