当前位置: 代码迷 >> Android >> Android摄像视频流的格式转换(YUV - RGB)
  详细解决方案

Android摄像视频流的格式转换(YUV - RGB)

热度:74   发布时间:2016-05-01 15:35:58.0
Android拍摄视频流的格式转换(YUV --- RGB)
Android允许用户实时捕获摄像头的视频流,这在利用摄像头的AR应用中非常有用。可以利用摄像流实时做画面图像的分析,并做出许多有用的应用。比如人脸识别,条码识别,特定图像替换等等,不过大多数图像处理软件在处理时是需要RGB格式的图像,而默认的视频流是压缩的YUV格式,Android下是YUV420SP,这个格式,虽然可以在程序中修改,但是修改后好像不起作用,也就是说只能得到编码为YUV420SP的视频流,这就需要把YUV420SP的视频流转换成RGB格式的图像,用于图像识别。特贴一个格式转换函数,方便大家使用。
    static public void decodeYUV420SP(byte[] rgbBuf, byte[] yuv420sp, int width, int height) {    	final int frameSize = width * height;		if (rgbBuf == null)			throw new NullPointerException("buffer 'rgbBuf' is null");		if (rgbBuf.length < frameSize * 3)			throw new IllegalArgumentException("buffer 'rgbBuf' size "					+ rgbBuf.length + " < minimum " + frameSize * 3);		if (yuv420sp == null)			throw new NullPointerException("buffer 'yuv420sp' is null");		if (yuv420sp.length < frameSize * 3 / 2)			throw new IllegalArgumentException("buffer 'yuv420sp' size " + yuv420sp.length					+ " < minimum " + frameSize * 3 / 2);    	    	int i = 0, y = 0;    	int uvp = 0, u = 0, v = 0;    	int y1192 = 0, r = 0, g = 0, b = 0;    	    	for (int j = 0, yp = 0; j < height; j++) {    		uvp = frameSize + (j >> 1) * width;    		u = 0;    		v = 0;    		for (i = 0; i < width; i++, yp++) {    			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;    			}    			    			y1192 = 1192 * y;    			r = (y1192 + 1634 * v);    			g = (y1192 - 833 * v - 400 * u);    			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;    			    			rgbBuf[yp * 3] = (byte)(r >> 10);    			rgbBuf[yp * 3 + 1] = (byte)(g >> 10);    			rgbBuf[yp * 3 + 2] = (byte)(b >> 10);    		}    	}    }

1 楼 jasonchain 2010-08-20  
我怎么转出来是花的?
2 楼 jasonchain 2010-08-20  
jasonchain 写道
我怎么转出来是花的?

有点绿色,蓝色
3 楼 cwh643 2010-09-27  

有点绿色,蓝色

很遗憾,你的问题还没有解决,我想你可能还没有理解rgbBuf到bitmap的转换,中间可能有些颜色产生了互相影响,你看这个方法是否可以帮助你,吧你个方法的最后几行改成这样 rgbBuf[yp * 3] = (byte)(r >> 10);
rgbBuf[yp * 3 + 1] = (byte)(g >> 10);
rgbBuf[yp * 3 + 2] = (byte)(b >> 10);

out[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);

这里就是把原来的rgbbuffer,转成用于生成bitmap的buffer,格式是ARGB
jasonchain 写道
jasonchain 写道
我怎么转出来是花的?
4 楼 keithlee980 2010-09-27  
楼主,请问这个函数怎么使用呢?是不是在onPreviewFrame里调用?我调用了转换出的图片打不开,应该是我没调用好。麻烦楼主讲一下怎么调用这个函数吧。谢谢了。
5 楼 jasonchain 2010-09-28  
cwh643 写道

有点绿色,蓝色

很遗憾,你的问题还没有解决,我想你可能还没有理解rgbBuf到bitmap的转换,中间可能有些颜色产生了互相影响,你看这个方法是否可以帮助你,吧你个方法的最后几行改成这样 rgbBuf[yp * 3] = (byte)(r >> 10);
rgbBuf[yp * 3 + 1] = (byte)(g >> 10);
rgbBuf[yp * 3 + 2] = (byte)(b >> 10);

out[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);

这里就是把原来的rgbbuffer,转成用于生成bitmap的buffer,格式是ARGB
jasonchain 写道
jasonchain 写道
我怎么转出来是花的?



谢谢您的回复,已经试过了,效果一样
6 楼 cwh643 2010-10-08  
keithlee980 写道
楼主,请问这个函数怎么使用呢?是不是在onPreviewFrame里调用?我调用了转换出的图片打不开,应该是我没调用好。麻烦楼主讲一下怎么调用这个函数吧。谢谢了。

我是这样调用的,你可以参考一下
    	public synchronized void onPreviewFrame(byte[] data, Camera camera) {    		if (data == null) {    			return;    		}    		if (isStopPreview) {    			return;    		}    		if (mRenderer == null) {    			return;    		}    		//关闭摄像头预览回调    		camera.setPreviewCallback(null);    		    		if (bitmapData == null) {    			previewWidth = camera.getParameters().getPreviewSize().width;        		previewHeight = camera.getParameters().getPreviewSize().height;        		bitmapData = new int[previewWidth * previewHeight];        		rgbBuffer = new byte[previewWidth * previewHeight * 3];    		}    					decodeYUV420SP(bitmapData, rgbBuffer, data, previewWidth, previewHeight);						if (mARHelp != null) {				//调用artoolkit识别				mARHelp.findMarker(rgbBuffer, mRenderer);			}			//取得摄像头画面			Bitmap image = Bitmap.createBitmap(bitmapData, previewWidth, previewHeight, Bitmap.Config.ARGB_8888);			mRenderer.setBackgroundImage(image);						//刷新openGL显示			requestRender();						//打开摄像头预览回调			camera.setPreviewCallback(this);    	}
7 楼 cwh643 2010-10-08  
jasonchain 写道
cwh643 写道

有点绿色,蓝色

很遗憾,你的问题还没有解决,我想你可能还没有理解rgbBuf到bitmap的转换,中间可能有些颜色产生了互相影响,你看这个方法是否可以帮助你,吧你个方法的最后几行改成这样 rgbBuf[yp * 3] = (byte)(r >> 10);
rgbBuf[yp * 3 + 1] = (byte)(g >> 10);
rgbBuf[yp * 3 + 2] = (byte)(b >> 10);

out[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);

这里就是把原来的rgbbuffer,转成用于生成bitmap的buffer,格式是ARGB
jasonchain 写道
jasonchain 写道
我怎么转出来是花的?



谢谢您的回复,已经试过了,效果一样

你在真机上试了吗,应该可以的,如果效果不好,是不是由于图片的PreviewSize像素设的太低了呢?
8 楼 lipeng88213 2010-12-07  
jasonchain 写道
我怎么转出来是花的?

楼上的问题解决了吗 我的也是花的

请教楼主 花屏如何解决啊。。。。
9 楼 cwh643 2010-12-08  
lipeng88213 写道
jasonchain 写道
我怎么转出来是花的?

楼上的问题解决了吗 我的也是花的

请教楼主 花屏如何解决啊。。。。

我这里一直用的,在多款android手机上测试都是好的,包括最新的Nexus s,只是在模拟器上有一些阴影一样的颜色,不知道你们的程序是否有其他问题
10 楼 lipeng88213 2010-12-08  
cwh643 写道
lipeng88213 写道
jasonchain 写道
我怎么转出来是花的?

楼上的问题解决了吗 我的也是花的

请教楼主 花屏如何解决啊。。。。

我这里一直用的,在多款android手机上测试都是好的,包括最新的Nexus s,只是在模拟器上有一些阴影一样的颜色,不知道你们的程序是否有其他问题

我调了一下 感觉是
byte[] rgbBuf, byte[] yuv420sp, int width, int height
这几个参数的比例 应该有某种问题

不知道 楼主 是怎么设置的 以及 android端setPreviewSize的大小
11 楼 cwh643 2011-01-07  
lipeng88213 写道
cwh643 写道
lipeng88213 写道
jasonchain 写道
我怎么转出来是花的?

楼上的问题解决了吗 我的也是花的

请教楼主 花屏如何解决啊。。。。

我这里一直用的,在多款android手机上测试都是好的,包括最新的Nexus s,只是在模拟器上有一些阴影一样的颜色,不知道你们的程序是否有其他问题

我调了一下 感觉是
byte[] rgbBuf, byte[] yuv420sp, int width, int height
这几个参数的比例 应该有某种问题

不知道 楼主 是怎么设置的 以及 android端setPreviewSize的大小

我的程序中是这样设置这些参数的
previewWidth = camera.getParameters().getPreviewSize().width;previewHeight = camera.getParameters().getPreviewSize().height;rgbBuffer = new byte[previewWidth * previewHeight * 3];decodeYUV420SP(rgbBuffer, data, previewWidth, previewHeight);

就是说这里PreviewSize是取得当前camera的实际的PreviewSize,你设定的previewSize不一定是设备的可以支持的
12 楼 zhjb_javaeye 2011-05-20  
cwh643 写道
keithlee980 写道
楼主,请问这个函数怎么使用呢?是不是在onPreviewFrame里调用?我调用了转换出的图片打不开,应该是我没调用好。麻烦楼主讲一下怎么调用这个函数吧。谢谢了。

我是这样调用的,你可以参考一下
    	public synchronized void onPreviewFrame(byte[] data, Camera camera) {    		if (data == null) {    			return;    		}    		if (isStopPreview) {    			return;    		}    		if (mRenderer == null) {    			return;    		}    		//关闭摄像头预览回调    		camera.setPreviewCallback(null);    		    		if (bitmapData == null) {    			previewWidth = camera.getParameters().getPreviewSize().width;        		previewHeight = camera.getParameters().getPreviewSize().height;        		bitmapData = new int[previewWidth * previewHeight];        		rgbBuffer = new byte[previewWidth * previewHeight * 3];    		}    					decodeYUV420SP(bitmapData, rgbBuffer, data, previewWidth, previewHeight);						if (mARHelp != null) {				//调用artoolkit识别				mARHelp.findMarker(rgbBuffer, mRenderer);			}			//取得摄像头画面			Bitmap image = Bitmap.createBitmap(bitmapData, previewWidth, previewHeight, Bitmap.Config.ARGB_8888);			mRenderer.setBackgroundImage(image);						//刷新openGL显示			requestRender();						//打开摄像头预览回调			camera.setPreviewCallback(this);    	}


楼主,能你发的“decodeYUV420SP”少了个参数,能否帖个这断代码里用的“decodeYUV420SP”方法不???
13 楼 windloverain 2011-06-17  
very good.
学习下。
14 楼 Jefry 2012-02-03  
大侠,ARGB_8888占4个字节啊,怎么乘以3呢
15 楼 土块的魅力 2012-02-17  
我的在pc机端是花屏,如果解决的话请指点,qq:776704371,谢谢了!
16 楼 cwh643 2012-03-27  
Jefry 写道
大侠,ARGB_8888占4个字节啊,怎么乘以3呢

这个函数是转成RGB的,如果要ARGB,请按照下面提示自行修改
out[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
  相关解决方案