콘솔로 이동

Android에서 ML Kit를 통한 이미지 속 텍스트 인식

ML Kit를 사용하여 이미지 속 텍스트를 인식할 수 있습니다. ML Kit에는 거리 표지판 텍스트와 같은 이미지 속 텍스트 인식에 적합한 범용 API와 문서의 텍스트 인식에 최적화된 범용 API가 모두 있습니다. 범용 API에는 기기별 및 클라우드 기반 모델이 모두 있습니다. 문서 텍스트 인식은 클라우드 기반 모델에서만 사용할 수 있습니다. 클라우드 및 기기별 모델 비교에 대한 개요를 참조하세요.

GitHub의 ML Kit 빠른 시작 샘플에서 이 API의 사용 예를 참조하거나 Codelab을 사용해 보세요.

시작하기 전에

  1. 아직 추가하지 않았다면 Android 프로젝트에 Firebase를 추가합니다.
  2. 프로젝트 수준 build.gradle 파일의 buildscriptallprojects 섹션에 Google의 Maven 저장소가 포함되어야 합니다.
  3. 모듈(앱 수준) Gradle 파일(일반적으로 app/build.gradle)에 ML Kit Android 라이브러리의 종속 항목을 추가합니다.
    dependencies {
      // ...
    
      implementation 'com.google.firebase:firebase-ml-vision:20.0.0'
    }
    
  4. 선택사항이지만 권장함: 기기별 API를 사용하는 경우 Play 스토어에서 앱 설치 후 기기에 머신러닝 모델을 자동으로 다운로드하도록 앱을 설정합니다.

    이를 위해 다음 선언을 앱의 AndroidManifest.xml 파일에 추가합니다.

    <application ...>
      ...
      <meta-data
          android:name="com.google.firebase.ml.vision.DEPENDENCIES"
          android:value="ocr" />
      <!-- To use multiple models: android:value="ocr,model2,model3" -->
    </application>
    
    설치 시간 모델 다운로드를 사용 설정하지 않으면 기기별 감지를 처음 실행할 때 모델이 다운로드됩니다. 다운로드가 완료되기 전에 요청하면 결과가 산출되지 않습니다.
  5. Cloud 기반 모델을 사용하려는 경우 프로젝트에 대해 Cloud 기반 API를 아직 사용 설정하지 않았으면 다음 안내에 따라 지금 수행하세요.

    1. Firebase 콘솔의 ML Kit API 페이지를 엽니다.
    2. 프로젝트를 Blaze 요금제로 아직 업그레이드하지 않은 경우 업그레이드를 클릭하여 업그레이드하세요. 프로젝트가 Blaze 요금제가 아닌 경우에만 업그레이드하라는 메시지가 표시됩니다.

      Blaze 수준 프로젝트만 Cloud 기반 API를 사용할 수 있습니다.

    3. Cloud 기반 API가 아직 사용 설정되지 않은 경우 Cloud 기반 API 사용 설정을 클릭합니다.

    기기별 모델만 사용하려는 경우 이 단계를 건너뛸 수 있습니다.

이제 이미지 속 텍스트 인식을 시작할 수 있습니다.

입력 이미지 가이드라인

  • ML Kit가 텍스트를 정확하게 인식하려면 입력 이미지에 충분한 픽셀 데이터로 표시된 텍스트가 있어야 합니다. 라틴어 텍스트의 경우 각 문자가 16x16픽셀 이상이어야 좋습니다. Cloud 기반 API에서만 지원되는 한국어, 일본어, 중국어 텍스트의 경우 각 문자가 24x24픽셀이어야 합니다. 일반적으로 모든 언어의 문자가 24x24픽셀보다 크면 정확도가 저하됩니다.

    따라서 예를 들어 640x480픽셀 이미지는 이미지의 전체 너비를 차지하는 명함을 스캔하는 데 적합합니다. 레터 사이즈 용지에 인쇄된 문서를 스캔하려면 720x1280픽셀 이미지가 필요할 수도 있습니다.

  • 이미지 초점이 잘 맞지 않으면 텍스트 인식 정확도가 저하될 수 있습니다. 허용 가능한 수준의 결과를 얻지 못하는 경우 사용자에게 이미지를 다시 캡처하도록 요청합니다.

  • 실시간 애플리케이션에서 텍스트를 인식하는 경우 입력 이미지의 전체 크기를 고려해야 할 수도 있습니다. 이미지 크기가 작을수록 더 빠르게 처리될 수 있으므로 지연 시간을 줄이려면 위의 정확도 요구사항에 유의하여 낮은 해상도에서 이미지를 캡처하고 텍스트가 가능한 많은 이미지를 차지하도록 합니다. 또한 실시간 성능 향상을 위한 팁도 참조하세요.


이미지의 텍스트 인식

기기별 모델 또는 클라우드 기반 모델을 사용하여 이미지 속 텍스트를 인식하려면 아래에 설명된 대로 텍스트 인식기를 실행합니다.

1. 텍스트 인식기 실행

이미지의 텍스트를 인식하려면 FirebaseVisionImage 객체를 Bitmap, media.Image, ByteBuffer, 바이트 배열이나 기기의 파일에서 만듭니다. 그런 다음 FirebaseVisionImage 객체를 FirebaseVisionTextRecognizerprocessImage 메소드에 전달합니다.

  1. 이미지에서 FirebaseVisionImage 객체를 만듭니다.

    • Bitmap 객체에서 FirebaseVisionImage 객체를 만드는 방법은 다음과 같습니다.

      자바

      FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);

      Kotlin

      val image = FirebaseVisionImage.fromBitmap(bitmap)
      Bitmap 객체로 표현된 이미지는 추가 회전이 필요 없는 수직 상태여야 합니다.
    • 기기 카메라에서 이미지를 캡처할 때와 같이 FirebaseVisionImage 객체를 media.Image 객체에서 만들려면 먼저 기기의 카메라 센서 방향 및 기기 회전을 보정하기 위해 이미지 회전 각도를 결정합니다.

      자바

      private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
      static {
          ORIENTATIONS.append(Surface.ROTATION_0, 90);
          ORIENTATIONS.append(Surface.ROTATION_90, 0);
          ORIENTATIONS.append(Surface.ROTATION_180, 270);
          ORIENTATIONS.append(Surface.ROTATION_270, 180);
      }
      
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      private int getRotationCompensation(String cameraId, Activity activity, Context context)
              throws CameraAccessException {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
          int rotationCompensation = ORIENTATIONS.get(deviceRotation);
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
          int sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION);
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360;
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          int result;
          switch (rotationCompensation) {
              case 0:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  break;
              case 90:
                  result = FirebaseVisionImageMetadata.ROTATION_90;
                  break;
              case 180:
                  result = FirebaseVisionImageMetadata.ROTATION_180;
                  break;
              case 270:
                  result = FirebaseVisionImageMetadata.ROTATION_270;
                  break;
              default:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  Log.e(TAG, "Bad rotation value: " + rotationCompensation);
          }
          return result;
      }

      Kotlin

      private val ORIENTATIONS = SparseIntArray()
      
      init {
          ORIENTATIONS.append(Surface.ROTATION_0, 90)
          ORIENTATIONS.append(Surface.ROTATION_90, 0)
          ORIENTATIONS.append(Surface.ROTATION_180, 270)
          ORIENTATIONS.append(Surface.ROTATION_270, 180)
      }/**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      @Throws(CameraAccessException::class)
      private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          val deviceRotation = activity.windowManager.defaultDisplay.rotation
          var rotationCompensation = ORIENTATIONS.get(deviceRotation)
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager
          val sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION)!!
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          val result: Int
          when (rotationCompensation) {
              0 -> result = FirebaseVisionImageMetadata.ROTATION_0
              90 -> result = FirebaseVisionImageMetadata.ROTATION_90
              180 -> result = FirebaseVisionImageMetadata.ROTATION_180
              270 -> result = FirebaseVisionImageMetadata.ROTATION_270
              else -> {
                  result = FirebaseVisionImageMetadata.ROTATION_0
                  Log.e(TAG, "Bad rotation value: $rotationCompensation")
              }
          }
          return result
      }

      그런 다음 media.Image 객체 및 회전 값을 FirebaseVisionImage.fromMediaImage()에 전달합니다.

      자바

      FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);

      Kotlin

      val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
    • ByteBuffer 또는 바이트 배열에서 FirebaseVisionImage 객체를 만들려면 먼저 위에서 설명한 대로 이미지 회전을 계산합니다.

      그런 다음 이미지의 높이, 너비, 색상 인코딩 형식, 방향이 포함된 FirebaseVisionImageMetadata 객체를 만듭니다.

      자바

      FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
              .setWidth(480)   // 480x360 is typically sufficient for
              .setHeight(360)  // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build();

      Kotlin

      val metadata = FirebaseVisionImageMetadata.Builder()
              .setWidth(480) // 480x360 is typically sufficient for
              .setHeight(360) // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build()

      버퍼나 배열, 메타데이터 객체를 사용하여 FirebaseVisionImage 객체를 만듭니다.

      자바

      FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);// Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);

      Kotlin

      val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata)// Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
    • 파일에서 FirebaseVisionImage 객체를 만들려면 앱 컨텍스트 및 파일 URI를 FirebaseVisionImage.fromFilePath()에 전달합니다.

      자바

      FirebaseVisionImage image;
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri);
      } catch (IOException e) {
          e.printStackTrace();
      }

      Kotlin

      val image: FirebaseVisionImage
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri)
      } catch (e: IOException) {
          e.printStackTrace()
      }

  2. FirebaseVisionTextRecognizer 인스턴스를 가져옵니다.

    기기별 모델을 사용하는 방법은 다음과 같습니다.

    자바

    FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance()
            .getOnDeviceTextRecognizer();

    Kotlin

    val detector = FirebaseVision.getInstance()
            .onDeviceTextRecognizer

    클라우드 기반 모델을 사용하는 방법은 다음과 같습니다.

    자바

    FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance()
            .getCloudTextRecognizer();
    // Or, to change the default settings:
    //   FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance()
    //          .getCloudTextRecognizer(options);
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    FirebaseVisionCloudTextRecognizerOptions options = new FirebaseVisionCloudTextRecognizerOptions.Builder()
            .setLanguageHints(Arrays.asList("en", "hi"))
            .build();
    

    Kotlin

    val detector = FirebaseVision.getInstance().cloudTextRecognizer
    // Or, to change the default settings:
    // val detector = FirebaseVision.getInstance().getCloudTextRecognizer(options)
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    val options = FirebaseVisionCloudTextRecognizerOptions.Builder()
            .setLanguageHints(Arrays.asList("en", "hi"))
            .build()
    
  3. 마지막으로 이미지를 processImage 메소드에 전달합니다.

    자바

    Task<FirebaseVisionText> result =
            detector.processImage(image)
                    .addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
                        @Override
                        public void onSuccess(FirebaseVisionText firebaseVisionText) {
                            // Task completed successfully
                            // ...
                        }
                    })
                    .addOnFailureListener(
                            new OnFailureListener() {
                                @Override
                                public void onFailure(@NonNull Exception e) {
                                    // Task failed with an exception
                                    // ...
                                }
                            });

    Kotlin

    val result = detector.processImage(image)
            .addOnSuccessListener { firebaseVisionText ->
                // Task completed successfully
                // ...
            }
            .addOnFailureListener {
                // Task failed with an exception
                // ...
            }

2. 인식된 텍스트 블록에서 텍스트 추출

텍스트 인식 작업이 성공하면 FirebaseVisionText 객체가 성공 리스너에 전달됩니다. FirebaseVisionText 객체는 이미지에서 인식된 전체 텍스트 및 0개 이상의 TextBlock 객체를 포함합니다.

TextBlockLine 객체를 0개 이상 포함하는 사각형 모양의 텍스트 블록을 나타냅니다. 각 Line 객체는 단어 및 단어와 유사한 항목(날짜, 숫자 등)을 나타내는 Element 객체를 0개 이상 포함합니다.

TextBlock, Line, Element 객체에 대해 해당 영역에서 인식된 텍스트와 영역의 경계 좌표를 가져올 수 있습니다.

예:

자바

String resultText = result.getText();
for (FirebaseVisionText.TextBlock block: result.getTextBlocks()) {
    String blockText = block.getText();
    Float blockConfidence = block.getConfidence();
    List<RecognizedLanguage> blockLanguages = block.getRecognizedLanguages();
    Point[] blockCornerPoints = block.getCornerPoints();
    Rect blockFrame = block.getBoundingBox();
    for (FirebaseVisionText.Line line: block.getLines()) {
        String lineText = line.getText();
        Float lineConfidence = line.getConfidence();
        List<RecognizedLanguage> lineLanguages = line.getRecognizedLanguages();
        Point[] lineCornerPoints = line.getCornerPoints();
        Rect lineFrame = line.getBoundingBox();
        for (FirebaseVisionText.Element element: line.getElements()) {
            String elementText = element.getText();
            Float elementConfidence = element.getConfidence();
            List<RecognizedLanguage> elementLanguages = element.getRecognizedLanguages();
            Point[] elementCornerPoints = element.getCornerPoints();
            Rect elementFrame = element.getBoundingBox();
        }
    }
}

Kotlin

val resultText = result.text
for (block in result.textBlocks) {
    val blockText = block.text
    val blockConfidence = block.confidence
    val blockLanguages = block.recognizedLanguages
    val blockCornerPoints = block.cornerPoints
    val blockFrame = block.boundingBox
    for (line in block.lines) {
        val lineText = line.text
        val lineConfidence = line.confidence
        val lineLanguages = line.recognizedLanguages
        val lineCornerPoints = line.cornerPoints
        val lineFrame = line.boundingBox
        for (element in line.elements) {
            val elementText = element.text
            val elementConfidence = element.confidence
            val elementLanguages = element.recognizedLanguages
            val elementCornerPoints = element.cornerPoints
            val elementFrame = element.boundingBox
        }
    }
}

실시간 성능 향상을 위한 팁

기기별 모델을 사용하여 실시간 애플리케이션에서 텍스트를 인식하고자 하는 경우 다음 안내에 따르면 최상의 프레임 속도를 얻을 수 있습니다.

  • 텍스트 인식기 호출을 제한합니다. 텍스트 인식기가 실행 중일 때 새 동영상 프레임을 사용할 수 있게 되면 프레임을 낮춥니다.
  • 텍스트 인식기 출력을 사용해서 입력 이미지에서 그래픽을 오버레이하는 경우 먼저 ML Kit에서 텍스트 인식 결과를 가져온 후 이미지를 렌더링하고 단일 단계로 오버레이합니다. 이렇게 하면 각 입력 프레임별로 한 번만 디스플레이 표면에 렌더링됩니다. 관련 예는 빠른 시작 샘플 앱에서 CameraSourcePreviewGraphicOverlay 클래스를 참조하세요.
  • Camera2 API를 사용할 경우 ImageFormat.YUV_420_888 형식으로 이미지를 캡처합니다.

    이전 Camera API를 사용할 경우 ImageFormat.NV21 형식으로 이미지를 캡처합니다.

  • 낮은 해상도로 이미지를 캡처하는 것도 고려해 보세요. 하지만 이 API의 이미지 크기 요구사항도 유의해야 합니다.

문서의 이미지 속 텍스트 인식

문서의 텍스트를 인식하려면 아래에 설명된 대로 클라우드 기반 문서 텍스트 인식기를 구성하고 실행합니다.

아래에 설명된 문서 텍스트 인식 API는 문서 이미지 작업에 더욱 편리한 전용 인터페이스를 제공합니다. 하지만 FirebaseVisionTextRecognizer API에서 제공된 인터페이스를 사용하려면 클라우드 텍스트 인식기에서 밀집 텍스트 모델을 사용하도록 구성하여 이 인터페이스로 문서를 스캔하면 됩니다.

문서 텍스트 인식 API를 사용하려면 다음을 수행합니다.

1. 텍스트 인식기 실행

이미지의 텍스트를 인식하려면 FirebaseVisionImage 객체를 Bitmap, media.Image, ByteBuffer, 바이트 배열이나 기기의 파일에서 만듭니다. 그런 다음 FirebaseVisionImage 객체를 FirebaseVisionDocumentTextRecognizerprocessImage 메소드에 전달합니다.

  1. 이미지에서 FirebaseVisionImage 객체를 만듭니다.

    • Bitmap 객체에서 FirebaseVisionImage 객체를 만드는 방법은 다음과 같습니다.

      자바

      FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);

      Kotlin

      val image = FirebaseVisionImage.fromBitmap(bitmap)
      Bitmap 객체로 표현된 이미지는 추가 회전이 필요 없는 수직 상태여야 합니다.
    • 기기 카메라에서 이미지를 캡처할 때와 같이 FirebaseVisionImage 객체를 media.Image 객체에서 만들려면 먼저 기기의 카메라 센서 방향 및 기기 회전을 보정하기 위해 이미지 회전 각도를 결정합니다.

      자바

      private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
      static {
          ORIENTATIONS.append(Surface.ROTATION_0, 90);
          ORIENTATIONS.append(Surface.ROTATION_90, 0);
          ORIENTATIONS.append(Surface.ROTATION_180, 270);
          ORIENTATIONS.append(Surface.ROTATION_270, 180);
      }
      
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      private int getRotationCompensation(String cameraId, Activity activity, Context context)
              throws CameraAccessException {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
          int rotationCompensation = ORIENTATIONS.get(deviceRotation);
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
          int sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION);
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360;
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          int result;
          switch (rotationCompensation) {
              case 0:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  break;
              case 90:
                  result = FirebaseVisionImageMetadata.ROTATION_90;
                  break;
              case 180:
                  result = FirebaseVisionImageMetadata.ROTATION_180;
                  break;
              case 270:
                  result = FirebaseVisionImageMetadata.ROTATION_270;
                  break;
              default:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  Log.e(TAG, "Bad rotation value: " + rotationCompensation);
          }
          return result;
      }

      Kotlin

      private val ORIENTATIONS = SparseIntArray()
      
      init {
          ORIENTATIONS.append(Surface.ROTATION_0, 90)
          ORIENTATIONS.append(Surface.ROTATION_90, 0)
          ORIENTATIONS.append(Surface.ROTATION_180, 270)
          ORIENTATIONS.append(Surface.ROTATION_270, 180)
      }/**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      @Throws(CameraAccessException::class)
      private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          val deviceRotation = activity.windowManager.defaultDisplay.rotation
          var rotationCompensation = ORIENTATIONS.get(deviceRotation)
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager
          val sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION)!!
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          val result: Int
          when (rotationCompensation) {
              0 -> result = FirebaseVisionImageMetadata.ROTATION_0
              90 -> result = FirebaseVisionImageMetadata.ROTATION_90
              180 -> result = FirebaseVisionImageMetadata.ROTATION_180
              270 -> result = FirebaseVisionImageMetadata.ROTATION_270
              else -> {
                  result = FirebaseVisionImageMetadata.ROTATION_0
                  Log.e(TAG, "Bad rotation value: $rotationCompensation")
              }
          }
          return result
      }

      그런 다음 media.Image 객체 및 회전 값을 FirebaseVisionImage.fromMediaImage()에 전달합니다.

      자바

      FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);

      Kotlin

      val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
    • ByteBuffer 또는 바이트 배열에서 FirebaseVisionImage 객체를 만들려면 먼저 위에서 설명한 대로 이미지 회전을 계산합니다.

      그런 다음 이미지의 높이, 너비, 색상 인코딩 형식, 방향이 포함된 FirebaseVisionImageMetadata 객체를 만듭니다.

      자바

      FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
              .setWidth(480)   // 480x360 is typically sufficient for
              .setHeight(360)  // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build();

      Kotlin

      val metadata = FirebaseVisionImageMetadata.Builder()
              .setWidth(480) // 480x360 is typically sufficient for
              .setHeight(360) // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build()

      버퍼나 배열, 메타데이터 객체를 사용하여 FirebaseVisionImage 객체를 만듭니다.

      자바

      FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);// Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);

      Kotlin

      val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata)// Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
    • 파일에서 FirebaseVisionImage 객체를 만들려면 앱 컨텍스트 및 파일 URI를 FirebaseVisionImage.fromFilePath()에 전달합니다.

      자바

      FirebaseVisionImage image;
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri);
      } catch (IOException e) {
          e.printStackTrace();
      }

      Kotlin

      val image: FirebaseVisionImage
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri)
      } catch (e: IOException) {
          e.printStackTrace()
      }

  2. FirebaseVisionDocumentTextRecognizer 인스턴스를 가져옵니다.

    자바

    FirebaseVisionDocumentTextRecognizer detector = FirebaseVision.getInstance()
            .getCloudDocumentTextRecognizer();
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    FirebaseVisionCloudDocumentRecognizerOptions options =
            new FirebaseVisionCloudDocumentRecognizerOptions.Builder()
                    .setLanguageHints(Arrays.asList("en", "hi"))
                    .build();
    FirebaseVisionDocumentTextRecognizer detector = FirebaseVision.getInstance()
            .getCloudDocumentTextRecognizer(options);

    Kotlin

    val detector = FirebaseVision.getInstance()
            .cloudDocumentTextRecognizer
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    val options = FirebaseVisionCloudDocumentRecognizerOptions.Builder()
            .setLanguageHints(Arrays.asList("en", "hi"))
            .build()
    val detector = FirebaseVision.getInstance()
            .getCloudDocumentTextRecognizer(options)

  3. 마지막으로 이미지를 processImage 메소드에 전달합니다.

    자바

    detector.processImage(myImage)
            .addOnSuccessListener(new OnSuccessListener<FirebaseVisionDocumentText>() {
                @Override
                public void onSuccess(FirebaseVisionDocumentText result) {
                    // Task completed successfully
                    // ...
                }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    // Task failed with an exception
                    // ...
                }
            });

    Kotlin

    detector.processImage(myImage)
            .addOnSuccessListener {
                // Task completed successfully
                // ...
            }
            .addOnFailureListener {
                // Task failed with an exception
                // ...
            }

2. 인식된 텍스트 블록에서 텍스트 추출

텍스트 인식 작업이 성공하면 FirebaseVisionDocumentText 객체가 반환됩니다. FirebaseVisionDocumentText 객체는 이미지에서 인식된 전체 텍스트 및 인식된 문서 구조를 반영하는 객체의 계층구조를 포함합니다.

Block, Paragraph, Word, Symbol 객체에 대해 해당 영역에서 인식된 텍스트와 영역의 경계 좌표를 가져올 수 있습니다.

예:

자바

String resultText = result.getText();
for (FirebaseVisionDocumentText.Block block: result.getBlocks()) {
    String blockText = block.getText();
    Float blockConfidence = block.getConfidence();
    List<RecognizedLanguage> blockRecognizedLanguages = block.getRecognizedLanguages();
    Rect blockFrame = block.getBoundingBox();
    for (FirebaseVisionDocumentText.Paragraph paragraph: block.getParagraphs()) {
        String paragraphText = paragraph.getText();
        Float paragraphConfidence = paragraph.getConfidence();
        List<RecognizedLanguage> paragraphRecognizedLanguages = paragraph.getRecognizedLanguages();
        Rect paragraphFrame = paragraph.getBoundingBox();
        for (FirebaseVisionDocumentText.Word word: paragraph.getWords()) {
            String wordText = word.getText();
            Float wordConfidence = word.getConfidence();
            List<RecognizedLanguage> wordRecognizedLanguages = word.getRecognizedLanguages();
            Rect wordFrame = word.getBoundingBox();
            for (FirebaseVisionDocumentText.Symbol symbol: word.getSymbols()) {
                String symbolText = symbol.getText();
                Float symbolConfidence = symbol.getConfidence();
                List<RecognizedLanguage> symbolRecognizedLanguages = symbol.getRecognizedLanguages();
                Rect symbolFrame = symbol.getBoundingBox();
            }
        }
    }
}

Kotlin

val resultText = result.text
for (block in result.blocks) {
    val blockText = block.text
    val blockConfidence = block.confidence
    val blockRecognizedLanguages = block.recognizedLanguages
    val blockFrame = block.boundingBox
    for (paragraph in block.paragraphs) {
        val paragraphText = paragraph.text
        val paragraphConfidence = paragraph.confidence
        val paragraphRecognizedLanguages = paragraph.recognizedLanguages
        val paragraphFrame = paragraph.boundingBox
        for (word in paragraph.words) {
            val wordText = word.text
            val wordConfidence = word.confidence
            val wordRecognizedLanguages = word.recognizedLanguages
            val wordFrame = word.boundingBox
            for (symbol in word.symbols) {
                val symbolText = symbol.text
                val symbolConfidence = symbol.confidence
                val symbolRecognizedLanguages = symbol.recognizedLanguages
                val symbolFrame = symbol.boundingBox
            }
        }
    }
}

다음 단계

Cloud API를 사용하는 앱을 프로덕션 환경에 배포하기 전에 승인되지 않은 API 액세스로 인한 영향을 방지하고 완화하기 위한 몇 가지 추가 조치를 취해야 합니다.