GoogleVisionAPIで画像タグを取得してみた(チュートリアル実行)

仕事でGoogleVisionAPIを使うことになったので、まずは全体感を掴もうとチュートリアルをやってみることに。

公式ページはこちら。
https://cloud.google.com/vision/?hl=ja

1.チュートリアルを開く

一番下の「コースとハンズオンラボを受講する」から、「Cloud Vision API でラベル、顔、ランドマーク、画像を検出する」を実行してみます。

英語やないかw と思いつつ、ぱっと見日本語サイトを発見できなかったのでそのまま続行。
(あとで見つけましたが日本語サイトは多分 → https://cloud.google.com/vision/docs/quickstart?hl=ja

2.準備

f:id:hiro-29:20191009214624p:plain

Cloud Platform Projectが必要と書いてあるけど、この後で作ります。
ブラウザはChromeFirefoxとのこと。

f:id:hiro-29:20191009214652p:plain

実機触りながらやる?読むだけ?どれくらい詳しい?と聞かれる。
実機触りますし、初心者です。
これ変えるとコンテンツ変わるのかなぁ。未検証です。


「3. Setup and Requirements」に進みます。
まずはGoogleアカウントが必要。これは持っていたので割愛。

GoogleアカウントがあればCloud Platformが使えるようになっているので、早速アクセス。
console.cloud.google.com

プロジェクトを作れと言われるので、言われるまま「新しいプロジェクト」からプロジェクトを作成します。

f:id:hiro-29:20191009214725p:plain

最初、「My Project 123456」のようなプロジェクト名と、それとは全く関係なさそうなユニークIDが表示されるので、プロジェクト名を修正します。
IDはプラットフォーム上でユニークである必要があるっぽく、ユニークな文字列ではないとバリデーションチェックで勝手に数字を付けてユニークなIDを提案してくれます。

とにかく最初、何も考えずそのまま作ったのが「My First Project」で、「Curious kingdom」他はIDがユニーク(プロジェクト名と同じ)になるようにして作ったやつです。
Curious Kingdomは、勝手にレコメンドされた文字列(笑)
意味不明だったので採用(笑)

f:id:hiro-29:20191009214743p:plain

そして支払方法を登録すれば使えるようになりますとのことで、素直に「enable billing」をクリックします。
開いたページで、「請求先アカウントを追加」をクリック。

f:id:hiro-29:20191009214756p:plain

このあと、カード情報と住所を登録する画面になるので登録の上、「無料トライアルを開始」をクリックします。

まあ、会社で承認通すのもめんどくさいし、動作確認レベルの処理量なので、仮に課金に引っかかったとしてもカワイイ金額だろうということで脳死で自分のカードを登録します。
無料トライアルについての説明は出ている通り。この$300の無料トライアルを有効にしなくても、動作確認で使うくらいなら課金されることはないようですね。
でも、いたるところで「$300トライアルやろうぜ!!」というレコメンドが表示されるので、もう普通にトライアルしてしまって良いと思います。デメリットは特に無いんではないかな。

ちなみに課金の料金はこちらの通り。
https://cloud.google.com/vision/pricing?hl=ja

だいたい、月に1,000枚の処理を超えると、500万枚までは月に160円ということで、ま、大丈夫でしょう。そんなに検証しまくらないと思うししても数百円ということで。

3.Vision APIを有効にする

次の 「4. Enable the Cloud Vision API」ページのとおり、

左上ハンバーガーメニュー > SPIとサービス > APIとサービスを有効化 > vision と検索し、出現した「Google Cloud Vision API」を有効化します。

そしてクラウドシェルの説明。

クラウドシェルは、ローカルに環境を作らなくても、ブラウザ上でそのまま実行できるコマンドライン
5GBのストレージが最初についてくるということで、簡単な動作検証ならこちらで完結できそうですね。素晴らしい。
Projectを選択状態で右上のクラウドシェルを選択すると、画面下部にクラウドシェルが立ち上がります。

f:id:hiro-29:20191009214830p:plain

ベータ版ですがコードエディタもついてる!
気づかずviでファイルを作っちゃいましたが、コードエディタのほうが打断然見やすいので、次から使いたいなと思います。


そしてAPIを使うので、API Keyを発行しておきます。
こちらも「6. Create an API Key」のキャプチャどおりに実行。

f:id:hiro-29:20191009214843p:plain

この数字はコピって保存しておきます。
変数として入れておくとイイね! ということで、変数定義まで書かれている通りに実行。

export API_KEY=取得したAPIキー

で登録した変数は printenv API_KEY で表示できます。
f:id:hiro-29:20191009214902p:plain

4.バケットの作成と権限の設定

さて、APIにどうやって画像渡す?の方法として、「base64エンコード」か「Cloud StorageにアップロードしてURLを渡す」の2択。
さすがにエンコードはww ということで、手順通りにクラウドストレージを利用します。

f:id:hiro-29:20191009214920p:plain

ちなみに、12ヶ月$300の無料トライアルに登録していないままだとこういう画面になります。
「クイックスタート」を押しても、やっぱりトライアルに登録しているプロジェクトに紐つけろと表示されるので、ここは素直に登録しましょう。

f:id:hiro-29:20191009214937p:plain

バケットの作成では、「バケットの名前」、「データの保存場所」、「データのデフォルトのストレージクラスの選択」、「オブジェクトへのアクセスを制限する方法の選択」、「詳細」と、色々と設定することがあります。

バケットに名前をつける

こちらは、英小文字、数字、ハイフン、アンダースコアのみ使用可。
f:id:hiro-29:20191009214954p:plain

データの保存場所

リージョンをまたがるかどうかというのを選択できるらしい。
想像でしかないけど、アクセス元を近所エリアだと想定するなら「近所の同一リージョン」のほうがリッチで、世界規模でスケールしてパフォーマンスを保持したいなら「複数リージョン」という感じなのでしょうか。
f:id:hiro-29:20191009215010p:plain

今回はただの動作テストなので、ここでは単一リージョンでTokyoを選択しておきます。
お客様も国内で完結する予定だから、実務でもひとまずこれで良さそうかな。

デフォルトのストレージクラス

f:id:hiro-29:20191009215029p:plain
これは説明がそのまま載っているので素直に選択。
頻繁でもないけどアーカイブってわけでもないので、「Nearline」を選択しておきます。

オブジェクトへのアクセスを制御する方法

これは結構大事な気がしますね。
アクセス制御をどっちでやるかを選択できる。

f:id:hiro-29:20191009215044p:plain
Cloud IAM か、ACL(アクセス制限リスト)の二択。

ドキュメントによれば

Cloud Identity and Access Management(Cloud IAM)権限: バケットへのアクセス、および 1 つのバケットのオブジェクトへの一括アクセスを許可します。Cloud IAM 権限では、プロジェクトとバケットに対する幅広い制御が可能ですが、個々のオブジェクトを細かく制御することはできません

アクセス制御リスト(ACL): 個々のバケットやオブジェクトへの読み取りまたは書き込みアクセスを許可します。ほとんどの場合、ACL ではなく Cloud IAM 権限を使用します。ACL は、個々のオブジェクトを細かく制御する必要がある場合にのみ使用します。

ということらしいので、素直にIAMのほうにしておきます。

詳細は省略可ということで、省略しちゃいます。
バケットが出来ました。

f:id:hiro-29:20191009215105p:plain

わーい!ブラウザアップロード! と、条件反射でドラッグ&ドロップすると怒られます…。

f:id:hiro-29:20191009215121p:plain
オブジェクトクリエイトの権限がIAMのデフォだと許可されていないわけですね。
ということで、チュートリアルどおり「ファイルのアップロード」ボタンからアップロードします。
今回使うのは花火の写真。夏にスマホで撮ったやつが入っていたのでね。

f:id:hiro-29:20191009215522j:plain

で、このファイルに直接アクセス権を付与します。
このままだと外からアクセス出来ないわけですね。

f:id:hiro-29:20191009215149p:plain

チュートリアルと違い、「ユーザー」として自分のGoogleアカウントがオーナーとして追加されていますが、チュートリアル通りに読み取り専用で「allUsers」グループを追加します。
これをすると、「公開アクセス」が、「非公開」から、エクスクラメーションマーク付きの「公開」に変更されますね。

5.リクエストを作成して呼び出し

いざ、Cloud Shellとコードエティタでリクエストを作成します。
クラウドシェルの右側、このボタンからコードエディタを立ち上げる。

f:id:hiro-29:20191009215202p:plain

f:id:hiro-29:20191009215216p:plain

快適快適~~。
(最初エディタの存在を知らず本当はViで書いたんですけどね‥w)


そしていよいよ! 呼び出しです!!

ここもコピペでOK。
API_KEYは、そのまま「API_KEY」で変数定義していますので、中括弧だけ削除して、クラウドシェルから実行します。

curl -s -X POST -H "Content-Type: application/json" --data-binary @request.json https://vision.googleapis.com/v1/images:annotate?key=$API_KEY

結果です!

{
  "responses": [
    {
      "labelAnnotations": [
        {
          "mid": "/m/0g6b5",
          "description": "Fireworks",
          "score": 0.99602693,
          "topicality": 0.99602693
        },
        {
          "mid": "/m/015h7g",
          "description": "New Years Day",
          "score": 0.93273723,
          "topicality": 0.93273723
        },
        {
          "mid": "/m/05_5t0l",
          "description": "Landmark",
          "score": 0.90139806,
          "topicality": 0.90139806
        },
        {
          "mid": "/m/01kv7h",
          "description": "Midnight",
          "score": 0.8801451,
          "topicality": 0.8801451
        },
        {
          "mid": "/m/07bb2_",
          "description": "F?te",
          "score": 0.8785918,
          "topicality": 0.8785918
        },
        {
          "mid": "/m/081pkj",
          "description": "Event",
          "score": 0.877146,
          "topicality": 0.877146
        },
        {
          "mid": "/m/04k84",
          "description": "Light",
          "score": 0.8738562,
          "topicality": 0.8738562
        },
        {
          "mid": "/m/01d74z",
          "description": "Night",
          "score": 0.8551577,
          "topicality": 0.8551577
        },
        {
          "mid": "/m/03gkl",
          "description": "Holiday",
          "score": 0.83703744,
          "topicality": 0.83703744
        },
        {
          "mid": "/m/01pl3y",
          "description": "New year's eve",
          "score": 0.8369392,
          "topicality": 0.8369392
        }
      ]
    }
  ]
}

素晴らしい。

Fireworks」「New Years Day」とか、まさしく!という感じですね。
「Landmark」が入っているということは、花火の手前のビルを認識したのでしょうか。


request.jsonの「type」を「WEB_DETECTION」に変更して実行すると、類似イメージ検索のようなことも可能。
かなり似ている写真がリストされました。
顔写真はアップしたくなかったので「FACE_DELECTION」は試してませんが、その他色々とメソッドがあるみたいですね。これは楽しいわ。

終わりに

Windowsコマンドラインからも実行(request.jsonはローカルにも配置)したところ、問題なく結果が帰ってきました。


ミスすると400だとか403という結果が返ってきたりするのですが、だいたいAPIキーの記述をミスっているか、アイテム側やバケットに権限がない場合だと思われます。
最初、バケット作成のところで誤って別プロジェクトを再作成してしまい紐付けがごっちゃになってたので権限設定がうまく完了出来ておらず、何度やっても返ってこない…という状況に陥ってました。
権限設定は肝になりそうなので気をつけたいと思います。

{
  "error": {
    "code": 400,
    "message": "API key not valid. Please pass a valid API key.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.Help",
        "links": [
          {
            "description": "Google developers console",
            "url": "https://console.developers.google.com"
          }
        ]
      }
    ]
  }
}

~終~