相机原始数据转Bitmap

作者: 夕hl月 | 来源:发表于2019-06-17 13:26 被阅读22次

    项目中需要用到人脸识别技术,外接的第三方人脸识别sdk,用的是本地离线识别方案,但是在注册时和识别人脸成功时都需要获取Bitmap位图对象,在SDK的说明文档上面,我们拿到的是Raw格式图像,这时就需要将Raw格式转成我们需要的Bitmap格式。
    格式转化方法如下:

    /**
     * Raw转Bitmap
     *  on 2019/6/17.
     */
    public class RawToBitMap {
        /**
         * 从流中读取数组
         *
         * @param stream 输入流
         * @return
         */
        public static byte[] readByteArrayFormStream(InputStream stream) {
            try {
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                int len = 0;
                byte[] tmp = new byte[1024];
                while ((len = stream.read(tmp)) != -1) {
                    outStream.write(tmp, 0, len);
                }
    
                byte[] data = outStream.toByteArray();
    
                return data;
            } catch (IOException e) {
                e.printStackTrace();
                return new byte[0];
            }
        }
    
        /**
         * 8位灰度转Bitmap
         * <p>
         * 图像宽度必须能被4整除
         *
         * @param data   裸数据
         * @param width  图像宽度
         * @param height 图像高度
         * @return
         */
        public static Bitmap convert8bit(byte[] data, int width, int height) {
            byte[] Bits = new byte[data.length * 4]; //RGBA 数组
    
            int i;
            for (i = 0; i < data.length; i++) {
                // 原理:4个字节表示一个灰度,则RGB  = 灰度值,最后一个Alpha = 0xff;
                Bits[i * 4] = Bits[i * 4 + 1] = Bits[i * 4 + 2] = data[i];
                Bits[i * 4 + 3] = -1; //0xff
            }
    
            // Bitmap.Config.ARGB_8888 表示:图像模式为8位
            Bitmap bmp = Bitmap
                    .createBitmap(width, height, Bitmap.Config.ARGB_8888);
            bmp.copyPixelsFromBuffer(ByteBuffer.wrap(Bits));
    
            return bmp;
        }
    
        /**
         * 24位灰度转Bitmap
         * <p>
         * 图像宽度必须能被4整除
         *
         * @param data   裸数据
         * @param width  图像宽度
         * @param height 图像高度
         * @return
         */
        public static Bitmap convert24bit(byte[] data, int width, int height) {
            byte[] Bits = new byte[data.length * 4]; //RGBA 数组
    
            int i;
    
            // data.length / 3 表示 3位为一组
            for (i = 0; i < data.length / 3; i++) {
                // 原理:24位是有彩色的,所以要复制3位,最后一位Alpha = 0xff;
                Bits[i * 4] = data[i * 3];
                Bits[i * 4 + 1] = data[i * 3 + 1];
                Bits[i * 4 + 2] = data[i * 3 + 2];
                Bits[i * 4 + 3] = -1;
            }
    
            // Bitmap.Config.ARGB_8888 表示:图像模式为8位
            Bitmap bmp = Bitmap
                    .createBitmap(width, height, Bitmap.Config.ARGB_8888);
            bmp.copyPixelsFromBuffer(ByteBuffer.wrap(Bits));
    
            return bmp;
        }
    
        /**
         * 8位灰度转Bitmap
         *
         * @param stream 输入流
         * @param width  图像宽度
         * @param height 图像高度
         * @return
         */
        public static Bitmap convert8bit(InputStream stream, int width, int height) {
            return convert8bit(readByteArrayFormStream(stream), width, height);
        }
    
        /**
         * 24位灰度转Bitmap
         *
         * @param stream   输入流
         * @param width  图像宽度
         * @param height 图像高度
         * @return
         */
        public static Bitmap convert24bit(InputStream stream, int width, int height) {
            return convert24bit(readByteArrayFormStream(stream), width, height);
        }
    }
    

    但是转化得到的是黑白的图像,换了好几次格式也都不行。于是放弃了这种方法,根据回调方法拿到的原始数据中,看到了原始格式应该是nv21格式,又通过百度大法找到了nv21格式转Bitmap的方法,然后发现该方法是可行的,代码如下:

    /**
     * by 2019/6/17.
     */
    public class NV21ToBitmap {
        private RenderScript rs;
        private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
        private Type.Builder yuvType, rgbaType;
        private Allocation in, out;
    
        public NV21ToBitmap(Context context) {
            rs = RenderScript.create(context);
            yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
        }
    
        public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) {
            if (yuvType == null) {
                yuvType = new Type.Builder(rs, Element.U8(rs)).setX(nv21.length);
                in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
                rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height);
                out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
            }
            in.copyFrom(nv21);
            yuvToRgbIntrinsic.setInput(in);
            yuvToRgbIntrinsic.forEach(out);
            Bitmap bmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            out.copyTo(bmpout);
            return bmpout;
        }
    }
    

    感谢简书作者一杯茶一本书提供的文章
    原文地址:https://www.jianshu.com/p/d61443506687

    相关文章

      网友评论

        本文标题:相机原始数据转Bitmap

        本文链接:https://www.haomeiwen.com/subject/vmtafctx.html