Ograniczanie obszaru wykrywania w Google Vision, rozpoznawanie tekstu

11

Cały dzień szukałem rozwiązania. Sprawdziłem kilka wątków dotyczących mojego problemu.

Ale niewiele mi to pomogło. Zasadniczo chcę, aby podgląd kamery był pełnoekranowy, ale tekst jest rozpoznawany tylko na środku ekranu, na którym rysowany jest prostokąt.

Technologie, których używam:

  • Interfejsy API Google Mobile Vision do optycznego rozpoznawania znaków (OCR)
  • Dependecy: play-services-vision

Mój obecny stan: utworzyłem klasę 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);
    }
}

I zaimplementowałem tutaj wystąpienie tej klasy:

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

Podczas wykonywania generowany jest ten wyjątek:

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)

Jeśli ktoś ma jakiś pomysł, jaka jest moja wina lub ma jakieś alternatywy, byłbym bardzo wdzięczny. Dziękuję Ci!

To właśnie chcę osiągnąć, Rect. Skaner obszaru tekstowego:

Co chcę osiągnąć

Alan
źródło

Odpowiedzi:

0

Wykrywanie wizji Google ma wejście jest ramką. Ramka jest danymi obrazu i zawiera powiązane z nią szerokość i wysokość. U może przetworzyć tę ramkę (przyciąć ją do mniejszej wyśrodkowanej ramki) przed przekazaniem jej do detektora. Ten proces musi być szybki i przebiegać równolegle z przetwarzaniem obrazu z kamery. Sprawdź mój Github poniżej, Wyszukaj FrameProcessingRunnable. U widzi tam wejście ramki. możesz sam zrobić tam proces.

CameraSource

Thành Hà Văn
źródło
Witaj, przede wszystkim dzięki za odpowiedź! Widziałem twój kod i zastanawiałem się, co muszę zmienić w kodzie? Czy jedyne, co muszę dodać, to część przetwarzająca ramkę? (2 prywatne lekcje)?
Alan
Tak, musisz zmodyfikować ramkę, zanim prześlesz ją do ostatniej operacji Detektora: mDetector.receiveFrame(outputFrame);
Thành Hà Văn
Czy możesz edytować swoją odpowiedź za pomocą kodu, który muszę dodać, abym mógł ją kodować i przyznać nagrodę?
Alan
0

W google-vision możesz uzyskać współrzędne wykrytego tekstu, jak opisano w Jak uzyskać pozycję tekstu na obrazie za pomocą Mobile Vision API?

Otrzymujesz TextBlocksod TextRecognizer, a następnie filtrujesz TextBlockwedług ich współrzędnych, które można określić za pomocą metody getBoundingBox()lub klasy:getCornerPoints()TextBlocks

TextRecognizer

Wyniki rozpoznawania są zwracane przez wykrywanie (ramka). Algorytm OCR próbuje wywnioskować układ tekstu i organizuje każdy akapit w instancje TextBlock. W przypadku wykrycia dowolnego tekstu zostanie zwrócona co najmniej jedna instancja TextBlock.

[..]

Metody publiczne

public SparseArray<TextBlock> detect (Frame frame)Wykrywa i rozpoznaje tekst na obrazie. Na razie obsługuje tylko bitmapę i NV21. Zwraca odwzorowanie int na TextBlock, gdzie domena int reprezentuje nieprzezroczysty identyfikator bloku tekstowego.

źródło: https://developers.google.com/android/reference/com/google/android/gms/vision/text/TextRecognizer

TextBlock

public class TextBlock extends Object implements Text

Blok tekstu (potraktuj to jako akapit) zgodnie z zasadą silnika OCR.

Podsumowanie metod publicznych

Rect getBoundingBox() Zwraca wyrównaną do osi obwiednię TextBlock.

List<? extends Text> getComponents() Mniejsze komponenty, które składają się na ten byt, jeśli występują.

Point[] getCornerPoints() 4 punkty narożne w kierunku zgodnym z ruchem wskazówek zegara, zaczynając od lewego górnego rogu.

String getLanguage() Przeważający język w TextBlock.

String getValue() Pobierz rozpoznany tekst jako ciąg.

źródło : https://developers.google.com/android/reference/com/google/android/gms/vision/text/TextBlock

Więc zasadniczo postępujesz jak w Jak uzyskać pozycję tekstu na obrazie za pomocą Mobile Vision API? jednak nie dzielisz żadnego bloku na wiersze, a następnie żadnych wierszy na słowa takie jak

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


                    }

                }
            }

zamiast tego dostajesz obwiednię wszystkich bloków tekstowych, a następnie wybierasz obwiednię ze współrzędnymi najbliższymi środka ekranu / ramki lub prostokąta, który określasz (tj. Jak mogę uzyskać środek x, y mojego widoku w Androidzie? ). W tym celu używasz metody getBoundingBox()lub ...getCornerPoints()TextBlocks

ralf htp
źródło
Przetestuję to jutro dzięki
Alan
Próbowałem, ale nie wiedziałem, jak poprawnie go wdrożyć
Alan