2016-08-18 33 views
1

我使用支持庫中的ScriptIntrinsicYuvToRGB將圖像從NV21格式轉換爲Bitmaps(ARGB_8888)時出現問題。下面的代碼可以說明問題。使用ScriptIntrinsicYuvToRGB(支持lib)NV21到位圖時損壞的圖像

假設我有以下50×50圖像(下面的一個是從裝置的屏幕截圖,實際上不是50×50):

enter image description here

然後,如果我轉換所述圖像以通過YuvImage#compressToJpeg + BitmapFactory.decodeByteArray一個位圖:

YuvImage yuvImage = new YuvImage(example, android.graphics.ImageFormat.NV21, width, height, null); 
ByteArrayOutputStream os = new ByteArrayOutputStream(); 
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, os); 
byte[] jpegByteArray = os.toByteArray(); 
return BitmapFactory.decodeByteArray(jpegByteArray, 0, jpegByteArray.length); 

我得到了預期的圖像。但是,如果我把它轉換通過ScriptIntrinsicYuvToRGB如下:

RenderScript rs = RenderScript.create(context); 

Type.Builder tb = new Type.Builder(rs, Element.createPixel(rs, 
     Element.DataType.UNSIGNED_8, Element.DataKind.PIXEL_YUV)); 
tb.setX(width); 
tb.setY(height); 
tb.setYuvFormat(android.graphics.ImageFormat.NV21); 
Allocation yuvAllocation = Allocation.createTyped(rs, tb.create(), Allocation.USAGE_SCRIPT); 
yuvAllocation.copyFrom(example); 

Type rgbType = Type.createXY(rs, Element.RGBA_8888(rs), width, height); 
Allocation rgbAllocation = Allocation.createTyped(rs, rgbType); 

ScriptIntrinsicYuvToRGB yuvToRgbScript = ScriptIntrinsicYuvToRGB.create(rs, Element.RGBA_8888(rs)); 
yuvToRgbScript.setInput(yuvAllocation); 
yuvToRgbScript.forEach(rgbAllocation); 

Bitmap convertedBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
rgbAllocation.copyTo(convertedBitmap); 

我得到以下損壞的圖像:

enter image description here

我已經注意到這種情況的發生與方形尺寸的圖像,且從未2的冪(例如64x64,128x128等)。如果我沒有嘗試方形尺寸,我不會注意到這個問題,因爲一些圖片尺寸(如2592x1728)可以正常工作。我錯過了什麼?

更新:將生成原始圖像的要求代碼:

int width = 50; 
int height = 50; 
int size = width * height; 

byte[] example = new byte[size + size/2]; 
for (int x = 0; x < width; x++) { 
    for (int y = 0; y < height; y++) { 
     example[y * width + x] = (byte) ((x*y/(float)size) * 255); 
    } 
} 
for (int i = 0; i < size/2; i++) { 
    example[size + i] = (byte) (127); 
} 
+0

你能後的輸入文件,它可以用來測試你的代碼?重現錯誤有點困難,否則。 :) – cmaster11

+0

@ cmaster11我做得比這更好,我只是在問題的末尾添加了生成輸入圖像的代碼:) – silvaren

回答

2

下面的代碼行爲以錯誤的方式:

Type.Builder tb = new Type.Builder(rs, Element.createPixel(rs, 
        Element.DataType.UNSIGNED_8, Element.DataKind.PIXEL_YUV)); 
tb.setX(width); 
tb.setY(height); 
tb.setYuvFormat(android.graphics.ImageFormat.NV21); 
yuvAllocation = Allocation.createTyped(rs, tb.create(), Allocation.USAGE_SCRIPT); 

如果你使用一個「原始」的方式取代它創建分配,轉換將起作用:

int expectedBytes = width * height * 
       ImageFormat.getBitsPerPixel(ImageFormat.NV21)/8; 

Type.Builder yuvTypeBuilder = new Type.Builder(rs, Element.U8(rs)) 
                .setX(expectedBytes); 
Type yuvType = yuvTypeBuilder.create(); 
yuvAllocation = Allocation.createTyped(rs, yuvType, Allocation.USAGE_SCRIPT); 

看來,如果您使用PIXEL_YUV定義,在16維的非倍數上有尺寸問題。仍在調查。

+0

據我所知,任何偶數(如在奇數/偶數)分辨率尺寸圖像都可以接受對於NV21(參見http://i.stack.imgur.com/NqqJD.png格式參考),你會發現即使是這個例子是6x4,它不能被16整除。所以它看起來像是一個50x50的圖像NV21-有效,但我可能做錯了什麼或ScriptIntrinsicYuvToRgb中存在一個錯誤 – silvaren

+0

該圖像不是指向NV21,它僅僅是一個例子,告訴你平面YUV系統的內存分配是什麼 – cmaster11

+0

什麼是錯誤的它?我在格式上多次使用該格式引用來進行直接字節操作。 – silvaren