2016-09-28 6 views
2

Я искал преобразование байт NV21, который я получаю от onPreviewFrame(). Я искал форумы и Google для различных решений. Я попробовал RenderScripts и некоторые другие примеры кода. Некоторые из них дают мне изображение с желтым оттенком, некоторые дают мне изображение с красным и синим перевернутым (после того, как я переверну его обратно в коде, я получаю желтый оттенок назад), некоторые дают мне странные цветовые функции по всему изображению (почти как негатив), некоторые дают мне изображение в оттенках серого, некоторые дают мне изображение настолько темным, что вы ничего не можете сделать.NV21 для растрового изображения на Android, очень темное изображение, оттенки серого или желтый оттенок?

Поскольку я набираю вопрос, я понимаю, что я должен быть идиотом в комнате, поэтому мы начнем с this post. Это конкретное решение дает мне очень темное изображение, но я недостаточно крут, чтобы еще прокомментировать. Кто-нибудь пробовал это решение или имеет тот, который производит изображение с тем же качеством, что и оригинальный формат NV21?

Мне нужен либо действительный байт ARGB [], либо действительный Bitmap, я могу изменить свой проект, чтобы справиться с ним. Просто для справки, я попробовал эти (и некоторые другие, которые на самом деле являются копирку них):

One solution I tried
Another solution I tried

ответ

1

Если вы пытаетесь преобразовать YUV от камеры к Bitmap, здесь что-то вы можете попробовать:

// import android.renderscript.* 
// RenderScript mRS; 
// ScriptIntrinsicYuvToRGB mYuvToRGB; 
// Allocation yuvPreviewAlloc; 
// Allocation rgbOutputAlloc; 

// Create RenderScript context, ScriptIntrinsicYuvToRGB and Allocations and keep reusing them. 
if (NotInitialized) { 
    mRS = RenderScript.create(this). 
    mYuvToRGB = ScriptIntrinsicYuvToRGB.create(mRS, Element.YUV(mRS));  

    // Create a RS Allocation to hold NV21 data. 
    Type.Builder tYuv = new Type.Builder(mRS, Element.YUV(mRS)); 
    tYuv.setX(width).setY(height).setYuvFormat(android.graphics.ImageFormat.NV21); 
    yuvPreviewAlloc = Allocation.createTyped(mRS, tYuv.create(), Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_INPUT); 

    // Create a RS Allocation to hold RGBA data. 
    Type.Builder tRgb = new Type.Builder(mRS, Element.RGBA_8888(mRS)); 
    tRgb.setX(width).tRgb(height); 
    rgbOutputAlloc = Allocation.createTyped(mRS, tRgb.create(), Allocation.USAGE_SCRIPT); 

    // Set input of ScriptIntrinsicYuvToRGB 
    mYuvToRGB.setInput(yuvPreviewAlloc); 
} 

// Use rsPreviewSurface as one of the output surface from Camera API. 
// You can refer to https://github.com/googlesamples/android-HdrViewfinder/blob/master/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java#L504 
Surface rsPreviewSurface = yuvPreviewAlloc.getSurface(); 
... 

// Whenever a new frame is available 
// Update the yuv Allocation with a new Camera buffer without any copy. 
// You can refer to https://github.com/googlesamples/android-HdrViewfinder/blob/master/Application/src/main/java/com/example/android/hdrviewfinder/ViewfinderProcessor.java#L109 
yuvPreviewAlloc.ioReceive(); 
// The actual Yuv to Rgb conversion. 
mYuvToRGB.forEach(rgbOutputAlloc); 

// Copy the rgb Allocation to a Bitmap. 
rgbOutputAlloc.copyTo(mBitmap); 

// continue processing mBitmap. 
... 
+0

Вы также можете играть с «YUV_420_888» и «YV12», в случае, если буфер камеры не «NV21». –

+0

Я пытаюсь это сделать, и я получаю и ошибки, которых я раньше не видел: «E/RenderScript: YuvToRGB выполняется без данных, пропуская» каждый кадр предварительного просмотра. Я попытался добавить «yuvPreviewAlloc.copyFrom (данные)»; просто чтобы быть уверенным, что это не так. Кто-нибудь сталкивался с этим? –

+0

Это сообщение об ошибке обычно означает, что в yuvPreviewAlloc Allocation не было получено никаких данных из API камеры. Пожалуйста, дважды проверьте 1. Если rsPreviewSurface правильно настроена как выходная поверхность камеры. 2. Если вызывается ioReceive. 3. убедитесь, что вы используете «import android.renderscript. *», Так как USAGE_IO_INPUT не работает с поддержкой библиотеки RenderScript (import android.support.v8.renderscript). Я также добавил некоторые комментарии к коду, чтобы указать вам некоторую ссылку на код для настройки. –

0

Я был в состоянии получить другой метод работает (тот, который был ранее связан) используя код here. Но это давало красный/синий цвет. Итак, я просто перестроил линии U и V, и все было в порядке. Это не так быстро, как RenderScript. Было бы неплохо, если бы RenderScript работал правильно. Вот код:

static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) { 
    final int frameSize = width * height; 

    for (int j = 0, yp = 0; j < height; j++) { 
     int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; 
     for (int i = 0; i < width; i++, yp++) { 
      int y = (0xff & ((int) yuv420sp[yp])) - 16; 
      if (y < 0) y = 0; 
      if ((i & 1) == 0) { 
       u = (0xff & yuv420sp[uvp++]) - 128; //Just changed the order 
       v = (0xff & yuv420sp[uvp++]) - 128; //It was originally v then u 
      } 

      int y1192 = 1192 * y; 
      int r = (y1192 + 1634 * v); 
      int g = (y1192 - 833 * v - 400 * u); 
      int b = (y1192 + 2066 * u); 

      if (r < 0) r = 0; else if (r > 262143) r = 262143; 
      if (g < 0) g = 0; else if (g > 262143) g = 262143; 
      if (b < 0) b = 0; else if (b > 262143) b = 262143; 

      rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); 
     } 
    } 
} 

У кого-нибудь есть RenderScript, у которого нет проблем с оттенками и/или переворачиванием цвета?

1

При использовании ScriptIntrinsics я настоятельно рекомендую обновить по крайней мере JellyBean 4.3 или выше (API18). Все гораздо проще в использовании, чем в JB 4.2 (API 17).

ScriptIntrinsicYuvToRGB не так сложно, как кажется. Особенно вам не нужны объекты Type.Builder. Формат предварительного просмотра камеры must be NV21!

in onCreate() ...Метод создания объекта Renderscript и характеристическая:

mRS = RenderScript.create(this); 
mYuvToRGB = ScriptIntrinsicYuvToRGB.create(mRS, Element.U8_4(mRS));  

С вашей cameraPreviewWidth и cameraPreviewHeight вычислить длину массива камеры байт данных:

int yuvDatalength = cameraPreviewWidth*cameraPreviewHeight*3/2 ; // this is 12 bit per pixel 

Вам нужно растровое изображение для вывода:

mBitmap = Bitmap.createBitmap(cameraPreviewWidth, cameraPreviewHeight, Bitmap.Config.ARGB_8888); 

Затем вы создаете распределения ввода и вывода (здесь приведены изменения в API18 +)

yuvPreviewAlloc = Allocation.createSized(mRS, Element.U8(mRS), yuvDatalength); 

rgbOutputAlloc = Allocation.createFromBitmap(mRS, mBitmap); // this simple ! 

и установить скрипт-вход для распределения входных

mYuvToRGB.setInput(yuvPreviewAlloc); // this has to be done only once ! 

В цикле камеры (всякий раз, когда новый кадр имеющийся), скопировать NV21 байт-массив (данные []) в yuvPreviewAlloc , выполнить сценарий и скопировать результат в растровом изображении:

yuvPreviewAlloc.copyFrom(data); // or yuvPreviewAlloc.copyFromUnchecked(data); 

mYuvToRGB.forEach(rgbOutputAlloc); 

rgbOutputAlloc.copyTo(mBitmap); 

Например: на Nexus 7 (2013, Jellybean 4.3) полный HD (1920х1080) преобразование камеры предварительного просмотра занимает около 7 мс.

+0

Это действительно работает, и он работает хорошо! В конце концов, мне нужно было сделать дополнительную работу внутри сценария рендеринга, чтобы сохранить мою обработку до минимума. Итак, мне пришлось написать собственный сценарий рендеринга (который потребовалось некоторое время, чтобы понять). Я нашел много полезной информации в книге Renderscript (я получил ее на Amazon). –

 Смежные вопросы

  • Нет связанных вопросов^_^