Android上的NV21到位图,非常暗的图像,灰度或黄色调?

时间:2016-09-28 17:12:28

标签: android image bitmap argb

我一直在寻找转换来自onPreviewFrame()的NV21字节[]。我搜索了论坛和谷歌的各种解决方案。我已经尝试过RenderScripts和其他一些代码示例。他们中的一些给我一个黄色调的图像,有些给我一个红色和蓝色翻转的图像(我在代码中翻回后,我得到黄色色调),有些在整个图像中给我奇怪的颜色特征(几乎像一个负片),有些给我一个灰度图像,有些给我一个如此黑暗的图像,你可以真正做出任何事情。

由于我是打字问题的人,我意识到我必须是房间里的白痴,所以我们将从this post开始。这个特殊的解决方案给了我一个非常黑暗的图像,但我还不够酷,无法发表评论。有没有人试过这个解决方案,或者有一个产生与原始NV21格式相同质量的图像?

我需要一个有效的ARGB字节[]或一个有效的Bitmap,我可以修改我的项目来处理它们。仅供参考,我已尝试过这些(以及其他几个实际上只是这些的副本):

One solution I tried
Another solution I tried

3 个答案:

答案 0 :(得分:1)

如果您尝试将YUV从相机转换为位图,可以尝试以下方法:

// import android.renderscript.*
// RenderScript mRS;
// ScriptIntrinsicYuvToRGB mYuvToRGB;
// Allocation yuvPreviewAlloc;
// Allocation rgbOutputAlloc;

// Create RenderScript context, ScriptIntrinsicYuvToRGB and Allocations and keep reusing them.
if (NotInitialized) {
    mRS = RenderScript.create(this).
    mYuvToRGB = ScriptIntrinsicYuvToRGB.create(mRS, Element.YUV(mRS));    

    // Create a RS Allocation to hold NV21 data.
    Type.Builder tYuv = new Type.Builder(mRS, Element.YUV(mRS));
    tYuv.setX(width).setY(height).setYuvFormat(android.graphics.ImageFormat.NV21);
    yuvPreviewAlloc = Allocation.createTyped(mRS, tYuv.create(), Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_INPUT);

    // Create a RS Allocation to hold RGBA data.
    Type.Builder tRgb = new Type.Builder(mRS, Element.RGBA_8888(mRS));
    tRgb.setX(width).tRgb(height);
    rgbOutputAlloc = Allocation.createTyped(mRS, tRgb.create(), Allocation.USAGE_SCRIPT);

    // Set input of ScriptIntrinsicYuvToRGB
    mYuvToRGB.setInput(yuvPreviewAlloc);
}

// Use rsPreviewSurface as one of the output surface from Camera API.
// You can refer to https://github.com/googlesamples/android-HdrViewfinder/blob/master/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java#L504
Surface rsPreviewSurface = yuvPreviewAlloc.getSurface();
...

// Whenever a new frame is available
// Update the yuv Allocation with a new Camera buffer without any copy.
// You can refer to https://github.com/googlesamples/android-HdrViewfinder/blob/master/Application/src/main/java/com/example/android/hdrviewfinder/ViewfinderProcessor.java#L109
yuvPreviewAlloc.ioReceive();
// The actual Yuv to Rgb conversion.
mYuvToRGB.forEach(rgbOutputAlloc);

// Copy the rgb Allocation to a Bitmap.
rgbOutputAlloc.copyTo(mBitmap);

// continue processing mBitmap.
...

答案 1 :(得分:1)

使用ScriptIntrinsics时,我强烈建议至少更新到JellyBean 4.3或更高版本(API18)。事情比JB 4.2(API 17)更容易使用。

ScriptIntrinsicYuvToRGB并不像看起来那么复杂。 特别是你不需要Type.Builder对象。 相机预览格式必须为NV21!

在onCreate()...方法中创建RenderScript对象和Intrinsic:

mRS = RenderScript.create(this);
mYuvToRGB = ScriptIntrinsicYuvToRGB.create(mRS, Element.U8_4(mRS));    

用你的cameraPreviewWidth和cameraPreviewHeight计算出来 摄像机数据字节数组的长度:

int yuvDatalength = cameraPreviewWidth*cameraPreviewHeight*3/2 ;  // this is 12 bit per pixel

您需要输出位图:

mBitmap = Bitmap.createBitmap(cameraPreviewWidth, cameraPreviewHeight, Bitmap.Config.ARGB_8888);

然后创建输入和输出分配(这里是API18 +中的更改)

yuvPreviewAlloc = Allocation.createSized(mRS, Element.U8(mRS),  yuvDatalength);

rgbOutputAlloc =  Allocation.createFromBitmap(mRS, mBitmap);  // this simple !

并将脚本输入设置为输入分配

mYuvToRGB.setInput(yuvPreviewAlloc);  // this has to be done only once !

在相机循环中(每当有新帧可用时),将NV21字节数组(data [])复制到yuvPreviewAlloc,执行脚本并将结果复制到位图:

yuvPreviewAlloc.copyFrom(data);  // or yuvPreviewAlloc.copyFromUnchecked(data);

mYuvToRGB.forEach(rgbOutputAlloc);

rgbOutputAlloc.copyTo(mBitmap);

例如:在Nexus 7(2013,JellyBean 4.3)上,全高清(1920x1080)相机预览转换大约需要7毫秒。

答案 2 :(得分:0)

通过使用代码here,我能够使用不同的方法(之前已链接过的方法)。但那是红色/蓝色翻转。所以,我只是重新安排了U和V线,一切都很好。但这并不像RenderScript那么快。让RenderScript正常运行会很好。这是代码:

static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
    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) {
                u = (0xff & yuv420sp[uvp++]) - 128; //Just changed the order
                v = (0xff & yuv420sp[uvp++]) - 128; //It was originally v then u
            }

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

任何人都有一个没有色彩和/或翻转问题的RenderScript吗?