Android:预览帧,从YCbCr_420_SP(NV21)格式转换为RGB渲染正确的图片,但是绿色

时间:2015-03-01 20:34:29

标签: android camera rgb yuv

我发布了这个问题,因为我在以下帖子中找不到解决问题的答案:

Converting preview frame to bitmap

Android decodeYUV420SP results in green images?

Displaying YUV Image in Android

我从

获取了我的数据和cameraResolution(在选择BestPreviewSize之后)
  public void onPreviewFrame(byte[] data, Camera camera) {
    Point cameraResolution = configManager.getCameraResolution();
    Handler thePreviewHandler = previewHandler;
    if (cameraResolution != null && thePreviewHandler != null) {
      Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
          cameraResolution.y, data);
      message.sendToTarget();
      previewHandler = null;
    } else {
      Log.d(TAG, "Got preview callback, but no handler or resolution available");
    }
  }

稍后从转换为RGB,我使用:

  int[] pixels=new int[yuvData.length];
  // int size = dataWidth*dataHeight;
 //  int[] pixels=new int[size]; replacing yuvData.length by size is not working too
  pixels=decodeYUV420SP(pixels,yuvData, dataWidth, dataHeight);
    Bitmap bitmap = Bitmap.createBitmap(dataWidth, dataHeight, Bitmap.Config.RGB_565);
    bitmap.setPixels(pixels, 0, dataWidth, 0, 0, dataWidth, dataHeight);

我尝试了两种方法,一种使用RenderScript,另一种使用decodeYUV420SP:

public Bitmap convertYUV420_NV21toRGB8888_RenderScript(byte [] data,int W, int H, CaptureActivityOCR fragment) { 
    // https://stackoverflow.com/questions/20358803/how-to-use-scriptintrinsicyuvtorgb-converting-byte-yuv-to-byte-rgba 
  RenderScript rs;
  ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
  rs = RenderScript.create(fragment.getActivity());
  yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); //Create an intrinsic for converting YUV to RGB. 

  Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(data.length);
  Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); //an Allocation will be populated with empty data when it is first created

  Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(W).setY(H);
  Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); //an Allocation will be populated with empty data when it is first created

  in.copyFrom(data);//Populate Allocations with data.

  yuvToRgbIntrinsic.setInput(in); //Set the input yuv allocation, must be U8(RenderScript). 
  yuvToRgbIntrinsic.forEach(out); //Launch the appropriate kernels,Convert the image to RGB. 


  Bitmap bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888);
  out.copyTo(bmpout); //Copy data out of Allocation objects.
  return bmpout;

}

int[] decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) { 
  Log.e("camera", "   decodeYUV420SP  ");

  // TODO Auto-generated method stub
  final int frameSize = width * height;

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

但我仍然不知道为什么我会得到一些好的形象但是绿色。 (我有另外类似的黑白方法,它正在工作) 除了上面的链接,我尝试了所有与此主题相关的帖子,所以如果有人可以帮助另一个提示,请?我可能会对要申请的尺寸感到困惑吗?

在OnPreviewFrame方法之后和转换为RGB方法之前的某个地方,我使用另一个方法和下面的指令,因为我需要旋转接收到的数据。我想知道这不是问题的根源:

  byte[] rotatedData = new byte[data.length];
  for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++)
          rotatedData[x * height + height - y - 1] = data[x + y * width];
  }
  int tmp = width;
  width = height;
  height = tmp;

请帮帮我?

2 个答案:

答案 0 :(得分:2)

我认为你的轮换例程是错误的。 它适用于Luma(Y),因此您可以获得黑白图像的良好效果,但不能获得色度。如果宽度和高度是图片的尺寸,则根本不会旋转色度值。 因此,您需要为色度添加第二个循环并移动字节对(V和U)。

如果您在没有此旋转的情况下尝试了它并且仍然有绿色图片,则问题可能也在您的decodeYUV420SP功能中。

yuv to rgba转换没有一个通用公式。它必须与对方相匹配 在这里http://www.codeproject.com/Articles/402391/RGB-to-YUV-conversion-with-different-chroma-samplihttp://www.fourcc.org/fccyvrgb.php

这个适用于我

B = 1.164(Y - 16)                   + 2.018(U - 128)
G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
R = 1.164(Y - 16) + 1.596(V - 128)

它似乎与您只使用浮动版本相同,所以您可以尝试其他。

答案 1 :(得分:0)

我建议在RenderScript旋转后旋转位图:

If  ( -Not ( Test-Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\NASBackup\command")){New-Item -Path "Registry::HKEY_CLASSES_ROOT\Directory\shell\NASBackup\command" -ItemType RegistryKey -Force}
Set-ItemProperty -path "Registry::HKEY_CLASSES_ROOT\Directory\shell\NASBackup\command" -Name "(Default)" -Type "String" -Value "cmd /c start /b /wait powershell.exe -nologo -WindowStyle Hidden -file C:\Windows\System32\Backup.ps1"
#