Limitazione dell'area di rilevamento in Google Vision, riconoscimento del testo


11

Ho cercato una soluzione per tutto il giorno. Ho controllato diversi thread per quanto riguarda il mio problema.

Ma non mi ha aiutato molto. Fondamentalmente voglio che l'anteprima della fotocamera sia a schermo intero, ma il testo viene riconosciuto solo al centro dello schermo, dove viene disegnato un rettangolo.

Tecnologie che sto usando:

  • API di Google Mobile Vision per il riconoscimento ottico dei caratteri (OCR)
  • dependecy: play-services-vision

Il mio stato attuale: ho creato una classe 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 implementato un'istanza di questa classe qui:

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

All'esecuzione viene generata questa eccezione:

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)

Se qualcuno ha un indizio, qual è la mia colpa o ha delle alternative, lo apprezzerei davvero. Grazie!

Questo è ciò che voglio ottenere, un Rect. Scanner dell'area di testo:

Quello che voglio ottenere

Risposte:


0

Il rilevamento della visione di Google ha l'input è un frame. Una cornice è un dato di immagine e contiene una larghezza e un'altezza come dati associati. È possibile elaborare questa cornice (tagliarla su una cornice centrale più piccola) prima di passarla al rivelatore. Questo processo deve essere rapido e seguire l'immagine di elaborazione della videocamera. Dai un'occhiata al mio Github qui sotto, cerca FrameProcessingRunnable. U può vedere l'input del frame lì. puoi fare il processo da solo lì.

CameraSource


Ciao, prima di tutto grazie per aver risposto! Ho visto il tuo codice e mi chiedevo, cosa devo cambiare nel mio codice? L'unica cosa che devo aggiungere è la parte di elaborazione Frame? (Le 2 lezioni private)?
Alan

Sì, devi modificare il frame prima di passare all'ultima operazione di Detector: mDetector.receiveFrame(outputFrame);
Thành Hà Văn

Puoi modificare la tua risposta con il codice che devo aggiungere, in modo da poterlo codificare e premiarti con la ricompensa?
Alan

0

In google-vision puoi ottenere le coordinate di un testo rilevato come descritto in Come ottenere la posizione del testo in un'immagine usando l'API Mobile Vision?

Si ottiene il TextBlocksda TextRecognizer, quindi si filtra il TextBlockper le loro coordinate, che possono essere determinate dal metodo getBoundingBox()o getCornerPoints()della TextBlocksclasse:

TextRecognizer

I risultati del riconoscimento vengono restituiti da detect (Frame). L'algoritmo OCR tenta di inferire il layout del testo e organizza ogni paragrafo in istanze TextBlock. Se viene rilevato del testo, verrà restituita almeno un'istanza di TextBlock.

[..]

Metodi pubblici

public SparseArray<TextBlock> detect (Frame frame)Rileva e riconosce il testo in un'immagine. Supporta solo bitmap e NV21 per ora. Restituisce il mapping di int su TextBlock, dove il dominio int rappresenta un ID opaco per il blocco di testo.

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

TextBlock

public class TextBlock extends Object implements Text

Un blocco di testo (pensalo come un paragrafo) come ritenuto dal motore OCR.

Riepilogo metodo pubblico

Rect getBoundingBox() Restituisce il rettangolo di selezione allineato all'asse di TextBlock.

List<? extends Text> getComponents() Componenti più piccoli che compongono questa entità, se presenti.

Point[] getCornerPoints() 4 punti d'angolo in senso orario a partire da in alto a sinistra.

String getLanguage() Lingua prevalente in TextBlock.

String getValue() Recupera il testo riconosciuto come stringa.

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

Quindi sostanzialmente procedete come in Come ottenere la posizione del testo in un'immagine usando l'API Mobile Vision? tuttavia non dividi nessun blocco in righe e quindi nessuna riga in parole come

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


                    }

                }
            }

invece ottieni la casella di delimitazione di tutti i blocchi di testo e quindi seleziona la casella di delimitazione con le coordinate più vicine al centro dello schermo / cornice o al rettangolo specificato (ad esempio, come posso ottenere il centro x, y della mia vista in Android? ). Per questo usi il metodo getBoundingBox()o getCornerPoints()di TextBlocks...


Lo proverò domani grazie
Alan il

L'ho provato ma non sapevo come implementarlo correttamente
Alan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.