GASで画像からテキスト抽出!OCRの範囲指定からレシート処理まで

今日の部長から「GASを使ったOCRソリューションを考えろ」って言われたんだけど… 誰か助けてくれないかな…。
猫男
猫男
catman
catman
それならcatmanに任せるといい。GASで画像からテキストを抽出する方法を教えてやろう。

GASを使って画像からテキストを抽出する基本

まず、GASGoogle Vision APIを使ってみよう。

これならOCR(光学文字認識)が簡単にできる。以下の手順で始めるんだ。

Google Cloud Vision APIを有効化しよう

  • GCP(Google Cloud Platform)にアクセスし、新しいプロジェクトを作成。
  • APIライブラリで「Vision API」を検索し、有効化する。
  • 認証情報を作成し、APIキーを取得。

GASスクリプトでOCRを実装する

以下のスクリプトで画像からテキストを抽出してみよう。


function extractTextFromImage(imageUrl) {
  const apiKey = 'YOUR_API_KEY'; // GCPで取得したAPIキーを入力
  const visionUrl = 'https://vision.googleapis.com/v1/images:annotate?key=' + apiKey;
  
  const requestData = {
    requests: [{
      image: { source: { imageUri: imageUrl } },
      features: [{ type: 'TEXT_DETECTION' }]
    }]
  };

  const response = UrlFetchApp.fetch(visionUrl, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(requestData)
  });

  const result = JSON.parse(response.getContentText());
  return result.responses[0].fullTextAnnotation.text;
}

このスクリプトの動作はこんな感じだ。

apiKey:Google Cloud Platformから取得したAPIキーである。
visionUrl:Google Cloud Vision APIのエンドポイントURLを指定。
requestData:画像が格納されたURLとOCRの処理を指定。
UrlFetchApp.fetch():HTTPリクエストを送信するクラスで、Googleサービスと連携するために使用する。

おぉ、APIキーを使えばお手軽にGASでOCRできるんですね!
猫男
猫男

OCRの範囲指定で精度アップを図る

GAS OCRでは、特定の範囲からのみテキストを抽出することにより精度を向上できる場合がある。

範囲を指定する方法

スクリプトを改良して、特定の範囲の画像を指定してOCRを行おう。


function extractTextFromSpecificArea(imageUrl, left, top, width, height) {
  const apiKey = 'YOUR_API_KEY';
  const visionUrl = 'https://vision.googleapis.com/v1/images:annotate?key=' + apiKey;
  
  const requestData = {
    requests: [{
      image: { source: { imageUri: imageUrl } },
      features: [{ type: 'TEXT_DETECTION' }],
      imageContext: {
        cropHintsParams: {
          boundingPoly: {
            vertices: [
              { x: left, y: top },
              { x: left + width, y: top },
              { x: left + width, y: top + height },
              { x: left, y: top + height }
            ]
          }
        }
      }
    }]
  };

  const response = UrlFetchApp.fetch(visionUrl, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(requestData)
  });

  const result = JSON.parse(response.getContentText());
  return result.responses[0].fullTextAnnotation.text;
}

このスクリプトでは画像内の特定のエリアを指定できる。

boundingPoly:テキスト抽出のための四角形を表す。
vertices:四角形の角を指定し、開始点と対角線上のポイントを使って範囲を決める。

この範囲指定の機能は便利ですね!
猫男
猫男

実例:GASでOCRにてレシートを処理する方法

レシートなどの表形式の書類からテキストを抽出してみよう。

表形式データの抽出

レシートから情報を整理して抽出するための工夫が必要だ。このプロセスを試みてみるのも良い。


function extractTextFromReceipt(imageUrl) {
  const text = extractTextFromImage(imageUrl);
  const lines = text.split('\n');
  
  const receiptData = {};
  for (let line of lines) {
    if (line.includes('Total')) {
      receiptData.totalAmount = line.split(' ')[1]; // 総額を抽出
    }
    // 他の情報を抽出するロジックを追加
  }
  
  return receiptData;
}

このスクリプトでやっていることは以下の通り。

split(‘\n’):テキストを行ごとに分割。
includes(‘Total’):特定のキーワードを含むかどうかをチェックし、そこから得たい情報を抜き出す。

GASでレシートを処理するなんて、全国の家庭が大喜びじゃないですか!
猫男
猫男

練習問題

  1. Google Cloud Vision APIを利用して、特定範囲の画像からテキストを抽出するGASスクリプトを書いてください。
  2. GAS OCRを使用して、表形式のデータがある場合に「合計金額」だけを抽出する方法を考えてみてください。

解答・解説


function extractTextFromSpecificArea(imageUrl, left, top, width, height) {
  const apiKey = 'YOUR_API_KEY';
  const visionUrl = 'https://vision.googleapis.com/v1/images:annotate?key=' + apiKey;
  
  const requestData = {
    requests: [{
      image: { source: { imageUri: imageUrl } },
      features: [{ type: 'TEXT_DETECTION' }],
      imageContext: {
        cropHintsParams: {
          boundingPoly: {
            vertices: [
              { x: left, y: top },
              { x: left + width, y: top },
              { x: left + width, y: top + height },
              { x: left, y: top + height }
            ]
          }
        }
      }
    }]
  };

  const response = UrlFetchApp.fetch(visionUrl, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(requestData)
  });

  const result = JSON.parse(response.getContentText());
  return result.responses[0].fullTextAnnotation.text;
}

function extractTotalAmountFromReceipt(imageUrl) {
  const text = extractTextFromImage(imageUrl);
  const lines = text.split('\n');
  
  for (let line of lines) {
    if (line.includes('Total')) {
      return line.split(' ')[1];
    }
  }
  return 'Total amount not found';
}

1. extractTextFromSpecificArea関数では、画像内で特定のエリアを定義してOCRで解析する。
2. extractTotalAmountFromReceipt関数は、抽出したテキストの各行を確認し、「Total」と関連する単語が含まれる行から金額を取り出す。

練習問題のスクリプトをもとに、さまざまな応用を試みることで、GASでOCRの力を実感してみよう。