安卓Bitmap图像格式转为BGRA

来源:互联网 发布:java中list升序排列 编辑:程序博客网 时间:2024/05/13 15:00

最近在做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 ];//Rpixels[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格式。。还待优化吧,若有人有办法直接转换,望不吝赐教。

1 0