2015-09-05 38 views
8

Sto cercando di ottenere l'immagine del frame da elaborare mentre utilizzo la nuova API di visione mobile Android.Come creare Bitmap dall'immagine buffer di byte grayscaled?

Quindi ho creato Custom Detector per ottenere Frame e ho provato a chiamare il metodo getBitmap() ma è nullo quindi ho accesso ai dati in scala di grigi del frame. C'è un modo per creare una bitmap o una classe di immagini simile?

public class CustomFaceDetector extends Detector<Face> { 
private Detector<Face> mDelegate; 

public CustomFaceDetector(Detector<Face> delegate) { 
    mDelegate = delegate; 
} 

public SparseArray<Face> detect(Frame frame) { 
    ByteBuffer byteBuffer = frame.getGrayscaleImageData(); 
    byte[] bytes = byteBuffer.array(); 
    int w = frame.getMetadata().getWidth(); 
    int h = frame.getMetadata().getHeight(); 
    // Byte array to Bitmap here 
    return mDelegate.detect(frame); 
} 

public boolean isOperational() { 
    return mDelegate.isOperational(); 
} 

public boolean setFocus(int id) { 
    return mDelegate.setFocus(id); 
}} 
+0

Il frame non ha dati bitmap perché proviene direttamente dalla fotocamera. Il formato immagine della videocamera è NV21: http://developer.android.com/reference/android/graphics/ImageFormat.html#NV21 – pm0733464

risposta

11

probabilmente avete risolto questa situazione già, ma nel caso in cui qualcuno si imbatte in questa domanda in futuro, ecco come ho risolto:

Come @ pm0733464 sottolinea, il formato immagine predefinito venire su android.hardware.Camera è NV21 e quello utilizzato da CameraSource.

This StackOverflow risposta fornisce la risposta:

YuvImage yuvimage=new YuvImage(byteBuffer, ImageFormat.NV21, w, h, null); 
ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
yuvimage.compressToJpeg(new Rect(0, 0, w, h), 100, baos); // Where 100 is the quality of the generated jpeg 
byte[] jpegArray = baos.toByteArray(); 
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.length); 

Anche se frame.getGrayscaleImageData() suggerisce bitmap sarà una versione in scala di grigi dell'immagine originale, questo non è il caso, nella mia esperienza. In effetti, la bitmap è identica a quella fornita allo SurfaceHolder in modo nativo.

+0

Funziona alla grande. Ad ogni modo, potrei ritagliare solo la faccia anziché l'intera immagine? – Andro

0

Aggiungendo solo alcuni extra per impostare una casella di 300 px su ciascun lato per l'area di rilevamento. A proposito, se non si inseriscono l'altezza e la larghezza del frame in getGrayscaleImageData() dai metadati si ottengono strani bitmap corrotti.

public SparseArray<Barcode> detect(Frame frame) { 
     // *** crop the frame here 
     int boxx = 300; 
     int width = frame.getMetadata().getWidth(); 
     int height = frame.getMetadata().getHeight(); 
     int ay = (width/2) + (boxx/2); 
     int by = (width/2) - (boxx/2); 
     int ax = (height/2) + (boxx/2); 
     int bx = (height/2) - (boxx/2); 

     YuvImage yuvimage=new YuvImage(frame.getGrayscaleImageData().array(), ImageFormat.NV21, frame.getMetadata().getWidth(), frame.getMetadata().getHeight(), null); 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     yuvimage.compressToJpeg(new Rect(by, bx, ay, ax), 100, baos); // Where 100 is the quality of the generated jpeg 
     byte[] jpegArray = baos.toByteArray(); 
     Bitmap bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.length); 

     Frame outputFrame = new Frame.Builder().setBitmap(bitmap).build(); 
     return mDelegate.detect(outputFrame); 
    } 

    public boolean isOperational() { 
     return mDelegate.isOperational(); 
    } 

    public boolean setFocus(int id) { 
     return mDelegate.setFocus(id); 
    } 
}