简体   繁体   English

使用平面4:2:0 YUV全比例像素格式将图像从字节数组转换为位图

[英]Convert image from byte array to bitmap with planar 4:2:0 YUV full scale pixel format

Update: I contacted the vendor of the device and they let me know it is using the planar 4:2:0 YUV full scale pixel format. 更新:我联系了该设备的供应商,他们让我知道它使用的是平面4:2:0 YUV全尺寸像素格式。 Upon researching I found out there seem to be 3 major formats for YUV 4:2:0 : I420, J420 and YV12. 经研究,我发现YUV 4:2:0似乎有3种主要格式:I420,J420和YV12。 I was excited because there were constants for this image format in the android YuvImage class, when running my code however I got the the following exception: 我很兴奋,因为在运行我的代码时,Android YuvImage类中存在此图像格式的常量,但是出现以下异常:

java.lang.IllegalArgumentException: only support ImageFormat.NV21 and ImageFormat.YUY2 for now

Well thats a bummer.. 好吧,真是令人um目结舌..

After that I learned about the differences between YUV420 and NV21: 之后,我了解了YUV420和NV21之间的区别: YUV420 YUV420_NV21

I tried to write some simple function to interleave the 2 chroma planes like shown in the NV21 pixel format image. 我尝试编写一些简单的函数来交错2个色度平面,如NV21像素格式的图像所示。

 public static void convertYUY420ToNV21(byte[] data_yuv420, byte[] data_yuv_N21) {
    int idx = (int) (data_yuv_N21.length * (2.0f / 3.0f));
    int j = idx;
    int chroma_plane_end = (int) (idx + ((data_yuv_N21.length - idx) / 2));

    for (int i = idx; i < chroma_plane_end; i++) {
        data_yuv_N21[j] = data_yuv420[i];
        j += 2;
    }
    j = idx + 1;
    for (int i = chroma_plane_end; i < data_yuv_N21.length; i++) {
        data_yuv_N21[j] = data_yuv420[i];
        j += 2;
    }

However, the result seems still the same as from my original code.. One possible reason I was thinking about was the size of the byte array (1843200). 但是,结果似乎仍与原始代码相同。我在考虑的一个可能原因是字节数组(1843200)的大小。 I read that for YUV420 the depth of one pixel is 12bit. 我读到对于YUV420,一个像素的深度是12位。 The camera resolution is 1280x720 which are 921,600 pixels or 1,382,400 bytes. 相机分辨率为1280x720,即921,600像素或1,382,400字节。 That is one third less than the actual byte array size. 这比实际的字节数组大小小三分之一。 I read there might be some padding between the planes but I'm stuck on how to find out about that. 我读到飞机之间可能有一些填充物,但我一直在寻找有关方法。

The YuvImage class has a strides parameter in its constructor but I'm not sure how to use even after reading the android developer documentation. YuvImage类在其构造函数中具有strides参数,但即使阅读了android开发人员文档,我也不确定如何使用。

Any clues? 有什么线索吗?

Original Post: 原始帖子:

I'm having the following problem: I'm trying to access the camera of a device where there is no information provided on what type of camera or image format is used. 我遇到以下问题:我正在尝试访问没有提供有关使用哪种类型的相机或图像格式的信息的设备的相机。 The only information provided is on how to retrieve a byte array containing the video stream output. 提供的唯一信息是有关如何检索包含视频流输出的字节数组的信息。 I found out however that the resolution is 1280x720 and the byte array size is 1843200. By googling I stumbled across cameras with the exact same size and dimensions using YUYV and similar pixel formats. 但是我发现分辨率为1280x720,字节数组大小为1843200。通过使用谷歌搜索,我偶然发现了使用YUYV和类似像素格式的大小和尺寸完全相同的相机。 Based on that knowledge I wrote the code below: 基于这些知识,我编写了以下代码:

ByteArrayOutputStream out = new ByteArrayOutputStream();
            YuvImage yuv = new YuvImage(data, ImageFormat.YUY2, 1280, 720, null);
            yuv.compressToJpeg(new Rect(0, 0, 1280, 720), 100, out);
            byte[] bytes = out.toByteArray();
            bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
            if (bitmap != null) {
                ImageView cameraImageView = (ImageView) findViewById(R.id.imageView);
                cameraImageView.setImageBitmap(bitmap);
            } 

The BitmapFactory.decodeByteArray function returned a valid bitmap but when displaying it I saw the image having a green tint and purple spots, probably something related to the color channels? BitmapFactory.decodeByteArray函数返回一个有效的位图,但是在显示时,我看到图像具有绿色和紫色斑点,可能与颜色通道有关? Sample Image: 样本图片: 带有绿色/紫色斑点的图像

Is there a way how to find out the exact pixel format/ encoding that has been used? 有没有办法找出使用过的确切像素格式/编码? I'm not sure what other things to try from here on out. 我不确定从现在开始还有什么其他尝试。 Any advice is appreciated, thanks! 任何建议表示赞赏,谢谢!

try this : 尝试这个 :

    /** 
     * Save YUV image data (NV21 or YUV420sp) as JPEG to a FileOutputStream.
     */
    public static boolean saveYUYToJPEG(byte[] imageData,File saveTo,int format,int quality,int width,int height,int rotation,boolean flipHorizontally){
      FileOutputStream fileOutputStream=null;
      YuvImage yuvImg=null;
      try {
        fileOutputStream=new FileOutputStream(saveTo);
        yuvImg=new YuvImage(imageData,format,width,height,null);
        ByteArrayOutputStream jpegOutput=new ByteArrayOutputStream(imageData.length);
        yuvImg.compressToJpeg(new Rect(0,0,width - 1,height - 1),90,jpegOutput);
        Bitmap yuvBitmap=BitmapFactory.decodeByteArray(jpegOutput.toByteArray(),0,jpegOutput.size());
        Matrix imageMatrix=new Matrix();
        if (rotation != 0) {
          imageMatrix.postRotate(rotation);
        }
        if (flipHorizontally) {
        }
        yuvBitmap=Bitmap.createBitmap(yuvBitmap,0,0,yuvBitmap.getWidth(),yuvBitmap.getHeight(),imageMatrix,true);
        yuvBitmap.compress(CompressFormat.JPEG,quality,fileOutputStream);
      }
     catch (  FileNotFoundException e) {
        return false;
      }
      return true;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM