2022-07-21 Android 相机预览数据转Bitmap优化

背景

在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()函数中。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值