安卓Bitmap图像格式转为BGRA

最近在做opencv的一个项目,安卓人脸识别。

为了提高效率,完全抛弃javacv(opencv4android)的内容,完全使用jni开发,应用层做的工作只是把摄像头获取的图像数据传到jni中,其余人脸检测、识别完全在jni中用opencv的c、c++接口开发完成。

那么问题来了,安卓摄像头预览获取的yuv420sp数据如果直接传到jni中,用Mat矩阵来接收,格式是不支持的。使用opencv中的函数Mat image(height, width, CV_8UC4, (unsigned char*)pBuf);这个函数只能接收BGRA格式的图像数据。因此要对摄像头获取的数据进行转化。

public void onPreviewFrame(byte[] data, Camera camera) {
			
<span style="white-space:pre">	</span>if (data != null) {
	<span style="white-space:pre">	</span>int imageWidth = mCamera.getParameters().getPreviewSize().width;
		int imageHeight = mCamera.getParameters().getPreviewSize().height;
		int RGBData[] = new int[imageWidth * imageHeight];
<span style="white-space:pre">		</span>decodeYUV420SP(RGBData, data, imageWidth, imageHeight); <span style="white-space:pre">		</span>// 解码,yuv420sp转为RGB格式
<span style="white-space:pre">		</span>Bitmap bm = Bitmap.createBitmap(RGBData, imageWidth,imageHeight, Config.ARGB_8888);<span style="white-space:pre">	</span>//填到bitmap中
<span style="white-space:pre">		</span>byte[] bgra = getPixelsBGRA(bm);<span style="white-space:pre">				</span>//把bitmap中的ARGB_8888格式转为Mat矩阵中可用的BGRA格式数据bgra
    <span style="white-space:pre">	</span>}
}
public byte[] getPixelsBGRA(Bitmap image) {
	    // calculate how many bytes our image consists of
	    int bytes = image.getByteCount();

	    ByteBuffer buffer = ByteBuffer.allocate(bytes); // Create a new buffer
	    image.copyPixelsToBuffer(buffer); // Move the byte data to the buffer

	    byte[] temp = buffer.array(); // Get the underlying array containing the data.

	    byte[] pixels = new byte[temp.length]; // Allocate for BGRA

	    // Copy pixels into place
	    for (int i = 0; i < (temp.length / 4); i++) {
	     
	    	pixels[i * 4] = temp[i * 4 + 2];		//B
	    	pixels[i * 4 + 1] = temp[i * 4 + 1];<span style="white-space:pre">		</span>//G    
	    	pixels[i * 4 + 2] = temp[i * 4 ];		//R
		pixels[i * 4 + 3] = temp[i * 4 + 3]; 		//A
		       
	    }

	    return pixels;
	}


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


错误历程:
原本以为bitmap中的格式ARGB_8888,中的数据是按照字母顺序A、R、G、B来排列的,之前自己写了函数按这种顺序转换为B、G、R、A的顺序格式,传到Mat矩阵中,发现图像颜色总是显示不正确。几经调试,调试了好几天,才发现bitmap中所谓的ARGB_8888,实际的数据顺序为R、G、B、A。这尼玛不按套路出牌,还要靠自己摸索这么久。真心坑爹啊。

       以上的做法还是经历了yuv420sp->RGB->Bitmap->BGRA的格式变换,貌似饶了一大圈,因为yuv420sp转成的RGB数据传到Mat矩阵中,还是不能正常显示。。但是又没有找到一种方法可以把yuv420sp直接转为BGRA格式。。还待优化吧,若有人有办法直接转换,望不吝赐教。

猜你喜欢

转载自blog.csdn.net/u013547134/article/details/40894333