Je souhaite utiliser la nouvelle fonctionnalité de détection de visages fournie par l'API Vision ainsi que le traitement de trame supplémentaire dans une application. Pour cela, je dois avoir accès au cadre de la caméra qui a été traité par le détecteur de visage et concaténer un processeur en utilisant les données détectées par le visage.
Comme je le vois dans l'exemple, CameraSource résume la détection et l'accès à la caméra, et je ne peux pas avoir accès à l'image en cours de traitement. Y a-t-il des exemples de comment obtenir le cadre de la caméra dans cette API, ou, peut-être, créer et concaténer un détecteur qui le reçoit? Est-ce possible au moins?
Merci, Lucio
Oui c'est possible. Vous devez créer votre propre sous-classe de Detector qui enveloppe FaceDetector et exécute votre code de traitement de trame supplémentaire dans la méthode de détection. Cela ressemblerait à quelque chose comme ceci:
class MyFaceDetector extends Detector<Face> {
private Detector<Face> mDelegate;
MyFaceDetector(Detector<Face> delegate) {
mDelegate = delegate;
}
public SparseArray<Face> detect(Frame frame) {
// *** add your custom frame processing code here
return mDelegate.detect(frame);
}
public boolean isOperational() {
return mDelegate.isOperational();
}
public boolean setFocus(int id) {
return mDelegate.setFocus(id);
}
}
Vous emballez le détecteur de visage avec votre classe et passez votre classe dans la source de la caméra. Cela ressemblerait à quelque chose comme ceci:
FaceDetector faceDetector = new FaceDetector.Builder(context)
.build();
MyFaceDetector myFaceDetector = new MyFaceDetector(faceDetector);
myFaceDetector.setProcessor(/* include your processor here */);
mCameraSource = new CameraSource.Builder(context, myFaceDetector)
.build();
Votre détecteur sera appelé en premier avec les données de trame brutes.
Notez que l'image peut ne pas être droite si l'appareil est tourné. Vous pouvez obtenir l'orientation grâce à la méthode metadata.getRotation du cadre.
Un mot d'avertissement: une fois que la méthode de détection revient, vous ne devez pas accéder aux données de pixel de trame. Étant donné que la source de la caméra recycle les tampons d'image, le contenu de l'objet cadre sera éventuellement remplacé une fois la méthode revenue.
EDIT: (notes supplémentaires) Vous pouvez également éviter le code passe-partout de MyFaceDetector
en utilisant un MultiDetector comme ceci:
MultiDetector multiDetector = new MultiDetector.Builder()
.add(new FaceDetector.Builder(context)
.build())
.add(new YourReallyOwnDetector())
.build();
Notez également l'utilisation de FaceTrackerFactory
en conjonction avec MultiProcessor
qui y est décrite.
Voici la solution finale sur laquelle j'ai opté. Cela suppose que la boîte est centrée sur l'écran.
public class BoxDetector extends Detector {
private Detector mDelegate;
private int mBoxWidth, mBoxHeight;
public BoxDetector(Detector delegate, int boxWidth, int boxHeight) {
mDelegate = delegate;
mBoxWidth = boxWidth;
mBoxHeight = boxHeight;
}
public SparseArray detect(Frame frame) {
int width = frame.getMetadata().getWidth();
int height = frame.getMetadata().getHeight();
int right = (width / 2) + (mBoxHeight / 2);
int left = (width / 2) - (mBoxHeight / 2);
int bottom = (height / 2) + (mBoxWidth / 2);
int top = (height / 2) - (mBoxWidth / 2);
YuvImage yuvImage = new YuvImage(frame.getGrayscaleImageData().array(), ImageFormat.NV21, width, height, null);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(left, top, right, bottom), 100, byteArrayOutputStream);
byte[] jpegArray = byteArrayOutputStream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.length);
Frame croppedFrame =
new Frame.Builder()
.setBitmap(bitmap)
.setRotation(frame.getMetadata().getRotation())
.build();
return mDelegate.detect(croppedFrame);
}
public boolean isOperational() {
return mDelegate.isOperational();
}
public boolean setFocus(int id) {
return mDelegate.setFocus(id);
}
}
Enveloppez cette classe dans votre détecteur comme ceci
BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
BoxDetector boxDetector = new BoxDetector(barcodeDetector, heightPx, widthPx);
Selon la demande de l'utilisateur (nouveau développeur), comment configurer le détecteur de boîte. Vous pouvez utiliser comme ça
utilisation @MCR
Classe BoxDetector, puis suivez ces étapes.
Je donne juste un exemple sur la reconnaissance de texte pour que vous puissiez définir comme ceci
TextRecognizer mTextRecognizer = new TextRecognizer.Builder(getApplicationContext()).build();
BoxDetector boxDetector = new BoxDetector(mTextRecognizer, heightPx, widthPx);
set boxDetecotr ici
boxDetector.setProcessor(new Detector.Processor<TextBlock>() {
@Override
public void release() {
}
@Override
public void receiveDetections(Detector.Detections<TextBlock> detections) {
SparseArray<TextBlock> items = detections.getDetectedItems();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < items.size(); ++i) {
TextBlock item = items.valueAt(i);
if (item != null && item.getValue() != null) {
stringBuilder.append(item.getValue() + " ");
}
}
final String fullText = stringBuilder.toString();
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
// here full string(fullText) you can get whatever is it scanned.
}
});
}
});