처리 응답 처리

처리 요청에 대한 응답에는 Document AI가 추출할 수 있었던 모든 구조화된 정보를 비롯해 처리된 문서에 대해 알려진 모든 정보를 담고 있는 Document 객체가 포함됩니다.

이 페이지에서는 샘플 문서를 제공한 다음 OCR 결과의 측면을 Document 객체 JSON의 특정 요소에 매핑하여 Document 객체의 레이아웃을 설명합니다. 클라이언트 라이브러리 코드 샘플과 Document AI Toolbox SDK 코드 샘플도 제공합니다. 이 코드 샘플은 온라인 처리를 사용하지만 Document 객체 파싱은 일괄 처리에서도 동일하게 작동합니다.

handle-response-1

주황색 및 파란색 사각형과 화살표는 연결된 객체의 필드 중 하나 이상이 각각 .layout 또는 detectedLanguage임을 나타냅니다. 다이어그램은 까마귀 발 표기법을 사용합니다.

요소를 펼치거나 접도록 특별히 설계된 JSON 뷰어 또는 편집 유틸리티를 사용합니다. 일반 텍스트 유틸리티에서 원시 JSON을 검토하는 것은 비효율적입니다.

텍스트, 레이아웃, 품질 점수

다음은 샘플 텍스트 문서입니다.

handle-response-2

다음은 Enterprise Document OCR 프로세서에서 반환된 전체 문서 객체입니다.

JSON 다운로드

OCR은 프로세서에서 실행되므로 이 OCR 출력은 항상 Document AI 프로세서 출력에 포함됩니다. 기존 OCR 데이터를 사용하므로 인라인 문서 옵션을 사용하여 Document AI 프로세서에 이러한 JSON 데이터를 입력할 수 있습니다.

  image=None, # all our samples pass this var
  mime_type="application/json",
  inline_document=document_response # pass OCR output to CDE input - undocumented

다음은 몇 가지 중요한 필드입니다.

원시 텍스트

text 필드에는 Document AI에서 인식한 텍스트가 포함됩니다. 이 텍스트에는 공백, 탭, 줄 바꿈을 제외한 레이아웃 구조가 포함되어 있지 않습니다. 문서의 텍스트 정보를 저장하고 문서 텍스트의 정보 소스 역할을 하는 유일한 필드입니다. 다른 필드는 위치 (startIndexendIndex)로 텍스트 필드의 일부를 참조할 수 있습니다.

  {
    text: "Sample Document\nHeading 1\nLorem ipsum dolor sit amet, ..."
  }

페이지 크기 및 언어

문서 객체의 각 page은 샘플 문서의 실제 페이지에 해당합니다. 샘플 JSON 출력에는 단일 PNG 이미지이므로 한 페이지가 포함됩니다.

  {
    "pages:" [
      {
        "pageNumber": 1,
        "dimension": {
          "width": 679.0,
          "height": 460.0,
          "unit": "pixels"
        },
      }
    ]
  }
{
  "pages": [
    {
      "detectedLanguages": [
        {
          "confidence": 0.98009938,
          "languageCode": "en"
        },
        {
          "confidence": 0.01990064,
          "languageCode": "und"
        }
      ]
    }
  ]
}

OCR 데이터

Document AI OCR은 텍스트 블록, 단락, 토큰, 기호 등 페이지의 다양한 세분성 또는 조직으로 텍스트를 감지합니다 (기호 수준 데이터를 출력하도록 구성된 경우 기호 수준은 선택사항임). 이러한 모든 항목은 페이지 객체의 멤버입니다.

모든 요소에는 위치와 텍스트를 설명하는 layout가 있습니다. 비텍스트 시각적 요소(예: 체크박스)도 페이지 수준에 있습니다.

{
  "pages": [
    {
      "paragraphs": [
        {
          "layout": {
            "textAnchor": {
              "textSegments": [
                {
                  "endIndex": "16"
                }
              ]
            },
            "confidence": 0.9939527,
            "boundingPoly": {
              "vertices": [ ... ],
              "normalizedVertices": [ ... ]
            },
            "orientation": "PAGE_UP"
          }
        }
      ]
    }
  ]
}

원시 텍스트는 startIndexendIndex로 기본 텍스트 문자열에 색인이 지정된 textAnchor 객체에서 참조됩니다.

  • boundingPoly의 경우 페이지의 왼쪽 상단이 원점 (0,0)입니다. 양수 X 값은 오른쪽, 양수 Y 값은 아래쪽입니다.

  • vertices 객체는 원본 이미지와 동일한 좌표를 사용하는 반면 normalizedVertices[0,1] 범위에 있습니다. 이미지의 기울기 보정 및 기타 정규화 속성을 나타내는 변환 행렬이 있습니다.

  • boundingPoly를 그리려면 한 꼭지점에서 다음 꼭지점까지 선분을 그립니다. 그런 다음 마지막 꼭짓점에서 첫 번째 꼭짓점으로 선분을 그려 다각형을 닫습니다. 레이아웃의 orientation 요소는 텍스트가 페이지를 기준으로 회전되었는지 여부를 나타냅니다.

문서의 구조를 시각화할 수 있도록 다음 이미지에서는 page.paragraphs, page.lines, page.tokens의 경계 다각형을 그립니다.

단락

handle-response-3

handle-response-4

토큰

handle-response-5

블록

handle-response-6

Enterprise Document OCR 프로세서는 가독성을 기반으로 문서의 품질을 평가할 수 있습니다.

이 품질 평가는 [0, 1]의 품질평가점수이며 1는 완벽한 품질을 의미합니다. 품질 점수는 Page.imageQualityScores 필드에 반환됩니다. 감지된 모든 결함은 quality/defect_*로 표시되고 신뢰도 값을 기준으로 내림차순으로 정렬됩니다.

다음은 너무 어둡고 흐려서 편안하게 읽을 수 없는 PDF입니다.

PDF 다운로드

다음은 Enterprise Document OCR 프로세서에서 반환하는 문서 품질 정보입니다.

  {
    "pages": [
      {
        "imageQualityScores": {
          "qualityScore": 0.7811847,
          "detectedDefects": [
            {
              "type": "quality/defect_document_cutoff",
              "confidence": 1.0
            },
            {
              "type": "quality/defect_glare",
              "confidence": 0.97849524
            },
            {
              "type": "quality/defect_text_cutoff",
              "confidence": 0.5
            }
          ]
        }
      }
    ]
  }

코드 샘플

다음 코드 샘플은 처리 요청을 전송한 다음 필드를 읽고 터미널에 출력하는 방법을 보여줍니다.

Java

자세한 내용은 Document AI Java API 참조 문서를 참고하세요.

Document AI에 인증하려면 애플리케이션 기본 사용자 인증 정보를 설정합니다. 자세한 내용은 로컬 개발 환경의 인증 설정을 참조하세요.


import com.google.cloud.documentai.v1beta3.Document;
import com.google.cloud.documentai.v1beta3.DocumentProcessorServiceClient;
import com.google.cloud.documentai.v1beta3.DocumentProcessorServiceSettings;
import com.google.cloud.documentai.v1beta3.ProcessRequest;
import com.google.cloud.documentai.v1beta3.ProcessResponse;
import com.google.cloud.documentai.v1beta3.RawDocument;
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

public class ProcessOcrDocument {
  public static void processOcrDocument()
      throws IOException, InterruptedException, ExecutionException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String location = "your-project-location"; // Format is "us" or "eu".
    String processerId = "your-processor-id";
    String filePath = "path/to/input/file.pdf";
    processOcrDocument(projectId, location, processerId, filePath);
  }

  public static void processOcrDocument(
      String projectId, String location, String processorId, String filePath)
      throws IOException, InterruptedException, ExecutionException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs
    // to be created
    // once, and can be reused for multiple requests. After completing all of your
    // requests, call
    // the "close" method on the client to safely clean up any remaining background
    // resources.
    String endpoint = String.format("%s-documentai.googleapis.com:443", location);
    DocumentProcessorServiceSettings settings =
        DocumentProcessorServiceSettings.newBuilder().setEndpoint(endpoint).build();
    try (DocumentProcessorServiceClient client = DocumentProcessorServiceClient.create(settings)) {
      // The full resource name of the processor, e.g.:
      // projects/project-id/locations/location/processor/processor-id
      // You must create new processors in the Cloud Console first
      String name =
          String.format("projects/%s/locations/%s/processors/%s", projectId, location, processorId);

      // Read the file.
      byte[] imageFileData = Files.readAllBytes(Paths.get(filePath));

      // Convert the image data to a Buffer and base64 encode it.
      ByteString content = ByteString.copyFrom(imageFileData);

      RawDocument document =
          RawDocument.newBuilder().setContent(content).setMimeType("application/pdf").build();

      // Configure the process request.
      ProcessRequest request =
          ProcessRequest.newBuilder().setName(name).setRawDocument(document).build();

      // Recognizes text entities in the PDF document
      ProcessResponse result = client.processDocument(request);
      Document documentResponse = result.getDocument();

      System.out.println("Document processing complete.");

      // Read the text recognition output from the processor
      // For a full list of Document object attributes,
      // please reference this page:
      // https://googleapis.dev/java/google-cloud-document-ai/latest/index.html

      // Get all of the document text as one big string
      String text = documentResponse.getText();
      System.out.printf("Full document text: '%s'\n", escapeNewlines(text));

      // Read the text recognition output from the processor
      List<Document.Page> pages = documentResponse.getPagesList();
      System.out.printf("There are %s page(s) in this document.\n", pages.size());

      for (Document.Page page : pages) {
        System.out.printf("Page %d:\n", page.getPageNumber());
        printPageDimensions(page.getDimension());
        printDetectedLanguages(page.getDetectedLanguagesList());
        printParagraphs(page.getParagraphsList(), text);
        printBlocks(page.getBlocksList(), text);
        printLines(page.getLinesList(), text);
        printTokens(page.getTokensList(), text);
      }
    }
  }

  private static void printPageDimensions(Document.Page.Dimension dimension) {
    String unit = dimension.getUnit();
    System.out.printf("    Width: %.1f %s\n", dimension.getWidth(), unit);
    System.out.printf("    Height: %.1f %s\n", dimension.getHeight(), unit);
  }

  private static void printDetectedLanguages(
      List<Document.Page.DetectedLanguage> detectedLangauges) {
    System.out.println("    Detected languages:");
    for (Document.Page.DetectedLanguage detectedLanguage : detectedLangauges) {
      String languageCode = detectedLanguage.getLanguageCode();
      float confidence = detectedLanguage.getConfidence();
      System.out.printf("        %s (%.2f%%)\n", languageCode, confidence * 100.0);
    }
  }

  private static void printParagraphs(List<Document.Page.Paragraph> paragraphs, String text) {
    System.out.printf("    %d paragraphs detected:\n", paragraphs.size());
    Document.Page.Paragraph firstParagraph = paragraphs.get(0);
    String