2016-09-28 43 views
2

我一直在尋找轉換從onPreviewFrame()獲得的NV21字節[]。我已經搜索論壇和谷歌的各種解決方案。我已經嘗試了RenderScripts和其他一些代碼示例。其中一些給我一個黃色的圖像,一些給我一個紅色和藍色翻轉的圖像(在我翻回代碼後,我得到黃色色調),一些給我在整個圖像中的奇特的顏色特徵(幾乎像一個消極),有些給我一個灰度圖像,有些給我一個如此黑暗的形象,你不能真正做出任何東西。NV21 Android上的位圖,非常暗的圖像,灰度或黃色色調?

因爲我是一個打字問題,我意識到我一定是房間裏的白癡,所以我們將從this post開始。這個特殊的解決方案給了我一個非常黑暗的圖像,但我不夠酷,無法評論。有沒有人試過這個解決方案,或者有一個產生與原始NV21格式相同質量的圖像?

我需要一個有效的ARGB byte []或一個有效的位圖,我可以修改我的項目來處理。僅供參考我嘗試了這些(和其他幾個人是這些真的只是複寫):

One solution I tried
Another solution I tried

回答

1

如果你正試圖從YUV相機轉換爲位圖,這裏是你可以嘗試:

// import android.renderscript.* 
// RenderScript mRS; 
// ScriptIntrinsicYuvToRGB mYuvToRGB; 
// Allocation yuvPreviewAlloc; 
// Allocation rgbOutputAlloc; 

// Create RenderScript context, ScriptIntrinsicYuvToRGB and Allocations and keep reusing them. 
if (NotInitialized) { 
    mRS = RenderScript.create(this). 
    mYuvToRGB = ScriptIntrinsicYuvToRGB.create(mRS, Element.YUV(mRS));  

    // Create a RS Allocation to hold NV21 data. 
    Type.Builder tYuv = new Type.Builder(mRS, Element.YUV(mRS)); 
    tYuv.setX(width).setY(height).setYuvFormat(android.graphics.ImageFormat.NV21); 
    yuvPreviewAlloc = Allocation.createTyped(mRS, tYuv.create(), Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_INPUT); 

    // Create a RS Allocation to hold RGBA data. 
    Type.Builder tRgb = new Type.Builder(mRS, Element.RGBA_8888(mRS)); 
    tRgb.setX(width).tRgb(height); 
    rgbOutputAlloc = Allocation.createTyped(mRS, tRgb.create(), Allocation.USAGE_SCRIPT); 

    // Set input of ScriptIntrinsicYuvToRGB 
    mYuvToRGB.setInput(yuvPreviewAlloc); 
} 

// Use rsPreviewSurface as one of the output surface from Camera API. 
// You can refer to https://github.com/googlesamples/android-HdrViewfinder/blob/master/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java#L504 
Surface rsPreviewSurface = yuvPreviewAlloc.getSurface(); 
... 

// Whenever a new frame is available 
// Update the yuv Allocation with a new Camera buffer without any copy. 
// You can refer to https://github.com/googlesamples/android-HdrViewfinder/blob/master/Application/src/main/java/com/example/android/hdrviewfinder/ViewfinderProcessor.java#L109 
yuvPreviewAlloc.ioReceive(); 
// The actual Yuv to Rgb conversion. 
mYuvToRGB.forEach(rgbOutputAlloc); 

// Copy the rgb Allocation to a Bitmap. 
rgbOutputAlloc.copyTo(mBitmap); 

// continue processing mBitmap. 
... 
+0

如果相機緩衝區不是「NV21」,您可能還想使用「YUV_420_888」和「YV12」。 –

+0

我正在嘗試這個,我得到和我以前沒見過的錯誤:「E/RenderScript:YuvToRGB執行沒有數據,跳過」每個預覽幀。我嘗試添加「yuvPreviewAlloc.copyFrom(data);」只是爲了確保它不是那樣的。任何人都會遇到這個? –

+0

此錯誤消息通常表示yuvPreviewAlloc分配沒有從相機API獲取任何數據。請仔細檢查1.如果rsPreviewSurface已正確配置爲攝像機輸出表面。 2.如果ioReceive被調用。 3.確保您使用的是「import android.renderscript。*」,因爲USAGE_IO_INPUT不支持RenderScript支持庫(導入android.support.v8.renderscript)。我還在代碼中添加了一些註釋,以向您指出該設置的一些代碼參考。 –

0

我能得到一個不同的方法的工作(先前連接的一種)通過使用代碼here。但是,這是給紅/藍色翻轉。所以,我只是重新排列U和V線,一切都好。儘管這不像RenderScript那麼快。讓RenderScript正確運作將是一件好事。這裏是代碼:

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) { 
       u = (0xff & yuv420sp[uvp++]) - 128; //Just changed the order 
       v = (0xff & yuv420sp[uvp++]) - 128; //It was originally v then u 
      } 

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

任何人有一個沒有顏色色調和/或翻轉問題的RenderScript?

1

當使用ScriptIntrinsics我強烈建議升級到至少豆形軟糖4.3或更高版本(API18)。事情比JB 4.2(API 17)更容易使用。

ScriptIntrinsicYuvToRGB並不像看起來那麼複雜。 特別是你不需要Type.Builder對象。 相機預覽格式必須是NV21!

in onCreate()...方法創建的renderScript對象和本徵:

mRS = RenderScript.create(this); 
mYuvToRGB = ScriptIntrinsicYuvToRGB.create(mRS, Element.U8_4(mRS));  

有了您cameraPreviewWidth和cameraPreviewHeight計算 長度相機數據字節數組的:

int yuvDatalength = cameraPreviewWidth*cameraPreviewHeight*3/2 ; // this is 12 bit per pixel 

你需要一個位圖輸出:

mBitmap = Bitmap.createBitmap(cameraPreviewWidth, cameraPreviewHeight, Bitmap.Config.ARGB_8888); 

然後您創建輸入和輸出分配(這裏是API18 +中的更改)

yuvPreviewAlloc = Allocation.createSized(mRS, Element.U8(mRS), yuvDatalength); 

rgbOutputAlloc = Allocation.createFromBitmap(mRS, mBitmap); // this simple ! 

和腳本輸入設定爲輸入分配

mYuvToRGB.setInput(yuvPreviewAlloc); // this has to be done only once ! 

在相機環路(每當一個新幀是avaliable)時,NV21字節陣列(數據[])複製到yuvPreviewAlloc執行腳本和複製導致爲位圖:

yuvPreviewAlloc.copyFrom(data); // or yuvPreviewAlloc.copyFromUnchecked(data); 

mYuvToRGB.forEach(rgbOutputAlloc); 

rgbOutputAlloc.copyTo(mBitmap); 

例如:在Nexus 7(2013,傑利貝恩4.3)的全HD(1920×1080)相機預覽轉化需要大約7毫秒。

+0

這個工作,它運作良好!最後,我還需要在渲染腳本中做一些額外的工作,以便將處理降到最低。所以,我不得不寫一個自定義的渲染腳本(這花了一段時間才弄清楚)。我在Renderscript書中找到了很多有用的信息(我在亞馬遜上了解到)。 –