【问题标题】:Android : Preview frame, converted from YCbCr_420_SP (NV21) format to RGB render correct picture but in greenAndroid:预览帧,从 YCbCr_420_SP (NV21) 格式转换为 RGB 渲染正确的图片,但为绿色
【发布时间】:2015-03-01 20:34:29
【问题描述】:

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

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

我尝试了 2 种方法,一种使用 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;
} 

但我仍然不知道为什么我得到了一些不错的图像,但是是绿色的。 (我有另一种类似的黑白方法) 除了上面的链接之外,我还在 SO 上尝试了与该主题相关的所有帖子,所以如果有人可以提供另一个提示吗?我可能对要申请的尺寸感到困惑?

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

请帮帮我?

【问题讨论】:

    标签: android camera rgb yuv


    【解决方案1】:

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

    如果您在不进行此旋转的情况下尝试了它,但仍然有绿色图片,则问题也可能出在您的 decodeYUV420SP 函数中。

    yuv 到 rgba 的转换没有一个通用的公式。它必须与相反的匹配。
    看这里http://www.codeproject.com/Articles/402391/RGB-to-YUV-conversion-with-different-chroma-sampli 和这里http://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)
    

    这似乎与您仅使用浮动版本相同,因此您可以尝试其他版本。

    【讨论】:

    • 这个YUV转RGB公式使用浮点数,比上面dertin显示的要慢。
    【解决方案2】:

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

    if (bmpout == null) {
         bmpout = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    }
    rgbaAllocation.copyTo(bmpout);
    
    if (matrixPostRotate90 == null) {
        matrixPostRotate90 = new Matrix();
        matrixPostRotate90.postRotate(90);
    }
    
    Bitmap rotatedBitmap = Bitmap.createBitmap(bmpout, 0, 0, w, h, matrixPostRotate90, true);
    

    【讨论】:

      猜你喜欢
      • 2019-03-03
      • 2016-12-28
      • 1970-01-01
      • 2012-09-10
      • 2014-08-26
      • 1970-01-01
      • 2016-01-02
      • 1970-01-01
      • 2014-10-31
      相关资源
      最近更新 更多