Limitando a área de detecção no Google Vision, reconhecimento de texto

11

Estive procurando o dia inteiro por uma solução. Eu verifiquei vários tópicos em relação ao meu problema.

Mas isso não me ajudou muito. Basicamente, quero que a visualização da câmera seja de tela cheia, mas o texto seja reconhecido apenas no centro da tela, onde um retângulo é desenhado.

Tecnologias que estou usando:

  • APIs do Google Mobile Vision para reconhecimento óptico de caracteres (OCR)
  • Dependecy: play-services-vision

Meu estado atual: criei uma 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 implementou uma instância desta classe aqui:

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

Na execução, essa exceção é lançada:

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 alguém tem uma pista, qual é minha culpa ou tem alguma alternativa, eu realmente aprecio isso. Obrigado!

É isso que eu quero alcançar, um Rect. Scanner de área de texto:

O que eu quero alcançar

Alan
fonte

Respostas:

0

Detecção de visão do Google tem a entrada é um quadro. Um quadro é um dado de imagem e contém largura e altura como dados associados. Você pode processar esse quadro (corte-o em um quadro centralizado menor) antes de passá-lo ao detector. Esse processo deve ser rápido e ocorrer ao longo do processamento da imagem da câmera. Confira meu Github abaixo, procure por FrameProcessingRunnable. Você pode ver a entrada de quadro lá. você pode fazer o processo sozinho.

CameraSource

Thành Hà Văn
fonte
Olá, antes de tudo, obrigado por responder! Eu vi seu código e me perguntei: o que tenho que mudar no meu código? A única coisa que tenho a acrescentar é a parte de processamento de quadros? (As 2 aulas particulares)?
Alan
Sim, você tem que modificar seu quadro antes de passá-lo para a última operação do Detector: mDetector.receiveFrame(outputFrame);
Thành Hà Văn
Você pode editar sua resposta com o código que preciso adicionar, para que eu possa codificá-la e conceder a você a recompensa?
Alan
0

No google-vision, você pode obter as coordenadas de um texto detectado, como descrito em Como obter a posição do texto em uma imagem usando a API do Mobile Vision?

Você obtém o TextBlocksfrom e TextRecognizer, em seguida, filtra o TextBlockpor suas coordenadas, que podem ser determinadas pelo método getBoundingBox()ou getCornerPoints()da TextBlocksclasse:

TextRecognizer

Os resultados do reconhecimento são retornados por detect (Frame). O algoritmo OCR tenta inferir o layout do texto e organiza cada parágrafo em instâncias do TextBlock. Se algum texto for detectado, pelo menos uma instância do TextBlock será retornada.

[..]

Métodos públicos

public SparseArray<TextBlock> detect (Frame frame)Detecta e reconhece o texto em uma imagem. Por enquanto, apenas suporta bitmap e NV21. Retorna o mapeamento de int para TextBlock, onde o domínio int representa um ID opaco para o bloco de texto.

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

TextBlock

public class TextBlock extends Object implements Text

Um bloco de texto (pense nele como um parágrafo), considerado pelo mecanismo de OCR.

Resumo do Método Público

Rect getBoundingBox() Retorna a caixa delimitadora alinhada ao eixo do TextBlock.

List<? extends Text> getComponents() Componentes menores que compõem esta entidade, se houver.

Point[] getCornerPoints() 4 pontos de canto no sentido horário, começando com o canto superior esquerdo.

String getLanguage() Idioma predominante no TextBlock.

String getValue() Recupere o texto reconhecido como uma sequência.

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

Então você basicamente prossegue como em Como obter a posição do texto em uma imagem usando a API do Mobile Vision? no entanto, você não divide nenhum bloco em linhas e, em seguida, qualquer linha em palavras 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));


                    }

                }
            }

em vez disso, você obtém a caixa de limite de todos os blocos de texto e, em seguida, seleciona a caixa de limite com as coordenadas mais próximas do centro da tela / quadro ou o retângulo especificado (por exemplo, como posso obter o centro x, y da minha visão no android? ) Para isso, você usa o método getBoundingBox()ou getCornerPoints()de TextBlocks...

ralf htp
fonte
Vou testá-lo amanhã, obrigado
Alan
Eu tentei, mas não sabia como implementá-lo corretamente
Alan