2013-12-03 70 views
8

我有byte[] yuvByteArray(540x360圖像捕獲從Camera.PreviewCallback.onPreviewFrame方法和轉儲到assets/yuv.bin文件)。我想使用以下代碼(基於LivePreview android示例)將byte[] yuv轉換爲byte[] rgba數組。如何使用ScriptIntrinsicYuvToRGB(轉換byte [] yuv到byte [] rgba)

但我收到outBytes rgba數組填充零後forEach和複製out分配給outBytes。我的代碼有什麼問題?傳遞的ScriptIntrinsicYubToRGB構造


package hellorender;   
import android.app.Activity; 
import android.content.res.AssetManager; 
import android.graphics.Bitmap; 
import android.os.Bundle; 
import android.support.v8.renderscript.Allocation; 
import android.support.v8.renderscript.Element; 
import android.support.v8.renderscript.RenderScript; 
import android.support.v8.renderscript.ScriptIntrinsicYuvToRGB; 
import android.support.v8.renderscript.Type; 
import android.widget.ImageView; 
import hellorender.R; 

import java.io.IOException; 
import java.io.InputStream; 

public class HelloRenderActivity extends Activity { 

    public static final int W = 540; 
    public static final int H = 360; 
    private RenderScript rs; 
    private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     AssetManager assets = getAssets(); 
     byte[] yuvByteArray = new byte[291600]; 
     byte[] outBytes = new byte[W * H * 4]; 

     InputStream is = null; 
     try { 
      is = assets.open("yuv.bin"); 
      System.out.println("read: " + is.read(yuvByteArray)); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       is.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 

     ImageView iv = (ImageView) findViewById(R.id.image); 
     rs = RenderScript.create(this); 
     yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.RGBA_8888(rs)); 


     Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)) 
       .setX(W).setY(H) 
       .setYuvFormat(android.graphics.ImageFormat.NV21); 
     Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); 


     Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)) 
       .setX(W).setY(H); 
     Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); 

     in.copyFrom(yuvByteArray); 

     yuvToRgbIntrinsic.setInput(in); 
     yuvToRgbIntrinsic.forEach(out); 

     out.copyTo(outBytes); 

     Bitmap bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888); 
     out.copyTo(bmpout); 

     iv.setImageBitmap(bmpout); 
    } 

} 

回答

10

yuv.bin文件絕對是NV21格式,因爲它抓住了在這裏http://developer.android.com/reference/android/hardware/Camera.PreviewCallback.html#onPreviewFrame

setYuvFormat方法是從API級別18,我刪除它

所以這個代碼工作正常:

rs = RenderScript.create(this); 
    yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); 

    Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(yuvByteArray.length); 
    Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); 

    Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(W).setY(H); 
    Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); 

    in.copyFrom(yuvByteArray); 

    yuvToRgbIntrinsic.setInput(in); 
    yuvToRgbIntrinsic.forEach(out); 
+0

很高興你能夠得到它的工作。不幸的是,內部函數和大多數RenderScript沒有很好的記錄,所以很容易出現這樣的奇怪事情。 –

+0

我們如何獲得轉換的RGB字節數組? –

+0

與使用純java完成rutine相比,這是非常瘋狂的! – slott

0

更改您的輸出類型爲Element.U8_4,而不是Element.RGBA_8888。您需要使用Type.Builder來創建輸出Allocation

+0

outBytes用零填充再次。 – wilddev

+0

並且有由導致崩潰 :android.support.v8.renderscript.RSIllegalArgumentException:分配一種是USER,類型UNSIGNED_8的4個字節,通過位圖是ARGB_8888 'out.copyTo(bmpout)之後;' – wilddev

+0

變化'.setYuvFormat'使用'android.graphics.ImageFormat.YV21'而不是'android.graphics.ImageFormat.NV21',除非你的原始二進制文件是多計劃的YUV。在這種情況下,請使用'android.graphics.ImageFormat.YUV_420_888'。 –

1

我們的內部測試應用程序使用以下順序創建YUV分配。

tb = new Type.Builder(mRS, Element.createPixel(mRS, 
       Element.DataType.UNSIGNED_8, Element.DataKind.PIXEL_YUV)); 
    tb.setX(mWidth); 
    tb.setY(mHeight); 
    tb.setYuvFormat(android.graphics.ImageFormat.NV21); 
    mAllocationIn = Allocation.createTyped(mRS, tb.create(), Allocation.USAGE_SCRIPT); 

然後新的YUV數據可回調做內

mAllocationIn.copyFrom(theYuvByteArray); 
1

使用API​​18 + wilddev的回答能爲你鴕鳥政策需要Type.Builder對象上略有改善。 做所有這些東西在onCreate()方法:

aIn = Allocation.createSized(rs, Element.U8(rs), H*W*3/2); // what the f**k ? This is 12 bit per pixel, giving the length of the camera data byte array ! 

bmpout = Bitmap.createBitmap(W, H, Bitmap.Config.ARGB_8888); // you will need this bitmap for output anyway 

aOut = Allocation.createFromBitmap(rs, bmpout); // tada ! 

// and set the script´s input 
yuvToRgbIntrinsic.setInput(aIn); 

// as pixel data are stored as int (one byte for red, green, blue, alpha), you first need an int[] array 
int rgba[] = new int[w*h]; // the rgba[] array 

現在,您可以繼續使用這些把它們放進onPreviewFrame()方法:

aIn.copyFrom(data); // or aIn.copyFromUnchecked(data); // which is faster and safe for camera data 

yuvToRgbIntrinsic.forEach(aOut); // execute the script 

aOut.copyTo(bmpout); // copy result from aOut to bmpout 

// if you need the rgba-values, do 
bmpout.getPixels(rgba, 0, W, 0, 0, W, H); 

// now you may loop through the rgba[] array and extraxt the r,g,b,a values 
// and put them into a byte[] array(s), BUT this will surely have impact on the performance when doing in Java