如何使用ScriptIntrinsicYuvToRGB(将byte [] yuv转换为byte [] rgba)

时间:2013-12-03 18:25:12

标签: android renderscript

我有byte[] yuvByteArray(从Camera.PreviewCallback.onPreviewFrame方法捕获540x360图像并转储到assets/yuv.bin文件中)。我想使用以下代码(基于LivePreview android示例)将byte[] yuv转换为byte[] rgba数组。

但是我收到outBytes rgba数组,在forEach之后填充零,并将out分配复制到outBytes。我的代码出了什么问题?

<小时/>

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

}

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

5 个答案:

答案 0 :(得分:11)

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

答案 1 :(得分:2)

使用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

答案 2 :(得分: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);

答案 3 :(得分:0)

将传递给ScriptIntrinsicYubToRGB的构造函数的输出类型更改为Element.U8_4而不是Element.RGBA_8888。对于用于创建输出Type.Builder的{​​{1}},您需要相同的内容。

答案 4 :(得分:0)

  

科特琳

        val rs = RenderScript.create(CONTEXT_HERE)
        val yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs))

        val yuvType = Type.Builder(rs, Element.U8(rs)).setX(byteArray.size)
        val inData = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT)

        val rgbaType = Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height)
        val outData = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT)

        inData.copyFrom(byteArray)

        yuvToRgbIntrinsic.setInput(inData)
        yuvToRgbIntrinsic.forEach(outData)

        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        outData.copyTo(bitmap)