Android camera2 回调imagereader 从Image拿到YUV数据转化成RGB,生成bitmap并保存

Stella981
• 阅读 1069
ImageUtil.java

import android.graphics.ImageFormat;
import android.media.Image;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log;

import java.nio.ByteBuffer;

public class ImageUtil {
        public static final int YUV420P = 0;
        public static final int YUV420SP = 1;
        public static final int NV21 = 2;
        private static final String TAG = "ImageUtil";

        /***
         * 此方法内注释以640*480为例
         * 未考虑CropRect的
         */
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        public static byte[] getBytesFromImageAsType(Image image, int type) {
            try {
                //获取源数据,如果是YUV格式的数据planes.length = 3
                //plane[i]里面的实际数据可能存在byte[].length <= capacity (缓冲区总大小)
                final Image.Plane[] planes = image.getPlanes();

                //数据有效宽度,一般的,图片width <= rowStride,这也是导致byte[].length <= capacity的原因
                // 所以我们只取width部分
                int width = image.getWidth();
                int height = image.getHeight();

                //此处用来装填最终的YUV数据,需要1.5倍的图片大小,因为Y U V 比例为 4:1:1
                byte[] yuvBytes = new byte[width * height * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];
                //目标数组的装填到的位置
                int dstIndex = 0;

                //临时存储uv数据的
                byte uBytes[] = new byte[width * height / 4];
                byte vBytes[] = new byte[width * height / 4];
                int uIndex = 0;
                int vIndex = 0;

                int pixelsStride, rowStride;
                for (int i = 0; i < planes.length; i++) {
                    pixelsStride = planes[i].getPixelStride();
                    rowStride = planes[i].getRowStride();

                    ByteBuffer buffer = planes[i].getBuffer();

                    //如果pixelsStride==2,一般的Y的buffer长度=640*480,UV的长度=640*480/2-1
                    //源数据的索引,y的数据是byte中连续的,u的数据是v向左移以为生成的,两者都是偶数位为有效数据
                    byte[] bytes = new byte[buffer.capacity()];
                    buffer.get(bytes);

                    int srcIndex = 0;
                    if (i == 0) {
                        //直接取出来所有Y的有效区域,也可以存储成一个临时的bytes,到下一步再copy
                        for (int j = 0; j < height; j++) {
                            System.arraycopy(bytes, srcIndex, yuvBytes, dstIndex, width);
                            srcIndex += rowStride;
                            dstIndex += width;
                        }
                    } else if (i == 1) {
                        //根据pixelsStride取相应的数据
                        for (int j = 0; j < height / 2; j++) {
                            for (int k = 0; k < width / 2; k++) {
                                uBytes[uIndex++] = bytes[srcIndex];
                                srcIndex += pixelsStride;
                            }
                            if (pixelsStride == 2) {
                                srcIndex += rowStride - width;
                            } else if (pixelsStride == 1) {
                                srcIndex += rowStride - width / 2;
                            }
                        }
                    } else if (i == 2) {
                        //根据pixelsStride取相应的数据
                        for (int j = 0; j < height / 2; j++) {
                            for (int k = 0; k < width / 2; k++) {
                                vBytes[vIndex++] = bytes[srcIndex];
                                srcIndex += pixelsStride;
                            }
                            if (pixelsStride == 2) {
                                srcIndex += rowStride - width;
                            } else if (pixelsStride == 1) {
                                srcIndex += rowStride - width / 2;
                            }
                        }
                    }
                }

             //   image.close();

                //根据要求的结果类型进行填充
                switch (type) {
                    case YUV420P:
                        System.arraycopy(uBytes, 0, yuvBytes, dstIndex, uBytes.length);
                        System.arraycopy(vBytes, 0, yuvBytes, dstIndex + uBytes.length, vBytes.length);
                        break;
                    case YUV420SP:
                        for (int i = 0; i < vBytes.length; i++) {
                            yuvBytes[dstIndex++] = uBytes[i];
                            yuvBytes[dstIndex++] = vBytes[i];
                        }
                        break;
                    case NV21:
                        for (int i = 0; i < vBytes.length; i++) {
                            yuvBytes[dstIndex++] = vBytes[i];
                            yuvBytes[dstIndex++] = uBytes[i];
                        }
                        break;
                }
                return yuvBytes;
            } catch (final Exception e) {
                if (image != null) {
                    image.close();
                }
                Log.i(TAG, e.toString());
            }
            return null;
        }

    /***
     * YUV420 转化成 RGB
     */
    public static int[] decodeYUV420SP(byte[] yuv420sp, int width, int height)
    {
        final int frameSize = width * height;
        int rgb[] = new int[frameSize];
        for (int j = 0, yp = 0; j < height; j++) {
            int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
            for (int i = 0; i < width; i++, yp++) {
                int y = (0xff & ((int) yuv420sp[yp])) - 16;
                if (y < 0)
                    y = 0;
                if ((i & 1) == 0) {
                    v = (0xff & yuv420sp[uvp++]) - 128;
                    u = (0xff & yuv420sp[uvp++]) - 128;
                }
                int y1192 = 1192 * y;
                int r = (y1192 + 1634 * v);
                int g = (y1192 - 833 * v - 400 * u);
                int b = (y1192 + 2066 * u);
                if (r < 0)
                    r = 0;
                else if (r > 262143)
                    r = 262143;
                if (g < 0)
                    g = 0;
                else if (g > 262143)
                    g = 262143;
                if (b < 0)
                    b = 0;
                else if (b > 262143)
                    b = 262143;
                rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000)
                        | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
            }
        }
        return rgb;
    }
}

回调OnImageReader

private ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader) {
            Image image = reader.acquireLatestImage();

            int imageWidth = image.getWidth();
            int imageHeight = image.getHeight();

            byte[] data68 = ImageUtil.getBytesFromImageAsType(image,2);

            if(time==5) {
               int rgb[] = ImageUtil.decodeYUV420SP(data68, imageWidth, imageHeight);
                Bitmap bitmap2 = Bitmap.createBitmap(rgb, 0, imageWidth,
                        imageWidth, imageHeight,
                        android.graphics.Bitmap.Config.ARGB_8888);
                try {
                    File newFile = new File(Environment.getExternalStorageDirectory(), "345.png");
                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile));
                    bitmap2.compress(Bitmap.CompressFormat.PNG, 100, bos);
                    bos.flush();
                    bos.close();
                    bitmap2.recycle();
                } catch (Exception e) {

                }
            }

//            Message msg = Message.obtain();
//            msg.obj = bitmap2;
//            msg.what = 003;
//            runHandler.sendMessage(msg);

            image.close();
        }
    };
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
3年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Java修道之路,问鼎巅峰,我辈代码修仙法力齐天
<center<fontcolor00FF7Fsize5face"黑体"代码尽头谁为峰,一见秃头道成空。</font<center<fontcolor00FF00size5face"黑体"编程修真路破折,一步一劫渡飞升。</font众所周知,编程修真有八大境界:1.Javase练气筑基2.数据库结丹3.web前端元婴4.Jav
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这