Einschränkung des Erkennungsbereichs in Google Vision, Texterkennung


11

Ich habe den ganzen Tag nach einer Lösung gesucht. Ich habe mehrere Threads zu meinem Problem ausgecheckt.

Aber es hat mir nicht viel geholfen. Grundsätzlich möchte ich, dass die Kameravorschau im Vollbildmodus angezeigt wird, Text jedoch nur in der Mitte des Bildschirms erkannt wird, in der ein Rechteck gezeichnet wird.

Technologien, die ich verwende:

  • Google Mobile Vision-APIs für die optische Zeichenerkennung (OCR)
  • Abhängigkeit: play-services-vision

Mein aktueller Status: Ich habe eine BoxDetector-Klasse erstellt:

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

Und hier eine Instanz dieser Klasse implementiert:

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

Bei der Ausführung wird diese Ausnahme ausgelöst:

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)

Wenn jemand eine Ahnung hat, was meine Schuld ist oder welche Alternativen es gibt, würde ich es wirklich schätzen. Vielen Dank!

Das möchte ich erreichen, ein Rect. Textbereichsscanner:

Was ich erreichen will

Antworten:


0

Google Vision Detection haben die Eingabe ist ein Frame. Ein Frame ist ein Bilddaten und enthält eine Breite und Höhe als zugehörige Daten. Sie können diesen Rahmen verarbeiten (auf einen kleineren zentrierten Rahmen zuschneiden), bevor Sie ihn an den Detektor übergeben. Dieser Vorgang muss schnell sein und sich auf die Bildverarbeitung der Kamera auswirken. Schauen Sie sich meinen Github unten an, suchen Sie nach FrameProcessingRunnable. Dort können Sie die Frame-Eingabe sehen. Sie können den Prozess dort selbst durchführen.

CameraSource


Hallo, zunächst einmal vielen Dank für die Antwort! Ich habe Ihren Code gesehen und mich gefragt, was ich an meinem Code ändern muss. Muss ich nur den Frame-Verarbeitungsteil hinzufügen? (Die 2 Privatklassen)?
Alan

Ja, Sie müssen Ihren Rahmen ändern, bevor Sie ihn an die letzte Operation von Detector übergeben können: mDetector.receiveFrame(outputFrame);
Thành Hà Văn

Können Sie Ihre Antwort mit dem Code bearbeiten, den ich hinzufügen muss, damit ich sie codieren und Ihnen das Kopfgeld geben kann?
Alan

0

In Google Vision können Sie die Koordinaten eines erkannten Textes abrufen, wie unter So ermitteln Sie die Position von Text in einem Bild mithilfe der Mobile Vision-API beschrieben.

Sie erhalten die TextBlocksvon TextRecognizer, dann filtern Sie die TextBlocknach ihren Koordinaten, die durch die Methode getBoundingBox()oder getCornerPoints()der TextBlocksKlasse bestimmt werden können:

TextRecognizer

Erkennungsergebnisse werden durch Erkennung (Frame) zurückgegeben. Der OCR-Algorithmus versucht, auf das Textlayout zu schließen, und organisiert jeden Absatz in TextBlock-Instanzen. Wenn Text erkannt wird, wird mindestens eine TextBlock-Instanz zurückgegeben.

[..]

Öffentliche Methoden

public SparseArray<TextBlock> detect (Frame frame)Erkennt und erkennt Text in einem Bild. Unterstützt derzeit nur Bitmap und NV21. Gibt die Zuordnung von int zu TextBlock zurück, wobei die int-Domäne eine undurchsichtige ID für den Textblock darstellt.

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

Textblock

public class TextBlock extends Object implements Text

Ein Textblock (stellen Sie sich einen Absatz vor), wie er von der OCR-Engine angenommen wird.

Zusammenfassung der öffentlichen Methoden

Rect getBoundingBox() Gibt den achsenausgerichteten Begrenzungsrahmen des TextBlocks zurück.

List<? extends Text> getComponents() Kleinere Komponenten, aus denen diese Entität besteht, falls vorhanden.

Point[] getCornerPoints() 4 Eckpunkte im Uhrzeigersinn beginnend oben links.

String getLanguage() Vorherrschende Sprache im TextBlock.

String getValue() Rufen Sie den erkannten Text als Zeichenfolge ab.

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

Sie verfahren also im Wesentlichen wie unter So ermitteln Sie die Position von Text in einem Bild mithilfe der Mobile Vision-API. Sie teilen jedoch keinen Block in Zeilen und dann keine Zeile in Wörter wie

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


                    }

                }
            }

Stattdessen erhalten Sie das Begrenzungsfeld aller Textblöcke und wählen dann das Begrenzungsfeld mit den Koordinaten aus, die der Mitte des Bildschirms / Rahmens oder dem von Ihnen angegebenen Rechteck am nächsten liegen (dh wie kann ich die Mitte x, y meiner Ansicht in Android erhalten? ). Hierfür verwenden Sie die Methode getBoundingBox()oder getCornerPoints()von TextBlocks...


Ich werde es morgen testen, danke
Alan

Ich habe es versucht, aber ich wusste nicht, wie ich es richtig implementieren sollte
Alan
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.