Limitación del área de detección en Google Vision, reconocimiento de texto

11

He estado buscando todo el día una solución. He revisado varios hilos con respecto a mi problema.

Pero no me ayudó mucho. Básicamente, quiero que la Vista previa de la cámara sea de pantalla completa, pero el texto solo se reconoce en el centro de la pantalla, donde se dibuja un Rectángulo.

Tecnologías que estoy usando:

  • API de Google Mobile Vision para reconocimiento óptico de caracteres (OCR)
  • Dependencia: play-services-vision

Mi estado actual: creé una clase BoxDetector:

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

    @Override
    public void receiveFrame(Frame frame) {
        mDelegate.receiveFrame(frame);
    }
}

E implementó una instancia de esta clase aquí:

   final TextRecognizer textRecognizer = new TextRecognizer.Builder(App.getContext()).build();

    // Instantiate the created box detector in order to limit the Text Detector scan area
    BoxDetector boxDetector = new BoxDetector(textRecognizer, width, height);

    //Set the TextRecognizer's Processor but using the box collider

    boxDetector.setProcessor(new Detector.Processor<TextBlock>() {
        @Override
        public void release() {
        }

        /*
            Detect all the text from camera using TextBlock
            and the values into a stringBuilder which will then be set to the textView.
        */
        @Override
        public void receiveDetections(Detector.Detections<TextBlock> detections) {
            final SparseArray<TextBlock> items = detections.getDetectedItems();
            if (items.size() != 0) {

                mTextView.post(new Runnable() {
                    @Override
                    public void run() {
                        StringBuilder stringBuilder = new StringBuilder();
                        for (int i = 0; i < items.size(); i++) {
                            TextBlock item = items.valueAt(i);
                            stringBuilder.append(item.getValue());
                            stringBuilder.append("\n");
                        }
                        mTextView.setText(stringBuilder.toString());
                    }
                });
            }
        }
    });


        mCameraSource = new CameraSource.Builder(App.getContext(), boxDetector)
                .setFacing(CameraSource.CAMERA_FACING_BACK)
                .setRequestedPreviewSize(height, width)
                .setAutoFocusEnabled(true)
                .setRequestedFps(15.0f)
                .build();

En la ejecución se lanza esta excepción:

Exception thrown from receiver.
java.lang.IllegalStateException: Detector processor must first be set with setProcessor in order to receive detection results.
    at com.google.android.gms.vision.Detector.receiveFrame(com.google.android.gms:play-services-vision-common@@19.0.0:17)
    at com.spectures.shopendings.Helpers.BoxDetector.receiveFrame(BoxDetector.java:62)
    at com.google.android.gms.vision.CameraSource$zzb.run(com.google.android.gms:play-services-vision-common@@19.0.0:47)
    at java.lang.Thread.run(Thread.java:919)

Si alguien tiene una pista, cuál es mi culpa o tiene alguna alternativa, realmente lo agradecería. ¡Gracias!

Esto es lo que quiero lograr, un Rect. Escáner de área de texto:

Lo que quiero lograr

Alan
fuente

Respuestas:

0

La detección de visión de Google tiene la entrada es un marco. Un marco es un dato de imagen y contiene un ancho y un alto como datos asociados. U puede procesar este cuadro (cortarlo en un cuadro centrado más pequeño) antes de pasarlo al detector. Este proceso debe ser rápido y hacerlo junto con el procesamiento de imágenes de la cámara. Echa un vistazo a mi Github a continuación, Buscar FrameProcessingRunnable. U puede ver la entrada del cuadro allí. Puedes hacer el proceso tú mismo allí.

CameraSource

Thành Hà Văn
fuente
Hola, en primer lugar gracias por responder! Vi su código y me pregunté, ¿qué debo cambiar en mi código? ¿Es lo único que tengo que agregar es la parte de procesamiento de marcos? (Las 2 clases privadas)?
Alan
Sí, debe modificar su marco antes de pasarlo a la última operación del Detector: mDetector.receiveFrame(outputFrame);
Thành Hà Văn
¿Puedes editar tu respuesta con el código que necesito agregar, para que pueda codificarlo y otorgarle la recompensa?
Alan
0

En google-vision puede obtener las coordenadas de un texto detectado como se describe en ¿Cómo obtener la posición del texto en una imagen usando la API de Mobile Vision?

Obtiene el TextBlocksde TextRecognizer, luego filtra el TextBlockpor sus coordenadas, que se pueden determinar por el método getBoundingBox()o getCornerPoints()de TextBlocksclase:

TextRecognizer

Los resultados del reconocimiento son devueltos por detect (Frame). El algoritmo OCR intenta inferir el diseño del texto y organiza cada párrafo en instancias de TextBlock. Si se detecta algún texto, se devolverá al menos una instancia de TextBlock.

[..]

Métodos públicos

public SparseArray<TextBlock> detect (Frame frame)Detecta y reconoce texto en una imagen. Solo es compatible con mapas de bits y NV21 por ahora. Devuelve la asignación de int a TextBlock, donde el dominio int representa una ID opaca para el bloque de texto.

fuente: https://developers.google.com/android/reference/com/google/android/gms/vision/text/TextRecognizer

Bloque de texto

public class TextBlock extends Object implements Text

Un bloque de texto (piense en él como un párrafo) según lo considere el motor de OCR.

Resumen de método público

Rect getBoundingBox() Devuelve el cuadro delimitador alineado con el eje de TextBlock.

List<? extends Text> getComponents() Componentes más pequeños que comprenden esta entidad, si hay alguno.

Point[] getCornerPoints() 4 puntos de esquina en sentido horario comenzando con la esquina superior izquierda.

String getLanguage() Idioma predominante en TextBlock.

String getValue() Recupere el texto reconocido como una cadena.

fuente: https://developers.google.com/android/reference/com/google/android/gms/vision/text/TextBlock

¿Entonces básicamente procedes como en Cómo obtener la posición del texto en una imagen usando la API de Mobile Vision? sin embargo, no divide ningún bloque en líneas y luego ninguna línea en palabras como

//Loop through each `Block`
            foreach (TextBlock textBlock in blocks)
            {
                IList<IText> textLines = textBlock.Components; 

                //loop Through each `Line`
                foreach (IText currentLine in textLines)
                {
                    IList<IText>  words = currentLine.Components;

                    //Loop through each `Word`
                    foreach (IText currentword in words)
                    {
                        //Get the Rectangle/boundingBox of the word
                        RectF rect = new RectF(currentword.BoundingBox);
                        rectPaint.Color = Color.Black;

                        //Finally Draw Rectangle/boundingBox around word
                        canvas.DrawRect(rect, rectPaint);

                        //Set image to the `View`
                        imgView.SetImageDrawable(new BitmapDrawable(Resources, tempBitmap));


                    }

                }
            }

en su lugar, obtiene el cuadro de límite de todos los bloques de texto y luego selecciona el cuadro de límite con las coordenadas más cercanas al centro de la pantalla / marco o el rectángulo que especifique (es decir, ¿cómo puedo obtener el centro x, y de mi vista en Android? ) Para esto, utiliza el método getBoundingBox()o ...getCornerPoints()TextBlocks

ralf htp
fuente
Lo probaré mañana gracias
Alan
Lo intenté pero no sabía cómo implementarlo correctamente
Alan