zoukankan      html  css  js  c++  java
  • Android camera2 回调imagereader 从Image拿到YUV数据转化成RGB,生成bitmap并保存

    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();
            }
        };
  • 相关阅读:
    全站301跳转 PHP
    linux flush memcache缓存
    php Memcache
    PHP MemCached win安装
    windows下安装memcache
    2013 年最好的 20 款免费 jQuery 插件
    License Manager 10.3启动失败解决方法
    .ecp认证文件(10.3版本)
    ArcGIS 10.3 安装及破解
    win7下安装MYSQL报错:"MYSQL 服务无法启动"的3534问题
  • 原文地址:https://www.cnblogs.com/Jackie-zhang/p/10084947.html
Copyright © 2011-2022 走看看