首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Yuv (NV21)图像转换为位图

Yuv (NV21)图像转换为位图
EN

Stack Overflow用户
提问于 2016-03-06 12:14:57
回答 3查看 9K关注 0票数 4

我试图从相机预览的图像,并做一些绘图。问题是,我只有3-4 fps的绘图,一半的帧处理时间是接收和解码NV21图像从相机预览和转换为位图。我有一个代码来完成这个任务,这是我在另一个堆栈问题上发现的。它似乎不快,但我不知道如何优化它。三星Note 3的图像大小为1920x1080,大约需要100到150毫秒。我怎样才能让它工作得更快?

代码:

代码语言:javascript
复制
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是唯一可用的格式。我不确定,是否有可能在这些格式的变化中找到解决方案。

提前谢谢你。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-03-07 19:29:53

谢谢你,亚历克斯·科恩,你帮我加快了转换速度。我实现了您建议的方法(RenderScript本质)。此代码由RenderScript本质组成,将YUV图像转换为位图大约快5倍。以前的代码花费了100到150 ms。在三星Note 3上,这需要15-30英镑左右。如果有人需要执行同样的任务,下面是代码:

这些措施将用于:

代码语言:javascript
复制
private RenderScript rs;
private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
private Type.Builder yuvType, rgbaType;
private Allocation in, out;

在创建函数中,我初始化了..:

代码语言:javascript
复制
rs = RenderScript.create(this);
yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));

整个onPreviewFrame看起来如下(在这里,我接收并转换图像):

代码语言:javascript
复制
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);
票数 7
EN

Stack Overflow用户

发布于 2017-04-21 20:50:32

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

在"onPreviewFrame()“上,只做

代码语言:javascript
复制
aIn.copyFrom(data);

yuvToRgbIntrinsic.forEach(aOut);

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

这里不要创建任何对象。

所有其他东西(创建rs、yuvToRgbIntrinsic、分配、位图)都在onCreate()方法中完成,然后才开始相机预览。

代码语言:javascript
复制
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年,JellyBean 4.3)上,一个全高清(1920x1080)摄像头预览转换大约需要0.007秒(是的,7ms)。

票数 6
EN

Stack Overflow用户

发布于 2017-05-02 02:23:49

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

更好的方法是将NV21字节数组和int像素数组传递给Jni。在Jni侧可能不需要数组副本。然后,使用开源libyuv库(https://chromium.googlesource.com/libyuv/libyuv/)将NV21转换为ARGB。在Java中,我们使用传递的像素数组来构造位图。在Jni中,在NV21平台上,4160x3120字节数组从NV21到ARGB的转换只需4ms。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35826709

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档