Conversione di YUV-> RGB (elaborazione di immagini) -> YUV durante onPreviewFrame in android?

Sto catturando l'image utilizzando SurfaceView e ottenendo i dati di anteprima Raw di Yuv in public void onPreviewFrame4 (byte [] dati, camera)

Devo eseguire alcune elaborazioni di image in onPreviewFrame, quindi devo convertire i dati di anteprima di Yuv ai dati RGB rispetto alla pre-elaborazione delle immagini e tornare ai dati Yuv.

  • Ottenere tutti i messaggi di gruppo indietro quando si connette a xmpp da ios e android end
  • BroadcastReceiver non riceve BOOT_COMPLETED
  • Phonegap 2.4.0 con Android 4.2 - comportmento strano di doppio clic
  • Android: Visualizzazione di due attività in uno schermo
  • Ottieni l'altezza di un TextView
  • Caricare Android da URL a Bitmap
  • Ho usato sia la function per la codifica e la decodifica dei dati Yuv su RGB come segue:

    public void onPreviewFrame(byte[] data, Camera camera) { Point cameraResolution = configManager.getCameraResolution(); if (data != null) { Log.i("DEBUG", "data Not Null"); // Preprocessing Log.i("DEBUG", "Try For Image Processing"); Camera.Parameters mParameters = camera.getParameters(); Size mSize = mParameters.getPreviewSize(); int mWidth = mSize.width; int mHeight = mSize.height; int[] mIntArray = new int[mWidth * mHeight]; // Decode Yuv data to integer arrays decodeYUV420SP(mIntArray, data, mWidth, mHeight); // Converting int mIntArray to Bitmap and // than image preprocessing // and back to mIntArray. // Encode intArray to Yuv data encodeYUV420SP(data, mIntArray, mWidth, mHeight); } } static public void decodeYUV420SP(int[] rgba, 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) { v = (0xff & yuv420sp[uvp++]) - 128; u = (0xff & yuv420sp[uvp++]) - 128; } 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); // rgba, divide 2^10 ( >> 10) rgba[yp] = ((r << 14) & 0xff000000) | ((g << 6) & 0xff0000) | ((b >> 2) | 0xff00); } } } static public void encodeYUV420SP_original(byte[] yuv420sp, int[] rgba, int width, int height) { final int frameSize = width * height; int[] U, V; U = new int[frameSize]; V = new int[frameSize]; final int uvwidth = width / 2; int r, g, b, y, u, v; for (int j = 0; j < height; j++) { int index = width * j; for (int i = 0; i < width; i++) { r = (rgba[index] & 0xff000000) >> 24; g = (rgba[index] & 0xff0000) >> 16; b = (rgba[index] & 0xff00) >> 8; // rgb to yuv y = (66 * r + 129 * g + 25 * b + 128) >> 8 + 16; u = (-38 * r - 74 * g + 112 * b + 128) >> 8 + 128; v = (112 * r - 94 * g - 18 * b + 128) >> 8 + 128; // clip y yuv420sp[index++] = (byte) ((y < 0) ? 0 : ((y > 255) ? 255 : y)); U[index] = u; V[index++] = v; } } 

    Il problema è che i dati di codifica e decodifica di Yuv potrebbero avere un errore perché se salto il passo di precaricamento rispetto ai dati Yuv codificati si differenziano anche dai dati originali di PreviewCallback.

    Aiutaci a risolvere questo problema. Devo usare questo codice nella scansione OCR per cui ho bisogno di implementare questo tipo di logica.

    Se qualche altro modo di fare la stessa cosa che mi prego di fornire.

    Grazie in anticipo. 🙂

  • Android HttpClient cookies persistenti
  • FragmentActivity che causa ClassNotFoundException
  • Elementi di dati Android Wear
  • Quale driver USB dovremmo utilizzare per il Nexus 5?
  • getApplicationContext (), getBaseContext (), getApplication (), getParent ()
  • personalizzare tabview delle barre di azione
  • 6 Solutions collect form web for “Conversione di YUV-> RGB (elaborazione di immagini) -> YUV durante onPreviewFrame in android?”

    Perché non specificare che l'anteprima della telecamera dovrebbe fornire immagini RGB?

    cioè Camera.Parameters.setPreviewFormat (ImageFormat.RGB_565) ;

    Anche se la documentazione suggerisce che è ansible impostare in quale formato i dati dell'image dovrebbero arrivare dalla camera, in pratica si ha spesso una scelta: NV21, un formato YUV. Per un sacco di informazioni su questo formato, vedere http://www.fourcc.org/yuv.php#NV21 e per informazioni sulla teoria alla base della conversione in RGB, vedere http://www.fourcc.org/fccyvrgb.php . C'è una spiegazione basata sull'image in Estratto image in bianco e nero dal formato NV21 della camera android .

    Un altro formato, chiamato YUV420SP, è anche abbastanza prevalente.

    Tuttavia, una volta impostata la routine onPreviewFrame, la meccanica di andare dall'alloma byte che ti invia a dati utili è in qualche modo, ummmm, poco chiara. Dalla API 8 in poi, è disponibile la seguente soluzione per arrivare a un ByteStream che consolida un JPEG dell'image (compressToJpeg è l'unica opzione di conversione offerta da YuvImage):

     // pWidth and pHeight define the size of the preview Frame ByteArrayOutputStream out = new ByteArrayOutputStream(); // Alter the second parameter of this to the actual format you are receiving YuvImage yuv = new YuvImage(data, ImageFormat.NV21, pWidth, pHeight, null); // bWidth and bHeight define the size of the bitmap you wish the fill with the preview image yuv.compressToJpeg(new Rect(0, 0, bWidth, bHeight), 50, out); 

    Questo JPEG può quindi essere convertito nel formato desiderato. Se si desidera una Bitmap:

     byte[] bytes = out.toByteArray(); Bitmap bitmap= BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 

    Se, per qualsiasi motivo, non si è in grado di farlo, è ansible eseguire la conversione manualmente. Alcuni problemi da superare nel far questo:

    1. I dati arrivano in un arrays di byte. Per definizione, i byte sono numbers firmati, il che significa che vanno da -128 a 127. Tuttavia, i dati sono in realtà non firmati byte (da 0 a 255). Se ciò non viene affrontato, il risultato è destinato ad avere alcuni effetti di clipping strano.

    2. I dati sono in un ordine molto specifico (come per la pagina web menzionata in precedenza) e each pixel deve essere estratto con cura.

    3. Ogni pixel deve essere messo nel posto giusto su una bitmap, ad esempio. Questo richiede anche un approccio piuttosto disordinato (a mio avviso) di build un buffer dei dati e quindi riempire una bitmap da esso.

    4. Se hai effettivamente NV12 (o 420SP), allora devi cambiare le letture per U e V.

    Presento una soluzione (che sembra funzionare), con richieste di correzioni, miglioramenti e modalità per rendere less costosa l'intera operazione. Crea una bitmap la dimensione dell'image di anteprima:

    La variabile dei dati proviene dalla chiamata a onPreviewFrame

     // the bitmap we want to fill with the image Bitmap bitmap = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888); int numPixels = imageWidth*imageHeight; // the buffer we fill up which we then fill the bitmap with IntBuffer intBuffer = IntBuffer.allocate(imageWidth*imageHeight); // If you're reusing a buffer, next line imperative to refill from the start, // if not good practice intBuffer.position(0); // Set the alpha for the image: 0 is transparent, 255 fully opaque final byte alpha = (byte) 255; // Get each pixel, one at a time for (int y = 0; y < imageHeight; y++) { for (int x = 0; x < imageWidth; x++) { // Get the Y value, stored in the first block of data // The logical "AND 0xff" is needed to deal with the signed issue int Y = data[y*imageWidth + x] & 0xff; // Get U and V values, stored after Y values, one per 2x2 block // of pixels, interleaved. Prepare them as floats with correct range // ready for calculation later. int xby2 = x/2; int yby2 = y/2; // make this V for NV12/420SP float U = (float)(data[numPixels + 2*xby2 + yby2*imageWidth] & 0xff) - 128.0f; // make this U for NV12/420SP float V = (float)(data[numPixels + 2*xby2 + 1 + yby2*imageWidth] & 0xff) - 128.0f; // Do the YUV -> RGB conversion float Yf = 1.164f*((float)Y) - 16.0f; int R = (int)(Yf + 1.596f*V); int G = (int)(Yf - 0.813f*V - 0.391f*U); int B = (int)(Yf + 2.018f*U); // Clip rgb values to 0-255 R = R < 0 ? 0 : R > 255 ? 255 : R; G = G < 0 ? 0 : G > 255 ? 255 : G; B = B < 0 ? 0 : B > 255 ? 255 : B; // Put that pixel in the buffer intBuffer.put(alpha*16777216 + R*65536 + G*256 + B); } } // Get buffer ready to be read intBuffer.flip(); // Push the pixel information from the buffer onto the bitmap. bitmap.copyPixelsFromBuffer(intBuffer); 

    Come indicato di seguito @Timmmm, è ansible effettuare la conversione in int moltiplicando i fattori di scala per 1000 (ad esempio 1.164 diventa 1164) e quindi dividendo i risultati finali per 1000.

    Dopo alcuni test su Samsung S4 il codice più veloce è (120% più veloce di Neil (galleggianti!) E 30% più veloce di Hitesh originale):

     static public void decodeYUV420SP(int[] rgba, byte[] yuv420sp, int width, int height) { final int frameSize = width * height; // define variables before loops (+ 20-30% faster algorithm o0`) int r, g, b, y1192, y, i, uvp, u, v; for (int j = 0, yp = 0; j < height; j++) { uvp = frameSize + (j >> 1) * width; u = 0; v = 0; for (i = 0; i < width; i++, yp++) { y = (0xff & ((int) yuv420sp[yp])) - 16; if (y < 0) y = 0; if ((i & 1) == 0) { v = (0xff & yuv420sp[uvp++]) - 128; u = (0xff & yuv420sp[uvp++]) - 128; } y1192 = 1192 * y; r = (y1192 + 1634 * v); g = (y1192 - 833 * v - 400 * u); b = (y1192 + 2066 * u); // Java's functions are faster then 'IFs' r = Math.max(0, Math.min(r, 262143)); g = Math.max(0, Math.min(g, 262143)); b = Math.max(0, Math.min(b, 262143)); // rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & // 0xff00) | ((b >> 10) & 0xff); // rgba, divide 2^10 ( >> 10) rgba[yp] = ((r << 14) & 0xff000000) | ((g << 6) & 0xff0000) | ((b >> 2) | 0xff00); } } } 

    La velocità è paragonabile a YuvImage.compressToJpeg () con ByteArrayOutputStream come output (30-50 ms per l'image 640×480).

    Risultato: Samsung S4 mini (2×1.7GHz) non può comprimere in JPEG / convertire YUV in RGB in tempo reale (640×480 @ 30fps)

    L'implementazione Java è 10 volte più lenta della versione c, suggerisco di utilizzare la libreria GPUImage o semplicemente spostare questa parte del codice.

    C'è una versione Android di GPUImage: https://github.com/CyberAgent/android-gpuimage

    È ansible includere questa libreria se si utilizza gradle e call il metodo: GPUImageNativeLibrary.YUVtoRBGA (inputArray, WIDTH, HEIGHT, outputArray);

    Io confronto l'ora, per un'image NV21 che è 960×540, usa sopra il codice java, costa 200 ms +, con la versione GPUImage, solo 10 ms ~ 20 ms.

    Correggere lo snippet di codice di cui sopra

     static public void decodeYUV420SP(int[] rgba, byte[] yuv420sp, int width, int height) { final int frameSize = width * height; int r, g, b, y1192, y, i, uvp, u, v; for (int j = 0, yp = 0; j < height; j++) { uvp = frameSize + (j >> 1) * width; u = 0; v = 0; for (i = 0; i < width; i++, yp++) { y = (0xff & ((int) yuv420sp[yp])) - 16; if (y < 0) y = 0; if ((i & 1) == 0) { // above answer is wrong at the following lines. just swap ***u*** and ***v*** u = (0xff & yuv420sp[uvp++]) - 128; v = (0xff & yuv420sp[uvp++]) - 128; } y1192 = 1192 * y; r = (y1192 + 1634 * v); g = (y1192 - 833 * v - 400 * u); b = (y1192 + 2066 * u); r = Math.max(0, Math.min(r, 262143)); g = Math.max(0, Math.min(g, 262143)); b = Math.max(0, Math.min(b, 262143)); // combine ARGB rgba[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) | 0xff); } } } 

    Provate RenderScript ScriptIntrinsicYuvToRGB, che viene fornito con JellyBean 4.2 (Api 17+).

    https://developer.android.com/reference/android/renderscript/ScriptIntrinsicYuvToRGB.html

    Su Nexus 7 (2013, JellyBean 4.3) una conversione dell'image 1920×1080 (anteprima completa della telecamera HD) richiede circa 7 ms.

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.