前提
下記クイックスタートの「Vision APIの設定」は完了しているものとする。
クイックスタート: Vision API を設定する | Cloud Vision API | Google Cloud
やること
Vision APIの呼び出し方は大きく分けて2つあり、(本当は3つ)
1つは、クライアントライブラリと呼ばれるGCP専用のライブラリを介して呼び出す方法(GCP推奨の方法)であり、
もう1つは、既に用意されているエンドポイントからREST APIを呼び出す方法である。
今回は、クライアントライブラリからのVisionAPIの実行と、REST API経由でのVisionAPIの実行をやってみる。
開発はNodeJSで行う。
クライアントライブラリを使ってVision APIを実行する
公式の説明によると、クライアントライブラリは以下のようなものである。
- Cloud API を簡単かつ直感的に使用できるように、各言語で慣用的な生成済みコードや手書きコードを提供します。
- Google での認証など、サーバーとの通信に関する下位レベルのすべての詳細を処理します。
- npm や pip など、使い慣れたパッケージ管理ツールを使用してインストールできます。
- 場合によっては、gRPC を使用してパフォーマンスを高めることもできます
プロジェクトの準備
適当なディレクトリを作り、その中でnpm init
を実行。
以降はこのディレクトリ配下で作業を行う。
mkdir my-app
cd my-app
npm init
注意
環境変数GOOGLE_APPLICATION_CREDENTIALS
で、クイックスタートで作ったサービスアカウントキーファイルへのパスを設定しておく必要がある。
export GOOGLE_APPLICATION_CREDENTIALS=PATH_TO_KEY_FILE
クライアントライブラリのインストール
npm install --save @google-cloud/vision
実装
index.jsを作って、下記のように実装。(公式ドキュメントのサンプルをほぼコピペ)
クイックスタート: クライアント ライブラリの使用 | Cloud Vision API | Google Cloud
async function quickstart() {
// Imports the Google Cloud client library
const vision = require("@google-cloud/vision");
// Creates a client
const client = new vision.ImageAnnotatorClient();
// Performs label detection on the image file
const [result] = await client.labelDetection("./sports.jpg");
const labels = result.labelAnnotations;
console.log("Labels:");
labels.forEach((label) => console.log(label.description));
}
// これだけだとasync-awaitする必要はあまりない(なくても動く)
(async function () {
await quickstart();
})();
上記で使用しているlabelDetection
APIは、入力となる画像に含まれる物体、場所、活動、動物の種類、商品などを検出して、ラベルとしてアウトプットしてくれるもの。
例として、サッカー選手が真ん中に写っている画像を入力したときのアウトプットは以下のようになる。すごい。
node index.js
Labels:
Player
Sports
Sports equipment
Football player
Team sport
Ball game
Soccer player
Soccer
Football
Tournament
REST API経由でのVision APIの呼び出し
Vision API リクエストを作成する | Cloud Vision API | Google Cloud
エンドポイント
Vision APIのエンドポイントは以下のとおり。
POST https://vision.googleapis.com/v1/images:annotate
認証の設定
REST APIの実行には、「APIキー」または「サービスアカウント」による認証が必要であるが、今回は「APIキー」による認証を採用する。
APIキーの作成は、こちらを参照。 → API キーの使用 | 認証 | Google Cloud
APIキーを使う場合は、クエリパラメータとして渡す。
POST https://vision.googleapis.com/v1/images:annotate?key=YOUR_API_KEY
APIキーの保護
上記で作成したAPIキーは、デフォルトだと何も制限されていないため、APIキーを知っている人なら誰でもAPIが実行できる状態になっている。
いくつかの制限方法があるが、今回は自分だけ使えれば良いので、IPアドレスでの制限を設定。
https://cloud.google.com/docs/authentication/api-keys?hl=ja&visit_id=637246713360916796-291330020&rd=1#api_key_restrictions
下記のようなサイトで、自分のグローバルIPアドレスを調べて、GCPコンソール上で設定する。
念のためIPv4とIPv6のアドレス両方を許可した。(NodeJSから直接REST APIを実行する場合は、IPv4の設定だけでOKだったが、自分の環境だとブラウザを介してAPIを実行させる場合はIPv6の設定が必要だった。)
https://test-ipv6.com/index.html.ja_JP
IPアドレス制限に引っかかった場合は、以下のようなエラーレスポンスが帰ってくる。
XXX.XXX.XXX.XXX
の部分に自分のIPアドレスが入っているので、もし設定がうまくいっておらず下記のようなエラーが出た場合は、XXX.XXX.XXX.XXX
を許可するように設定すればOK。(XXX.XXX.XXX.XXX
はIPv6の場合もある。)
{
code: 403,
message: 'The provided API key has an IP address restriction. The originating IP address of the call (XXX.XXX.XXX.XXX) violates this restriction.',
status: 'PERMISSION_DENIED',
details: [ [Object] ]
}
リクエストの形式
{
"requests":[
{
"image":{
"content":"/9j/7QBEUGhvdG9...image contents...eYxxxzj/Coa6Bax//Z"
},
"features":[
{
"type":"LABEL_DETECTION",
"maxResults":1
}
]
}
]
}
image
画像の指定方法は3種類ある。
- base64形式で
image.content
に直接指定する - gcpのストレージサービス Cloud Storage にあるデータのURIを
image.source.imageUri
に指定する - HTTP または HTTPS でアクセス可能な公開URLを
image.source.imageUri
に指定する(※ このパターンはDOSなどの不正利用防止のため失敗することがあるので、本番での利用は非推奨)
今回は、base64形式のパターンを試す。
Base64形式へのエンコード方法は、下記に記載がある。
Base64 エンコード | Cloud Vision API | Google Cloud
features
Feature | Cloud Vision API | Google Cloud
type
には、FACE_DETECTION
やLABEL_DETECTION
など、機能に応じた文字列を指定する。
maxResults
には、上記で指定した機能で、最大何件検出を行うかを数値で指定する。
レスポンス例(ラベル検出の場合)
{
"responses": [
{
"labelAnnotations": [
{
"mid": "/m/0bt9lr",
"description": "dog",
"score": 0.97346616
},
{
"mid": "/m/09686",
"description": "vertebrate",
"score": 0.85700572
}
]
}
]
}
準備
APIキーの設定
環境変数にAPIキーを設定する。 export VISION_API_KEY={API_KEY}
NodeJSでは、環境変数で設定した値を、process.env["環境変数名"]
で取得できる。
パッケージのインストール
リクエストを送るために、axios
をインストールする。npm i axios
実装
今回は今後あまり使わなそうなランドマーク検出を使う。
function toBase64(imagePath) {
// Read the file into memory.
const fs = require("fs");
const imageFile = fs.readFileSync(imagePath);
// Convert the image data to a Buffer and base64 encode it.
return Buffer.from(imageFile).toString("base64");
}
(async function () {
const axios = require("axios");
const apiKey = process.env["VISION_API_KEY"];
if (!apiKey) {
console.log("Env 'VISION_API_KEY' must be set.");
process.exit(1);
}
const visionApiUrl = `https://vision.googleapis.com/v1/images:annotate?key=${apiKey}`;
const imagePath = "./liberty.jpeg";
const options = {
requests: [
{
image: {
content: toBase64(imagePath),
},
features: [
{
type: "LANDMARK_DETECTION",
maxResults: 3,
},
],
},
],
};
try {
const result = await axios.post(visionApiUrl, options);
console.log("Request success!");
if (result.data && result.data.responses) {
const responses = result.data.responses;
responses.forEach((response) => {
console.log("Landmarks:");
response.landmarkAnnotations.forEach((annotation) =>
console.log(annotation)
);
});
}
} catch (error) {
console.error(error.response || error);
}
})();
レスポンス
自由の女神像の写真をインプットとした場合の結果
node index.js
Request success!
Landmarks:
{
mid: '/m/072p8',
description: 'Statue of Liberty National Monument',
score: 0.790907,
boundingPoly: { vertices: [ [Object], [Object], [Object], [Object] ] },
locations: [ { latLng: [Object] } ]
}
{
mid: '/m/072p8',
description: 'Statue of Liberty',
score: 0.77413857,
boundingPoly: { vertices: [ [Object], [Object], [Object], [Object] ] },
locations: [ { latLng: [Object] } ]
}
{
mid: '/m/02nd_',
description: 'New York City',
score: 0.6340594,
boundingPoly: { vertices: [ [Object], [Object], [Object], [Object] ] },
locations: [ { latLng: [Object] } ]
}
(おまけ)Vision APIの実行回数の確認
Vision APIには、ラベル検出、テキスト検出、顔検出などの様々な種類の機能があるが、
それぞれについて、月1000回までが無料利用枠となっている。(機能によって違うが、1001回目からはだいたい$1.50[/1000回]かかる)
個人で、しかもお試しで使ってる分には1000回を超えることはないと思うが、心配だったので確認方法を探した。
料金 | Cloud Vision API | Google Cloud
GCPコンソールのホームにて、
デフォルトだと画面右にある「お支払い」カードの
「→請求の詳細を表示」を押すと、
機能ごとに何回使ったかがわかる。