2015-09-05 12 views
8

Ich versuche, Frame-Bild zu verarbeiten, während neue Android-Gesichtserkennung Mobile Vision API verwenden.Wie erstelle ich eine Bitmap aus einem Graustufen-Byte-Buffer-Image?

So habe ich Custom Detector erstellt, um Frame zu erhalten und versucht, getBitmap() -Methode aufzurufen, aber es ist null, so dass ich Graustufen Daten von Frame zugegriffen habe. Gibt es eine Möglichkeit, eine Bitmap daraus oder eine ähnliche Bildhalterklasse zu erstellen?

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

Der Rahmen hat keine Bitmap-Daten, da er direkt von der Kamera kommt. Das Bildformat von der Kamera ist NV21: http://developer.android.com/reference/android/graphics/ImageFormat.html#NV21 – pm0733464

Antwort

11

Sie haben dies bereits wahrscheinlich aussortiert, aber im Falle in Zukunft auf diese Frage jemand stolpert, hier ist, wie ich es gelöst:

Wie @ pm0733464 weist darauf hin, kommt die Standard-Bildformat aus android.hardware.Camera ist NV21, und das ist das von CameraSource verwendete.

This Antwort liefert die Stackoverflow Antwort:

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); 

Obwohl frame.getGrayscaleImageData()bitmap schlägt vor, wird eine Graustufenversion des Originalbildes sein, ist dies nicht der Fall ist, in meiner Erfahrung. Tatsächlich ist die Bitmap identisch mit der, die an die SurfaceHolder nativ geliefert wird.

+0

Das funktioniert super. Wie auch immer, ich konnte nur das Gesicht anstatt das ganze Bild ausschneiden? – Andro

0

Fügen Sie nur ein paar Extras hinzu, um eine Box mit 300px auf jeder Seite für den Erkennungsbereich zu setzen. Übrigens, wenn Sie nicht die Höhe und Breite des Frames in getGrayscaleImageData() aus den Metadaten einfügen, erhalten Sie merkwürdig beschädigte Bitmaps.

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); 
    } 
}