ML Kit for Firebase テキスト認識を使ってOCR処理をしてみた

## ML Kit for Firebase

**[OCR](https://ja.wikipedia.org/wiki/%E5%85%89%E5%AD%A6%E6%96%87%E5%AD%97%E8%AA%8D%E8%AD%98)**

> 活字の文書の画像（通常イメージスキャナーで取り込まれる）を文字コードの列に変換するソフトウェアである。

**[ML Kit for Firebase](https://firebase.google.com/docs/ml-kit?hl=ja)**

> ML Kit は、Google の機械学習の機能を Android アプリや iOS アプリとして提供するモバイル SDK です。

**[テキスト認識
](https://firebase.google.com/docs/ml-kit/recognize-text?hl=ja)**

> ML Kit のテキスト認識 API を使用すると、ラテン語由来の言語のテキストを認識できます（クラウドベースのテキスト認識を使用すると、より多くの言語のテキストを認識できます）。

> テキスト認識はクレジット カードや領収書、名刺の面倒なデータ入力を自動化できます。クラウドベースの API を使用すると、ドキュメントの写真からテキストを抽出することもできます。これにより、アクセシビリティの向上やドキュメントの翻訳を行うことができます。たとえば、列車上の番号を読み取り、アプリで実際の対象物を追跡することもできます。

メ◯カリとかの本人確認機能とかOCR機能使ってそう。ML Kit for Firebaseを利用すれば、簡単にOCR処理できるっぽいのでやってみました。

## 事前準備

### Firebase プロジェクトの作成

google-services.json が無いと動かないので、[Firebase Console](https://console.firebase.google.com/) でプロジェクトを作成し、アプリを追加します。アプリの追加が完了すると、google-services.json が作られるので、ダウンロードしてアプリプロジェクトに追加します。この辺は Firebase そもそもの使い方になるので割愛します。

### クラウドベースの API を有効化

今回はクラウドベースモデルを使用するので、クラウドベースの API を有効にします。
Firebase プロジェクトのプランを Blaze プランにアップグレードし、[クラウドベースの API を有効化]からクラウドベースの API を有効にします。

### ML Kit ライブラリのインストール

ML Kit ライブラリのインストールは CocoaPods を使用するとよいでしょう。Podfile に ML Kit ライブラリを含めます。テキスト認識の on-device API も使えるようにしておくとなると、最低限必要なのは以下の3つになります。

```
pod 'Firebase/Analytics'
pod 'Firebase/MLVision'
pod 'Firebase/MLVisionTextModel'
```

## ベースアプリの準備

まずはカメラで写真を撮るアプリを作成します。

<img width="870" alt="スクリーンショット 2019-12-09 19.25.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151693/a231020b-2c07-8c6f-b15a-2a693a563ae0.png">

UIはこんな感じ。Take Photo ボタンでカメラを起動して、Recognized Text View に認識した文字列を描画します。

```Swift
import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var recognizedTextView: UITextView!

    @IBAction func takePhotoButtonTouchUpInside(_ sender: Any) {
        
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            let imagePickerController = UIImagePickerController()
            imagePickerController.sourceType = .camera
            imagePickerController.delegate = self
            self.present(imagePickerController, animated: true, completion: nil)
        }
        
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
}
```

ViewControllerの実装はこんな感じ。

```Swift
extension ViewController: UIImagePickerControllerDelegate {
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        
        guard let image = info[.originalImage] as? UIImage else {
            return
        }
        
        picker.dismiss(animated: true, completion: nil)
        
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        
        picker.dismiss(animated: true, completion: nil)
        
    }
    
}

extension ViewController: UINavigationControllerDelegate {
    
}
```

UIImagePickerControllerDelegate と UINavigationControllerDelegate の実装はこんな感じ。

## テキスト認識の処理を実装

いよいよ本題。
まずは Firebase をインポート。

```Swift
import Firebase
```

次にテキスト認識の処理メソッドを ViewController に実装。

```Swift
private func recognizeTextInCloud(in image: UIImage) {

        let metadata = VisionImageMetadata()
        metadata.orientation = .rightTop

        let visionImage = VisionImage(image: image)
        visionImage.metadata = metadata

        let options = VisionCloudTextRecognizerOptions()

        let cloudTextRecognizer = Vision.vision().cloudTextRecognizer(options: options)

        cloudTextRecognizer.process(visionImage) { text, error in
            guard error == nil, let text = text else {
                print("Text recognizer failed with error: " + "\(error?.localizedDescription ?? "No Results")")
                return
            }

            self.recognizedTextView.text = text.text
        }

    }
```

はい、たったコレだけ。上記のコードではクラウドベースのテキスト認識になります。
on-device でテキスト認識する場合は、TextRecognizer オブジェクトのインスタンスを生成する際に、cloudTextRecognizer(options:) の変わりに onDeviceTextRecognizer() を使うだけです。

あとはカメラで撮影した写真をテキスト認識の処理メソッドに通すだけ。

```Swift
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        
    guard let image = info[.originalImage] as? UIImage else {
        return
    }
        
    self.recognizeTextInCloud(in: image)
        
    picker.dismiss(animated: true, completion: nil)
        
}
```

こんな感じ。

## 動かしてみる

<img width="375" alt="IMG_0158.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151693/ea2c81c0-d2a8-e428-9824-1070cb53a55a.png">

こんな感じの写真を撮ってみると、、、

<img width="375" alt="IMG_0159.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151693/fe73ed19-1fb8-afca-a9b6-e4d158c8c02b.png">

記号とかが怪しいけど、かなり正確に文字認識してます！
コレでメル◯リ風の本人確認機能に近いことはできるんじゃないでしょうか！