1. 程式人生 > >安卓Bitmap影象格式轉為BGRA

安卓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格式。。還待優化吧,若有人有辦法直接轉換,望不吝賜教。