ML сканер штрих-кода из потока предварительного просмотра камеры? - PullRequest
0 голосов
/ 18 декабря 2018

Я пытаюсь сделать сканер штрих-кода, используя детектор штрих-кода ML kit, camera2 API и Kotlin.Что касается камеры2, я начинаю с примера Google camera2basic Что касается детектора штрих-кодов комплекта ML, я начинаю с документа: Сканирование штрих-кодов с помощью комплекта ML на Android

В Camera2BasicFragment/ createCameraPreviewSession метод, я добавил

previewRequestBuilder.addTarget(imageReader!!.surface)

, поэтому onImageAvailableListener вызывается каждый раз, когда изображение доступно.

В методе Camera2BasicFragment / setUpCameraOutputs я изменил ImageReader ImageFormat.JPEG на ImageFormat YUV420_888,поэтому в onImageAvailableListener ImageReader выдает YUV-изображение

Тогда вот мой onImageAvailableListener:

   private val onImageAvailableListener = ImageReader.OnImageAvailableListener {
        val metadata = FirebaseVisionImageMetadata.Builder()
            .setWidth(480)   // 480x360 is typically sufficient for
            .setHeight(360)  // image recognition
            .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_YV12)
            .setRotation(getRotationCompensation(cameraId, activity as Activity, context!!))
            .build()
        BarcodeReader(it.acquireNextImage(), detector, metadata, mListener).run()
    }

В метаданных «ширина» и «высота» соответствуют указанным в документе ML kit doc, «формат»'является YV12 для обработки формата YUV

, а считыватель штрих-кода:

class BarcodeReader (private val image: Image,
                     private val detector: FirebaseVisionBarcodeDetector,
                     private val metadata: FirebaseVisionImageMetadata,
                     private val mListener: IBarcodeScanner) : Runnable {
    override fun run() {
        val visionImage = FirebaseVisionImage.fromByteBuffer(image.planes[0].buffer, metadata)
        detector.detectInImage(visionImage)
            .addOnSuccessListener { barcodes ->
                // Task completed successfully
                // [START_EXCLUDE]
                // [START get_barcodes]
                for (barcode in barcodes) {
                    val bounds = barcode.boundingBox
                    val corners = barcode.cornerPoints

                    val rawValue = barcode.rawValue

                    if (rawValue!=null)
                        mListener.onBarcode(rawValue)
                }
                // [END get_barcodes]
                // [END_EXCLUDE]
            }
            .addOnFailureListener {
                // Task failed with an exception
                // ...
                Log.d("barcode", "null")
            }
        image.close()
    }

Detector.detectInImage входит в onSuccessListener, но не обнаруживается штрих-код: barcodes массив всегда пуст.

Может кто-нибудь помочь мне, пожалуйста?

1 Ответ

0 голосов
/ 11 февраля 2019

Вам необходимо передать данные всех трех плоскостей в функцию FirebaseVisionImage.fromByteBuffer ().Ваш код просто передает первый (Y-самолет).В формате YV12 используется один буфер (массив), который содержит Y-данные, за которыми следуют U-данные, а затем V-данные.

Изображение содержит 3 отдельных буфера для трех значений (Y, Uи V), однако для реального кадра нужны все три в одном буфере (массиве).Таким образом, вам нужно создать один буфер и скопировать в него содержимое трех плоскостей в правильном порядке в соответствии с форматом (YV12 или NV21) и передать этот буфер (массив).

См. эта статья в Википедии , а также этот SO вопрос / ответ, в котором содержится дополнительная информация о преобразовании и компоновке формата YV12 и NV21.Еще один хороший источник этих форматов - VideoLan wiki.

Функция может выглядеть следующим образом:

override fun onImageAvailable(reader: ImageReader) {
    val image = imageReader?.acquireLatestImage() ?: return
    val planes = image.planes
    if (planes.size >= 3) {
        val y = planes[0].buffer
        val u = planes[1].buffer
        val v = planes[2].buffer
        val ly = y.remaining()
        val lu = u.remaining()
        val lv = v.remaining()

        val dataYUV = ByteArray(ly + lu + lv)
        y.get(dataYUV, 0, ly)
        u.get(dataYUV, ly, lu)
        v.get(dataYUV, ly + lu, lv)

        val metadata = FirebaseVisionImageMetadata.Builder()
            .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_YV12)
            .setWidth(width)
            .setHeight(height)
            .setRotation(rotation)
            .build()

        detector.detectInImage(FirebaseVisionImage.fromByteArray(dataYUV, metadata))
    }
    image.close()
}

Где ширина, высота и поворот зависят от вашей камеры/ Предварительный просмотр и / или настройки считывателя изображений.

...