2016-03-06 216 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墊建造時