Mobile Vision API - объединить новый объект-детектор для продолжения обработки кадра
Я хочу использовать новую функцию обнаружения лица, которую API видения предоставляет вместе с дополнительной обработкой кадров в приложении. Для этого мне нужно иметь доступ к кадру камеры, который был обработан детектором лица, и объединить процессор с использованием данных, обнаруженных лицом.
Как я вижу в примере, CameraSource абстрагирует обнаружение и доступ камеры, и я не могу получить доступ к обрабатываемому кадру. Есть ли примеры того, как получить кадр камеры в этом API или, может быть, создать и объединить детектор, который его получает? Возможно ли это по крайней мере?
Спасибо,
Lucio
Ответы
Ответ 1
Да, это возможно. Вам необходимо создать свой собственный подкласс Detector, который обертывает FaceDetector и выполняет ваш дополнительный код обработки кадра в методе обнаружения. Он будет выглядеть примерно так:
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);
}
}
Вы обертываете детектор лица своим классом и передаете свой класс в источник камеры. Он будет выглядеть примерно так:
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();
Ваш детектор будет вызываться сначала с данными необработанного кадра.
Обратите внимание, что изображение может быть не вертикально, если устройство повернуто. Вы можете получить ориентацию через метод metadata.getRotation фрейма.
Одно слово предостережения: как только метод обнаружения вернется, вы не должны получить доступ к данным пикселя кадра. Поскольку источник камеры перерабатывает буферы изображений, содержимое объекта фрейма будет в конечном итоге переопределено после возвращения метода.
EDIT: (дополнительные примечания)
Вы также можете избежать кода шаблона MyFaceDetector
с помощью MultiDetector следующим образом:
MultiDetector multiDetector = new MultiDetector.Builder()
.add(new FaceDetector.Builder(context)
.build())
.add(new YourReallyOwnDetector())
.build();
Также обратите внимание на использование FaceTrackerFactory
в сочетании с MultiProcessor
описанных там.
Ответ 2
Вот окончательное решение, на котором я остановился. Предполагается, что поле расположено по центру экрана.
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);
}
}
Оберните этот класс в свой детектор следующим образом
BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
BoxDetector boxDetector = new BoxDetector(barcodeDetector, heightPx, widthPx);
Ответ 3
В соответствии с запросом пользователя (нового разработчика), как установить детектор коробки. Вы можете использовать как это
Я просто привожу пример о распознавателе текста, чтобы вы могли установить, как это
TextRecognizer mTextRecognizer = new TextRecognizer.Builder(getApplicationContext()).build();
BoxDetector boxDetector = new BoxDetector(mTextRecognizer, heightPx, widthPx);
установить boxDetecotr здесь
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.
}
});
}
});