html中获取modelandview中的json数据_从Bitmap中获取YUV数据的两种方式
從Bitmap中我們能獲取到的是RGB顏色分量,當需要獲取YUV數據的時候,則需要先提取R,G,B分量的值,然后將RGB轉化為YUV(根據具體的YUV的排列格式做相應的Y,U,V分量的排列)
所以這篇文章的真正題目叫“從Bitmap中獲取RGB數據的兩種方式”,下面我們以從Bitmap中獲取NV21數據為例進行說明
從Bitmap中獲取RGB數據,Android?SDK提供了兩種方式供我們使用
第一種是getPixels接口:
public void getPixels(@ColorInt int[] pixels, int offset, int stride, int x, int y, int width, int height)Bitmap中的像素數據將copy到pixels數組中,數組中每一個pixel都是按ARGB四個分量8位排列壓縮而成的一個int值
第二種是copyPixelsToBuffer接口:
public void copyPixelsToBuffer(Buffer dst)Bitmap中的像素數據將copy到buffer中,buffer中每一個pixel都是按RGBA四個分量的順序進行排列的
兩種接口返回的顏色通道順序不同,在取值的時候需要特別注意
拿到R,G,B分量的值后,就可以轉化為Y,U,V分量了,轉化算法:
y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;v = ((112 * r - 94 * g -18 * b + 128) >> 8) + 128;使用getPixels接口從Bitmap中獲取NV21數據的完整代碼
public static byte[] fetchNV21(@NonNull Bitmap bitmap) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); int size = w * h; int[] pixels = new int[size]; bitmap.getPixels(pixels, 0, w, 0, 0, w, h);????????byte[]?nv21?=?new?byte[size?*?3?/?2];????????????????// Make w and h are all even.????????w &= ~1; h &= ~1; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) {????????????????int?yIndex?=?i?*?w?+?j;????????????????????????????????int?argb?=?pixels[yIndex];????????????????int?a?=?(argb?>>?24)?&?0xff;? // unused int r = (argb >> 16) & 0xff; int g = (argb >> 8) & 0xff; int b = argb & 0xff; int y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16; y = clamp(y, 16, 255); nv21[yIndex] = (byte)y; if (i % 2 == 0 && j % 2 == 0) { int u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128; int v = ((112 * r - 94 * g -18 * b + 128) >> 8) + 128; u = clamp(u, 0, 255); v = clamp(v, 0, 255); nv21[size + i / 2 * w + j] = (byte) v; nv21[size + i / 2 * w + j + 1] = (byte) u; } } } return nv21; }拿到nv21數據后,我們怎么驗證數據是正常的呢?
可以通過YuvImage接口轉成jpeg,然后再將jpeg轉化為Bitmap,使用ImageView顯示出來看下是否和原圖一致就可以驗證了
//?create?test?bitmap?and fetch nv21 dataBitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.header);int w = bitmap.getWidth();int?h?=?bitmap.getHeight();byte[] nv21 = Util.fetchNV21(bitmap);bitmap.recycle();// nv21 -> jpeg -> bitmapYuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, w, h, null);ByteArrayOutputStream outputStream = new ByteArrayOutputStream();yuvImage.compressToJpeg(new Rect(0, 0, w, h), 100, outputStream);byte[] array = outputStream.toByteArray();Bitmap tmp = BitmapFactory.decodeByteArray(array, 0, array.length);//?showimageView.setImageBitmap(tmp);在YuvImage的compressToJpeg接口的源碼中,有個調整壓縮rect的步驟
進入到adjustRectangle方法,可以發現壓縮區域的寬高被調整為偶數了
為什么w,h必須要保證為偶數呢?這個是因為當w,h都不為偶數的時候,在計算到最后的V,U的索引時候算出來會和NV21的數組長度一致,這樣就會導致ArrayIndexOutOfBoundsException了
使用copyPixelsToBuffer接口從Bitmap中獲取NV21數據的完整代碼
public static byte[] fetchNV21(@NonNull Bitmap bitmap) { ByteBuffer byteBuffer = ByteBuffer .allocateDirect(bitmap.getByteCount()) .order(ByteOrder.nativeOrder()); bitmap.copyPixelsToBuffer(byteBuffer); byte[] array = byteBuffer.array(); int w = bitmap.getWidth(); int h = bitmap.getHeight(); int area = w * h; int count = array.length / 4; if (count > area) { count = area; } int nv21Size = area * 3 / 2; byte[] nv21 = new byte[nv21Size]; for (int i = 0; i < count; i++) { int row = i / w; int col = i - col * w; int vIndex = area + (row >> 1) * w + (col & ~1); int uIndex = area + (row >> 1) * w + (col & ~1) + 1; // case: w or h not even if (vIndex >= nv21Size) { break; }????????????// RGBA int r = ((int)array[i * 4]) & 0xff; int g = ((int)array[i * 4 + 1]) & 0xff; int b = ((int)array[i * 4 + 2]) & 0xff; int a = ((int)array[i * 4 + 3]) & 0xff; // unused int y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16; int u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128; int v = ((112 * r - 94 * g -18 * b + 128) >> 8) + 128; y = clamp(y, 16, 255); u = clamp(u, 0, 255); v = clamp(v, 0, 255); nv21[i] = (byte)y; nv21[vIndex] = (byte)v; nv21[uIndex] = (byte)u; } return nv21; }通過buffer拷貝的數據,有時候是會多那么一兩個pixel。比如我測試的一張圖片,Bitmap寬高為1200,獲取到的byte數組長度為5760007,就多了7個字節,2個像素
fetchBitmapToNv21:?w?=?1200,?h?=?1200,?array.length?=?5760007,?w * h?=?1440000從Bitmap中拿到RGB數據,再轉化為YUV數據后,根據Y,U,V分量排列的不同可以任意組合為自己所需要的YUV格式~
推薦閱讀:
音視頻面試基礎題
OpenGL 之 GPUImage 源碼分析
OpenGL ES 實現實時音頻的可視化
Shader 優化 | OpenGL 繪制網格效果
覺得不錯,點個在看唄~
總結
以上是生活随笔為你收集整理的html中获取modelandview中的json数据_从Bitmap中获取YUV数据的两种方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++二进制文件java读取int_吃透
- 下一篇: c语言打印字符的函数参数,C语言格式化打