我一直在寻找转换来自onPreviewFrame()的NV21字节[]。我搜索了论坛和谷歌的各种解决方案。我已经尝试过RenderScripts和其他一些代码示例。他们中的一些给我一个黄色调的图像,有些给我一个红色和蓝色翻转的图像(我在代码中翻回后,我得到黄色色调),有些在整个图像中给我奇怪的颜色特征(几乎像一个负片),有些给我一个灰度图像,有些给我一个如此黑暗的图像,你可以真正做出任何事情。
由于我是打字问题的人,我意识到我必须是房间里的白痴,所以我们将从this post开始。这个特殊的解决方案给了我一个非常黑暗的图像,但我还不够酷,无法发表评论。有没有人试过这个解决方案,或者有一个产生与原始NV21格式相同质量的图像?
我需要一个有效的ARGB字节[]或一个有效的Bitmap,我可以修改我的项目来处理它们。仅供参考,我已尝试过这些(以及其他几个实际上只是这些的副本):
答案 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吗?