ゲーム画面をOCRする その2（Google Apps Script）

# 導入
[ゲーム画面をOCRする その1](https://qiita.com/www51k/items/1385d0a47ca354cfba12)
の続きになります。

GoogleドライブでのOCRが有用なのは分かりましたが、
ゲームの画像を複数処理するには労力がかかります。
それをスクリプトで一括して処理を行うことにします。

スクリプトは、Google Apps Script(以下、GAS)を使用します。
（この記事では、Pythonは使用しません。）

# Google Apps Script(GAS)
GASは、無料/有料で制限が違いますが、
無料の範囲内で活用していきます。

## GASの作成
Googleドライブを開き
　>　「新規」ボタン
　　>　「その他」を選択
　　　>　「Google Apps Script」を選択

とりあえず、コードを適当に書き
```
function myFunction() {
  Logger.log("Hello world!")
}
```
プロジェクトを保存すると、
コードを実行できるようになります。

## フォルダIDを取得する
Googleドライブにアップロードした画像フォルダを対象に
GASで処理を行うため、
「フォルダID」を調べます。

Googleドライブを開き
　>　画像フォルダを右クリック
　　>　「リンクを取得」を選択
　　　>　「リンクをコピー」ボタン
　　　　>　コピーされたURLからフォルダIDを取得する
```https://drive.google.com/drive/folders/[フォルダID]?usp=sharing```

## サンプルコード
```
const FOLDER_ID = “[フォルダID]”

function doOCR() {
  let imageFileIds = getImageFileIds(FOLDER_ID)
  Logger.log("imageFileIds>" + imageFileIds)

  let convertedFileIds = []
  for (let imageFileId of imageFileIds) {
    let convertedFileId = convertImageToDocument(imageFileId)
    convertedFileIds.push(convertedFileId)
  }
  Logger.log("convertedFileIds>" + convertedFileIds)

  let texts = []
  for (let convertedFileId of convertedFileIds) {
    let text = openDocument(convertedFileId)
    texts.push(text)
  }
  Logger.log("texts>" + texts)
}

function openDocument(documentFileId) {
  let documentFile = DocumentApp.openById(documentFileId)
  let text = documentFile.getBody().getText()
  return text
}

function convertImageToDocument(imageFileId) {
  let fileName = DriveApp.getFileById(imageFileId).getName() + ".ocr"
  var convertedFileId = ""
  if (DriveApp.getFilesByName(fileName).hasNext()) {
    convertedFileId = DriveApp.getFilesByName(fileName).next().getId()
  } else {
    let ocrOption = {"ocr": true, "ocrLanguage": "ja",}
    let ocrResource = {title: fileName}
    convertedFileId = Drive.Files.copy(ocrResource, imageFileId, ocrOption).id
  }

  return convertedFileId
}

function getImageFileIds(folderId) {
  let folder = DriveApp.getFolderById(folderId);
  let files = folder.getFiles()

  var fileIds = []
  while(files.hasNext()) {
    let file = files.next()
    let fileName = file.getName()
    if (fileName.search(/\.png$/i) >= 0) {
      fileIds.push(file.getId())
    }
  }

  return fileIds
}
```
1. フォルダIDの指定
       取得済みのフォルダIDで、[フォルダID]を差し替えてください。
       ```https://drive.google.com/drive/folders/abcd1234?usp=sharing```
       このURLの場合、
       ```const FOLDER_ID = “abcd1234”```
       のようになります。

2. サービスの追加
       Driveクラスの実行には、
     「サービス」に「Drive API」を追加する必要があります。
￼![Pasted Graphic 116.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53273/8cf08318-9295-3d34-962b-74aa7d010915.png)

3. 実行
       実行する関数には「doOCR」を指定してください。
       フォルダ内の画像をGoogleドキュメントに変換し、
       Googleドキュメントからテキストを読み出します。

4. GASのタイムアウト GASの1回の実行制限時間が6分に限られていており、
       対象画像が多いとタイムアウトが発生しますが、
       今回のサンプルスクリプトでは、
       GASを再度実行することで、
       変換済みの画像は処理対象外となり、
       未変換分のみ処理し続けます。
       最終的には、全画像が変換され、その後にテキストが抽出されます。

### フォルダIDからファイルIDを取得する
```
function getImageFileIds(folderId) {
  let folder = DriveApp.getFolderById(folderId);
  let files = folder.getFiles()

  var fileIds = []
  while(files.hasNext()) {
    let file = files.next()
    let fileName = file.getName()
    if (fileName.search(/\.png$/i) >= 0) {
      fileIds.push(file.getId())
    }
  }

  return fileIds
}
```
フォルダIDからPNG画像のファイルIDを取得します。
Googleドライブのフォルダ/ファイルは、名称が重複可能なため、
特定のフォルダ/ファイルにアクセスするには、IDを取得します。

### 画像をドキュメントに変換する
```
function convertImageToDocument(imageFileId) {
  let fileName = DriveApp.getFileById(imageFileId).getName() + ".ocr"
  var convertedFileId = ""
  if (DriveApp.getFilesByName(fileName).hasNext()) {
    convertedFileId = DriveApp.getFilesByName(fileName).next().getId()
  } else {
    let ocrOption = {"ocr": true, "ocrLanguage": "ja",}
    let ocrResource = {title: fileName}
    convertedFileId = Drive.Files.copy(ocrResource, imageFileId, ocrOption).id
  }

  return convertedFileId
}
```
画像をGoogleドキュメントに変換する過程で、
OCRも行われます。

画像からGoogleドキュメントへの変換は、
処理に時間がかかるため、
変換済みの場合は、スキップするようにしています。

### ドキュメントからテキストの取得
```
function openDocument(documentFileId) {
  let documentFile = DocumentApp.openById(documentFileId)
  let text = documentFile.getBody().getText()
  return text
}
```
Googleドキュメントからテキストのみを取得しています。

### 実行結果
```
6000000
1段階目 ソウタ |2021/07/26 12:33
ゴブリンクルート
6000000
1段階目 ユウキ
2021/07/26 13:37
ゴブリングレートSE
6000000
1段階目 「ダイチ
|2021/07/26 13:01
ゴブリングレート
```
Googleドライブで「画像 > Googleドキュメント」に
変換したのと同じテキストが取得されました。

# まとめ
GASからでも「画像からGoogleドキュメント」への変換によりOCRが行えます。
また、対象画像が複数ある場合でも、スクリプトにより連続してテキストの取得が行えるため、
あとは、テキストデータに対しての作業のみに集中できます。