Использование onPreviewFrame для запуска моделей ML - PullRequest
4 голосов
/ 28 февраля 2020

Так что я использую устаревший API-интерфейс Camera (насколько я могу судить), чтобы получить обратные вызовы previewFrame для запуска нескольких моделей машинного обучения, которые у меня есть. Я подтвердил, что модели машинного обучения работают, когда передается растровое изображение, когда я делаю снимок с помощью обратного вызова onPictureTaken. Прямо сейчас в приведенных ниже примерах я просто тестирую сканер штрих-кода ML Kit в качестве базового варианта, но мои пользовательские модели, похоже, также хорошо работают с обратным вызовом onPictureTaken.

Из того, что я понял, использование onPreviewFrame - не обязательно лучший способ сделать это, но ради быстрой демонстрации опыта (и опыта обучения) я решил просто go этот маршрут. Исходя из всего, что я пробовал у других, имеющих решения в Интернете, я не могу заставить что-то работать должным образом. Приведенный ниже код возвращает ноль:

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
//        Log.d("onPreviewFrame bytes.length", String.valueOf(bytes.length));
//        final Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
//        Log.d("onPreviewFrame bmp.getHeight()", String.valueOf(bmp.getHeight()));

    Camera.Parameters parameters = camera.getParameters();
    int width = parameters.getPreviewSize().width;
    int height = parameters.getPreviewSize().height;


    Log.d("onPreviewFrame - width", String.valueOf(width));
    Log.d("onPreviewFrame - height", String.valueOf(height));
    Log.d("onPreviewFrame - parameters.getPreviewFormat()", String.valueOf(parameters.getPreviewFormat()));

    YuvImage yuv = new YuvImage(data, parameters.getPreviewFormat(), width, height, null);

    ByteArrayOutputStream out = new ByteArrayOutputStream();
    yuv.compressToJpeg(new Rect(0, 0, width, height), 100, out);

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


    byte[] bytes = yuv.getYuvData();
    final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

    extractBarcode(FirebaseVisionImage.fromBitmap(bitmap), bitmap);
}

Вот еще кое-что, что я пробовал:

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
//        Log.d("onPreviewFrame bytes.length", String.valueOf(bytes.length));
//        final Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
//        Log.d("onPreviewFrame bmp.getHeight()", String.valueOf(bmp.getHeight()));

    Camera.Parameters parameters = camera.getParameters();
    int width = parameters.getPreviewSize().width;
    int height = parameters.getPreviewSize().height;


    Log.d("onPreviewFrame - width", String.valueOf(width));
    Log.d("onPreviewFrame - height", String.valueOf(height));

    YuvImage yuv = new YuvImage(data, parameters.getPreviewFormat(), width, height, null);

    ByteArrayOutputStream out = new ByteArrayOutputStream();
    yuv.compressToJpeg(new Rect(0, 0, width, height), 100, out);


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

    extractBarcode(FirebaseVisionImage.fromBitmap(bitmap), bitmap);
}

К сожалению, я получил эту ошибку:

ML Kit обнаружил, что Вы, кажется, передаете кадры камеры детектору как объект Bitmap. Это неэффективно. Пожалуйста, используйте формат YUV_420_888 для Camera2 API или формат NV21 для (унаследованного) API-интерфейса камеры и напрямую передайте байтовый массив в ML Kit.

с параметрами .getPreviewFormat (), возвращая 17, равное NV21. Я также попытался просто изменить его на ImageFormat.YUV_420_888, но это привело к исключению недопустимого аргумента:

на данный момент поддерживают только ImageFormat.NV21 и ImageFormat.YUY2

Ответы [ 2 ]

3 голосов
/ 28 февраля 2020

Вместо использования Camera API, попробуйте использовать CameraX . Его легко использовать, и вы можете выполнить свой код всякий раз, когда кадр получен с камеры. Пытаясь интегрировать модель ML с камерой, я столкнулся с похожей ошибкой и затем обратился к CameraX.

По сути, мы создадим класс ImageAnalysis.Analyser, через который мы получим Image объект (кадры). Используя функцию расширения, мы преобразуем этот Image объект в YuvImage.

. Вы можете следовать этому codelab , чтобы использовать CameraX для анализа кадров. Вы создадите класс, который расширяет класс ImageAnalysis.Analyser.

class FrameAnalyser() : ImageAnalysis.Analyzer {

    override fun analyze(image: ImageProxy?, rotationDegrees: Int) {
        val yuvImage = image?.image?.toYuv() // The extension function
    }
}

Создайте функцию расширения, которая преобразует Image в YuvImage.

private fun Image.toYuv(): YuvImage {
    val yBuffer = planes[0].buffer
    val uBuffer = planes[1].buffer
    val vBuffer = planes[2].buffer
    val ySize = yBuffer.remaining()
    val uSize = uBuffer.remaining()
    val vSize = vBuffer.remaining()
    val nv21 = ByteArray(ySize + uSize + vSize)
    yBuffer.get(nv21, 0, ySize)
    vBuffer.get(nv21, ySize, vSize)
    uBuffer.get(nv21, ySize + vSize, uSize)
    val yuvImage = YuvImage(nv21, ImageFormat.NV21, this.width, this.height, null)
    return yuvImage
}

Вы можете изменить формат изображения YUV при необходимости. Обратитесь к этим документам .

0 голосов
/ 03 марта 2020

Защищено от прямого прохождения FirebaseVisionImage

extractBarcode(FirebaseVisionImage.fromBitmap(bitmap), bitmap);

Вы можете сделать это так

var bitmap = toARGBBitmap(ocrBitmap)
  extractBarcode(FirebaseVisionImage.fromBitmap(bitmap), bitmap);

 private fun toARGBBitmap(img: Bitmap): Bitmap {
        return img.copy(Bitmap.Config.ARGB_8888, true)
    }

Вы можете попробовать это :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...