java - 使用平面 4 :2:0 YUV full scale pixel format 将图像从字节数组转换为位图

标签 java android camera image-formats pixelformat

更新:我联系了设备供应商,他们告诉我它使用的是平面 4:2:0 YUV 全尺寸像素格式。经过研究,我发现 YUV 4:2:0 似乎有 3 种主要格式:I420、J420 和 YV12。 我很兴奋,因为在 android YuvImage 类中有这种图像格式的常量,但是在运行我的代码时我得到了以下异常:

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

那真是太可惜了..

之后了解了YUV420和NV21的区别: YUV420 YUV420_NV21

我尝试编写一些简单的函数来交错 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;
    }

但是,结果似乎仍然与我的原始代码相同。 我考虑的一个可能原因是字节数组的大小 (1843200)。我读到对于 YUV420,一个像素的深度是 12 位。相机分辨率为 1280x720,即 921,600 像素或 1,382,400 字节。这比实际字节数组大小小三分之一。我读到飞机之间可能有一些填充物,但我仍然不知道如何找到它。

YuvImage 类在其构造函数中有一个 strides 参数,但即使在阅读了 android 开发人员文档后我也不确定如何使用。

有什么线索吗?

原帖:

我遇到以下问题:我正在尝试访问设备的摄像头,但没有提供有关所用摄像头类型或图像格式的信息。提供的唯一信息是关于如何检索包含视频流输出的字节数组。 然而,我发现分辨率是 1280x720,字节数组大小是 1843200。通过谷歌搜索,我偶然发现了使用 YUYV 和类似像素格式的大小和尺寸完全相同的相机。 基于这些知识,我编写了以下代码:

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);
            } 

BitmapFactory.decodeByteArray 函数返回了一个有效的位图,但在显示它时我看到图像有绿色和紫色 Blob ,可能与颜色 channel 有关? 样本图片: Image with green tint/ purple spots

有没有办法找出已使用的确切像素格式/编码?我不确定从现在开始还有什么其他的尝试。 感谢任何建议,谢谢!

最佳答案

试试这个:

    /** 
     * 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;
    }

关于java - 使用平面 4 :2:0 YUV full scale pixel format 将图像从字节数组转换为位图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47586625/

相关文章:

java - 使用spark-cassandra-connector-java api并在尝试提交spark作业时出现错误

android - Android Framework 小部件与其 AppCompat 版本之间的区别

android - 如何使用 libgdx 在 Box2D 的碰撞事件中设置 false/NoCollision?

iphone - 如何让 iPhone 相机的快门声静音?

linux - 逐帧更改相机曝光

android - 如何将android的相机设置为ffmpeg的输入

java - 并非所有请求的模块都可以启用 - org-netbeans-modules-nbjavac.jar

java - 如何使用 Jackson 数据类型 : JSR310 Deser standalone?

java - 帮我实现一个可倒带的缓冲区

android - 单击CheckBox时如何获取ListView中的项目