从安卓相机的NV21格式中提取黑白图像

我做了一些谷歌周围,找不到这个格式的足够的信息。 这是相机预览的默认格式。 任何人都可以提出有关它的好的信息来源,以及如何从这个格式的照片/预览图像提取数据? 更具体地说,我需要提取黑白图像。

编辑:看起来像这种格式也被称为YCbCr 420半平面

我开发了以下代码将NV21转换为RGB,并且正在工作。

 /** * Converts YUV420 NV21 to RGB8888 * * @param data byte array on YUV420 NV21 format. * @param width pixels width * @param height pixels height * @return a RGB8888 pixels int array. Where each int is a pixels ARGB. */ public static int[] convertYUV420_NV21toRGB8888(byte [] data, int width, int height) { int size = width*height; int offset = size; int[] pixels = new int[size]; int u, v, y1, y2, y3, y4; // i percorre os Y and the final pixels // k percorre os pixles U e V for(int i=0, k=0; i < size; i+=2, k+=2) { y1 = data[i ]&0xff; y2 = data[i+1]&0xff; y3 = data[width+i ]&0xff; y4 = data[width+i+1]&0xff; u = data[offset+k ]&0xff; v = data[offset+k+1]&0xff; u = u-128; v = v-128; pixels[i ] = convertYUVtoRGB(y1, u, v); pixels[i+1] = convertYUVtoRGB(y2, u, v); pixels[width+i ] = convertYUVtoRGB(y3, u, v); pixels[width+i+1] = convertYUVtoRGB(y4, u, v); if (i!=0 && (i+2)%width==0) i+=width; } return pixels; } private static int convertYUVtoRGB(int y, int u, int v) { int r,g,b; r = y + (int)(1.402f*v); g = y - (int)(0.344f*u +0.714f*v); b = y + (int)(1.772f*u); r = r>255? 255 : r<0 ? 0 : r; g = g>255? 255 : g<0 ? 0 : g; b = b>255? 255 : b<0 ? 0 : b; return 0xff000000 | (b<<16) | (g<<8) | r; } 

这个图像有助于理解。 YUV420 NV21

如果你想只是灰度图像是easer。 你可以丢弃所有的U和V信息,只取Y信息。 代码可以是这样的:

 /** * Converts YUV420 NV21 to Y888 (RGB8888). The grayscale image still holds 3 bytes on the pixel. * * @param pixels output array with the converted array o grayscale pixels * @param data byte array on YUV420 NV21 format. * @param width pixels width * @param height pixels height */ public static void applyGrayScale(int [] pixels, byte [] data, int width, int height) { int p; int size = width*height; for(int i = 0; i < size; i++) { p = data[i] & 0xFF; pixels[i] = 0xff000000 | p<<16 | p<<8 | p; } } 

只需创build您的位图:

 Bitmap bm = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); 

像素是你的int []数组。

NV21基本上是YUV420,而不是平面格式,其中Y,U和V有独立的平面,NV21有1个平面的Luma和Chroma的第二个平面。 格式看起来像

网友评论yyyyyyyyyyyyyyyyyyyyyyyyyyyyy 。 。 。

VUVUVUVUVUVUVUVUVUVUVUVUVUVUVUVU VUVUVUVUVUVUVUVUVUVUVUVUVUVUVUVUVU。 。 。 。 。

由于这种预览格式,我也有很多头痛的问题。

我能find的最好的是这些:

http://www.fourcc.org/yuv.php#NV21

http://v4l2spec.bytesex.org/spec/r5470.htm

看起来,Y组件是您获得的数组中的第一个宽度*高度字节。

更多信息链接:

http://msdn.microsoft.com/en-us/library/ms867704.aspx#yuvformats_yuvsampling

http://msdn.microsoft.com/en-us/library/ff538197(v=vs.85).aspx

希望这可以帮助。

数据是YUV420格式。
如果您只对单色通道感兴趣,即“黑白”,则表示您已经拥有数据缓冲区的第一个width x height字节。
Y通道是第一个图像平面。 这正是灰色/强度/亮度等渠道。

这里是提取灰度图像数据的代码:

 private int[] decodeGreyscale(byte[] nv21, int width, int height) { int pixelCount = width * height; int[] out = new int[pixelCount]; for (int i = 0; i < pixelCount; ++i) { int luminance = nv21[i] & 0xFF; out[i] = Color.argb(0xFF, luminance, luminance, luminance); } return out; } 

当你只需要一个灰度相机预览,你可以使用一个非常简单的渲染脚本:

 # pragma version(1) # pragma rs java_package_name(com.example.name) # pragma rs_fp_relaxed rs_allocation gIn; // Allocation filled with camera preview data (byte[]) int previewwidth; // camera preview width (int) // the parallel executed kernel void root(uchar4 *v_out, uint32_t x,uint32_t y){ uchar c = rsGetElementAt_uchar(gIn,x+y*previewwidth); *v_out = (uchar4){c,c,c,255}; } 

注意:这并不比ScriptIntrinsicYuvToRGB(以及ScriptIntrinsicColorMatrix执行RGBA->灰色)快,但是它使用API​​ 11+(其中Intrinsics需要Api 17+)运行。