Android camera2 api将yuv420转换为rgb绿色输出

Android camera2 api将yuv420转换为rgb绿色输出,android,image,android-camera,yuv,Android,Image,Android Camera,Yuv,我试图将图像从YUV_420_888转换为rgb,但输出图像时遇到一些问题。在ImageReader中,我以YUV_420_888格式获取图像(使用camera 2 api获取此图像预览) 在用于编写YuvImage类的android sdk中,该YuvImage仅使用NV21、YUY2 我们可以看到N21和yuv420之间的差别不大,我尝试将数据转换为N21 YUV420: 和N21: 在onImageAvailable中,我分别获取每个平面,并将它们放置在正确的位置(如图所示) 但我保存

我试图将图像从YUV_420_888转换为rgb,但输出图像时遇到一些问题。在ImageReader中,我以YUV_420_888格式获取图像(使用camera 2 api获取此图像预览)

在用于编写YuvImage类的android sdk中,该YuvImage仅使用NV21、YUY2

我们可以看到N21和yuv420之间的差别不大,我尝试将数据转换为N21

YUV420:

N21:

在onImageAvailable中,我分别获取每个平面,并将它们放置在正确的位置(如图所示)

但我保存的图像是绿色和粉色的:


我遗漏了什么???

bufferV.get(data2)增加了ByteBuffer的位置。这就是为什么(int i=0;i的循环
在转换尝试中存在两个主要问题:

  • 我们不能假设U面和V面是孤立的,它们可能包含交错数据(例如,
    U面={U1,V1,U2,V2,}
    )。事实上,它甚至可能已经是NV21样式的交错。这里的关键是查看平面的,并检查我们可以对
  • 事实上,你已经评论说,大多数U和V平面的数据都是零,这表明你正在经历一个错误。这意味着,即使你得到了正确的转换,如果你受到这个错误的影响,图像仍然是绿色的,这个错误只在安卓5.1.1和更高版本上得到了修复,因此值得检查一下你正在使用的版本他正在修改密码

  • 我已经在RenderScript中实现了YUV_420逻辑(如上图所示),请参见此处的完整代码:

    它为API 22生成了完美的BIMAP,但对于API 21,它显示了“绿色田园诗”。从这一点上,我可以确认您发现的结果。正如上面Silvaren所提到的,原因似乎是API 21中的Android错误。查看我的rs代码,很明显,如果U和V信息缺失(即零),则G(绿色)ARGB组件在转换过程中变大


    我在Galaxy S5(仍然是API 21)上看到了类似的绿色图片-这里甚至是颠倒的;-)。我怀疑API 21上的大多数设备目前还没有将Camera2用于设备摄像头应用程序。有一个名为“手动相机兼容性”的免费应用程序可以测试这一点。从这一点上,我看到S5/API21确实仍然没有使用Camera2…幸运的是没有…

    我得到了ImageFormat.YUV_420_888的图像,并成功地保存到jpeg文件,并且可以在windows上正确地查看它。
    我在这里分享:

    private final Image mImage;
    private final File mFile;
    private final int mImageFormat;
    
    
    ByteArrayOutputStream outputbytes = new ByteArrayOutputStream();
    
    ByteBuffer bufferY = mImage.getPlanes()[0].getBuffer();
    byte[] data0 = new byte[bufferY.remaining()];
    bufferY.get(data0);
    
    ByteBuffer bufferU = mImage.getPlanes()[1].getBuffer();
    byte[] data1 = new byte[bufferU.remaining()];
    bufferU.get(data1);
    
    ByteBuffer bufferV = mImage.getPlanes()[2].getBuffer();
    byte[] data2 = new byte[bufferV.remaining()];
    bufferV.get(data2);
    
    try
    {
        outputbytes.write(data0);
        outputbytes.write(data2);
        outputbytes.write(data1);
    
    
        final YuvImage yuvImage = new YuvImage(outputbytes.toByteArray(), ImageFormat.NV21, mImage.getWidth(),mImage.getHeight(), null);
        ByteArrayOutputStream outBitmap = new ByteArrayOutputStream();
    
        yuvImage.compressToJpeg(new Rect(0, 0,mImage.getWidth(), mImage.getHeight()), 95, outBitmap);
    
    
        FileOutputStream outputfile = null;
        outputfile = new FileOutputStream(mFile);
        outputfile.write(outBitmap.toByteArray());
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    finally
    {
        mImage.close();
    }
    

    我改变这个。。。但还是一样。我检查了一下,数组中的数据1、数据2和它们几乎为0。数组长度518400,从该长度517440是0值。可能只能使用前960?这可能是设备上camera2 API的错误实现。感谢与android bug的链接,我检查了我的版本,我也有5.0.1。因此,我将尝试更新我的android,并将看到什么变化:NV21的图表实际上是错误的,描绘了NV12编码。NV21是相同的,只是U和V是交换的,即VUV而不是UVUV。
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    
    ByteBuffer bufferY = image.getPlanes()[0].getBuffer();
    byte[] data0 = new byte[bufferY.remaining()];
    bufferY.get(data0);
    
    ByteBuffer bufferU = image.getPlanes()[1].getBuffer();
    byte[] data1 = new byte[bufferU.remaining()];
    bufferU.get(data1);
    
    ByteBuffer bufferV = image.getPlanes()[2].getBuffer();
    byte[] data2 = new byte[bufferV.remaining()];
    bufferV.get(data2);
    ...
    outputStream.write(data0);
    for (int i=0;i<bufferV.remaining();i++) {
        outputStream.write(data1[i]);
        outputStream.write(data2[i]);
    }
    
    final YuvImage yuvImage = new YuvImage(outputStream.toByteArray(), ImageFormat.NV21, 1920,1080, null);
    ByteArrayOutputStream outBitmap = new ByteArrayOutputStream();
    
    yuvImage.compressToJpeg(new Rect(0, 0,1920, 1080), 95, outBitmap);
    
    byte[] imageBytes = outBitmap.toByteArray();
    
    final Bitmap imageBitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
    mImageView.setImageBitmap(imageBitmap);
    ...
    imageBitmap.compress(Bitmap.CompressFormat.JPEG, 95, out);
    
    for (int i=0; i<data1.length; i++) {
        outputStream.write(data1[i]);
        outputStream.write(data2[i]);
    }
    
    private final Image mImage;
    private final File mFile;
    private final int mImageFormat;
    
    
    ByteArrayOutputStream outputbytes = new ByteArrayOutputStream();
    
    ByteBuffer bufferY = mImage.getPlanes()[0].getBuffer();
    byte[] data0 = new byte[bufferY.remaining()];
    bufferY.get(data0);
    
    ByteBuffer bufferU = mImage.getPlanes()[1].getBuffer();
    byte[] data1 = new byte[bufferU.remaining()];
    bufferU.get(data1);
    
    ByteBuffer bufferV = mImage.getPlanes()[2].getBuffer();
    byte[] data2 = new byte[bufferV.remaining()];
    bufferV.get(data2);
    
    try
    {
        outputbytes.write(data0);
        outputbytes.write(data2);
        outputbytes.write(data1);
    
    
        final YuvImage yuvImage = new YuvImage(outputbytes.toByteArray(), ImageFormat.NV21, mImage.getWidth(),mImage.getHeight(), null);
        ByteArrayOutputStream outBitmap = new ByteArrayOutputStream();
    
        yuvImage.compressToJpeg(new Rect(0, 0,mImage.getWidth(), mImage.getHeight()), 95, outBitmap);
    
    
        FileOutputStream outputfile = null;
        outputfile = new FileOutputStream(mFile);
        outputfile.write(outBitmap.toByteArray());
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    finally
    {
        mImage.close();
    }