2016-03-06 102 views
2

我试图从相机预览捕捉图像并对其进行一些绘制。问题是,我只有大约3-4fps的绘图,并且一半的帧处理时间是从相机预览接收和解码NV21图像并转换为位图。我有一个代码来完成这个任务,我在另一个堆栈问题上找到了。它似乎并不快,但我不知道如何优化它。 Samsung Note 3大约需要100-150 ms,图像尺寸为1920x1080。我怎样才能让它工作得更快?Yuv(NV21)图像转换为位图

代码:

public Bitmap curFrameImage(byte[] data, Camera camera) 
{ 
    Camera.Parameters parameters = camera.getParameters(); 
    int imageFormat = parameters.getPreviewFormat(); 

    if (imageFormat == ImageFormat.NV21) 
    { 
     YuvImage img = new YuvImage(data, ImageFormat.NV21, prevSizeW, prevSizeH, null); 
     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     img.compressToJpeg(new android.graphics.Rect(0, 0, img.getWidth(), img.getHeight()), 50, out); 
     byte[] imageBytes = out.toByteArray(); 
     return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); 
    } 
    else 
    { 
     Log.i(TAG, "Preview image not NV21"); 
     return null; 
    } 
} 

图像的最终格式必须是位图,这样的话我可以做它的处理。我试图将Camera.Parameters.setPreviewFormat设置为RGB_565,但无法将相机参数分配给相机,我也读过NV21是唯一可用的格式。我对此不确定,是否有可能在这些格式变化中找到解决方案。

预先感谢您。

+0

最快的方法是使用RenderScript内在,但问题是为什么你需要这么多的位图每秒?绘制这些位图或存储它们将成为流量的下一个瓶颈,速度为10 FPS或更少 –

+0

谢谢。我的任务是在相机预览的文本字段周围绘制矩形,所以当相机移动时,我想让文本字段周围的边界保持移动,并在新找到的文本字段周围查找和绘制矩形(因此,跟踪在此处不起作用) 。这是我第一次做这样的事情,比如实时画相机预览,所以也许你有任何建议或意见,也许我在这里做了一些非常错误的事情? –

+1

考虑通过OpenGL渲染矩形;您不能显示SurfaceTexture来渲染相机预览,因为您的矩形将以延迟显示(识别和追踪算法)。更好地使用着色器手动呈现YUV预览帧,完美地与您的矩形同步。也许您的识别和跟踪算法也可能被调整为依赖于YUV数据而不是RGB? –

回答

5

谢谢亚历克斯科恩,帮助我做这个转换更快。我实现了你的建议方法(RenderScript intrinsics)。该代码由RenderScript intrinsics制作,将YUV图像转换为位图约5倍。以前的代码需要100-150毫秒。在三星Note 3上,这需要15-30左右。 如果有人需要做同样的任务,这里是代码:

这些将用于:

private RenderScript rs; 
private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic; 
private Type.Builder yuvType, rgbaType; 
private Allocation in, out; 

在上创建函数初始化我..:

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

而整个onPreviewFrame看起来像这样(这里我接收并转换图像):

if (yuvType == null) 
{ 
    yuvType = new Type.Builder(rs, Element.U8(rs)).setX(dataLength); 
    in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); 

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

in.copyFrom(data); 

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

Bitmap bmpout = Bitmap.createBitmap(prevSizeW, prevSizeH, Bitmap.Config.ARGB_8888); 
out.copyTo(bmpout); 
+1

谢谢,基本方法(stackoverflow.com/questions/9192982/displaying-yuv-im年龄在Android#9330203)〜1秒处理1080p图像〜0.08秒与您的方法:) –

2

您可以获得更高的速度(使用JellyBean 4.3,API18或更高版本): 相机预览模式必须为NV21!

在 “onPreviewFrame()” 做只有

aIn.copyFrom(data); 

yuvToRgbIntrinsic.forEach(aOut); 

aOut.copyTo(bmpout); // and of course, show the bitmap or whatever 

不要在这里创建任何对象。

所有其他的东西(创建RS,yuvToRgbIntrinsic,分配,位图)做 在onCreate()方法开始前摄像头预览。

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

// you don´t need Type.Builder objects , with cameraPreviewWidth and cameraPreviewHeight do: 
int yuvDatalength = cameraPreviewWidth*cameraPreviewHeight*3/2; // this is 12 bit per pixel 
aIn = Allocation.createSized(rs, Element.U8(rs), yuvDatalength); 

// of course you will need the Bitmap 
bmpout = Bitmap.createBitmap(cameraPreviewWidth, cameraPreviewHeight, Bitmap.Config.ARGB_8888); 

// create output allocation from bitmap 
aOut = Allocation.createFromBitmap(rs,bmpout); // this simple ! 

// set the script´s in-allocation, this has to be done only once 
yuvToRgbIntrinsic.setInput(aIn); 

在Nexus 7(2013,杰利贝恩4.3)的全HD(1920×1080)相机预览转换时间约0.007秒(YES,7毫秒)。

1

与renderscript(68毫秒 - 不包括初始化时间)相比,OpenCV-JNI用于从Nv21数据为4160x3120大小的图像构建Mat看起来更快2倍(38毫秒)。如果我们需要调整构造的位图的大小,OpenCV-JNI似乎更好,因为我们只对Y数据使用全尺寸。CbCr数据将调整大小缩小您的数据在OpenCV垫建造时