Go言語とGoogle Cloud Vision APIで画像認識

こんにちは!最近、Google Cloud Platformを周りにオススメしている金子です。

先週、Googleが画像認識や分類を行えるCloud Vision APIをベータとしてついに公開したので、今回はCloud Vision APIをGo言語で使用する方法を書かせていただきます。

Cloud Vision API

Cloud Vision APIは画像上のテキスト読み取りや顔の位置検知だけでなく、対象となる物がどのような種類かの検知や人の感情を推測することもできます。

ov-gopher

テキストの検知も多言語に対応しているため、日本語も問題なく認識することができます。

Cloud Vision API – 準備編

Cloud Vision APIを利用するためにVision APIの有効化と、Go言語で実行するためにService accountの作成をする必要があります。この準備は公式ドキュメントに記載があるのと、他にもBrowser Keyを生成してcurl経由にてAPIリクエストする方法も記載してあります。

公式ドキュメント→Getting Started

Vision APIを有効化

Vision APIを使用するためにCloud Developer ConsoleのAPI ManagerからCloud Vision APIを有効化します。

01-vision-search

Google Developer Console

Cloud Developer ConsoleからAPI Managerを開き、Cloud Vision APIを選択してください。


画像の通り、上の方に「Enable」ボタンがあるのでそちらを押して下さい。

02-vision-enable

押すだけでは料金は発生しないので安心してください。料金体系の詳細はこちらをご覧ください。

Credentialsの準備

次に、Cloud Vision APIを認証する準備を行います。Cloud Vision APIへ認証するためにCredentialsページでService accountを作成します。

03-vision-credentials

Credentials Page

「Create Credentials」を押してから「Service account key」を選択してください。


04-vision-serviceaccount

「Service account」をNew service accountを設定し、「Name」には適当に文字を入れてください。「Key type」はJSONにして「Create」を押すと、下記のようなJSONファイルのダウンロードが開始します。

{
  "type": "service_account",
  "project_id": "project-id",
  "private_key_id": "some_number",
  "private_key": "-----BEGIN PRIVATE KEY-----\n....
  =\n-----END PRIVATE KEY-----\n",
  "client_email": "visionapi@project-id.iam.gserviceaccount.com",
  "client_id": "...",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://accounts.google.com/o/oauth2/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/visionapi%40project-id.iam.gserviceaccount.com"
}

これを使用してCloud Vision APIのOAuth2認証をします。Goから読み込むためと、各種SDKでも使用できるように環境変数にJSONファイルのパスを設定しておいてください。

例として、~/.credentialsディレクトリにダウンロードしたservice_account.jsonファイルを置き、そのファイルを設定します。

$ mkdir ~/.credentials
$ mv service_account.json ~/.credentials/
$ export GOOGLE_APPLICATION_CREDENTIALS=~/.credentials/service_account.json

ソースコードで文字列として指定するのも良いですが、上記はGoogleのSDKでは基本となるのでその通りに設定しましょう。

Cloud Vision API – 実装編

今回作成したGoファイルはGitHubにホスティングしています。

project-1

また、検証で使用したGoのバージョンは1.5.31.6で検証済みです。

セットアップ: go get

OAuth2認証をするために、oauth2/googlecontextパッケージが必要となります。

$ go get -u golang.org/x/net/context
$ go get -u golang.org/x/oauth2/google
$ go get -u google.golang.org/api/vision/...

GitHubにあげたリポジトリにはglide.lockをコミットしているのでglide installでも取得可能です。

使用方法

リポジトリのものはCLIとして提供しています。main.goをgo runで使用することもできますし、go getしたのならgo-cloud-vision-apiコマンドを使うことが可能です。

$ go-cloud-vision-api lenna.jpg
# go run main.go lenna.jpg
[
  {
    "faceAnnotations": [
      {
        "angerLikelihood": "VERY_UNLIKELY",
        "blurredLikelihood": "VERY_UNLIKELY",
        "boundingPoly": {
          "vertices": [
            {
              "x": 143,
              "y": 43
            },
            {
              "x": 245,
              "y": 43
            },
            {
              "x": 245,
              "y": 163
            },
            {
              "x": 143,
              "y": 163
            }
          ]
        },
        ....
        "headwearLikelihood": "UNLIKELY",
        "joyLikelihood": "VERY_UNLIKELY",
        "landmarkingConfidence": 0.5350582,
        "landmarks": [
          {
            "position": {
              "x": 197.90556,
              "y": 102.932,
              "z": 0.00083794753
            },
            "type": "LEFT_EYE"
          },
          ....
          {
            "position": {
              "x": 220.39294,
              "y": 132.60187,
              "z": 54.00494
            },
            "type": "CHIN_RIGHT_GONION"
          }
        ],
        "panAngle": 34.809193,
        "rollAngle": 5.9516206,
        "sorrowLikelihood": "VERY_UNLIKELY",
        "surpriseLikelihood": "VERY_UNLIKELY",
        "tiltAngle": -10.011973,
        "underExposedLikelihood": "VERY_UNLIKELY"
      }
    ]
  }
]

レスポンス結果(JSON)をそのまま標準出力に出しています。Credentialsの情報などが間違っている場合はエラーが出力されます。

Goでの実装

"google.golang.org/api/vision/v1"のリファレンスはgodoc.orgにホスティングされています。

Go言語側で必要な実装の大枠は5段階なので、その順番に解説をしていきます。

  • OAuth2認証準備
  • vision.Serviceの生成
  • vision.AnnotateImageRequestの生成
  • ServiceからRequest送信
  • Responseの処理

これから記述する実装のベースはkaneshin/go-cloud-vision-api/main.goにあります。

※以降出てくるコードは見易いようにpanicを使用などしています。

OAuth2認証準備

認証は先ほど作成したService accountのJSONファイルをgolang.org/x/oauth2/googleパッケージに渡すことによって簡単に認証することができます。

fn := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
b, err := ioutil.ReadFile(fn)
if err != nil {
	panic(err)
}

config, err := google.JWTConfigFromJSON(b, vision.CloudPlatformScope)
if err != nil {
	panic(err)
}

ref: main.go#L25-L38

JWTConfigFromJSONを使用せず、ConfigFromJSONを使用して認証することも可能ですが、JWTConfigFromJSONを利用する方が簡単です。

ConfigFromJSONを使う例はGoogle Calendar APIのQuick Startの「Step 3: Set up the sample」にサンプルコードがあります。

vision.Serviceの生成

先ほど作成したconfigを用いて、HTTPクライアントを取得します。そのHTTPクライアントをvisionのサービスに設定することによって使用することが可能になります。

client := config.Client(context.Background())

srv, err := vision.New(client)
if err != nil {
	panic(err)
}
return srv

ref: main.go#L39-L45

vision.AnnotateImageRequestの生成

画像をbase64にエンコードする必要があります。今回のサンプルコードでは引数にファイルパスを渡すため、Goコードの方でエンコードします。

encoded, err := ioutil.ReadFile(path)
if err != nil {
	panic(err)
}
content := base64.StdEncoding.EncodeToString(encoded)

このbase64エンコード文字列と、どの検知システムを使うかを設定します。

req := &vision.AnnotateImageRequest{
	// Apply image which is encoded by base64.
	Image: &vision.Image{
		Content: content,
	},
	// Apply features to indicate what type of image detection.
	Features: []*vision.Feature{
		{
			MaxResults: 10,
			Type:       "FACE_DETECTION",
		},
	},
}
return req

ref: main.go#L48-L68

vision.FeatureTypeには下記の値を渡すことができます。

  • "TYPE_UNSPECIFIED": タイプを特定してない、不特定の検知を行う。
  • "FACE_DETECTION": 顔(複数可)の位置や感情などを検知/推測する。
  • "LANDMARK_DETECTION": 物体の検知/推測を行う。
  • "LOGO_DETECTION": 企業のロゴマークを検知する。
  • "LABEL_DETECTION": ラベルにある多言語の文字を検知する。
  • "TEXT_DETECTION": OCRで多言語の文字を検知する。
  • "SAFE_SEARCH_DETECTION": アダルトコンテンツなどの画像を検知する。
  • "IMAGE_PROPERTIES": 画像が適切(アダルトコンテンツなどではない)であるかを推測する。

今回のサンプルでは"FACE_DETECTION"のみをサポートしています。

ServiceからRequest送信

Serviceが持つHTTPクライアントから送信することになりますが、バッチリクエストでまとめて実行します。

// To call multiple image annotation requests.
batch := &vision.BatchAnnotateImagesRequest{
	Requests: []*vision.AnnotateImageRequest{req},
}

// Execute the "vision.images.annotate".
res, err := srv.Images.Annotate(batch).Do()
if err != nil {
	panic(err)
}

ref: main.go#L93-L103

Responseの処理

Responseの中身にある各アノテーションに画像認識をした情報が入っています。

body, err := json.MarshalIndent(res.Responses, "", "  ")
if err != nil {
	panic(err)
}
fmt.Println(string(body))

ref: main.go#L105-L111

各アノテーションは下記のように定義されています。

type AnnotateImageResponse struct {
	FaceAnnotations      []*FaceAnnotation     `json:"faceAnnotations,omitempty"`
	LabelAnnotations     []*EntityAnnotation   `json:"labelAnnotations,omitempty"`
	LandmarkAnnotations  []*EntityAnnotation   `json:"landmarkAnnotations,omitempty"`
	LogoAnnotations      []*EntityAnnotation   `json:"logoAnnotations,omitempty"`
	SafeSearchAnnotation *SafeSearchAnnotation `json:"safeSearchAnnotation,omitempty"`
	TextAnnotations      []*EntityAnnotation   `json:"textAnnotations,omitempty"`
}

Cloud Vision API – 実行編

使用する画像は画像処理でお馴染みのレナさんを使用し、その結果もコミットしておきました。

lenna

lenna.jpgという命名の場合

$ go run main.go lenna.jpg

結果は長くなるので、リンクだけ貼っておきます。

画像のベストプラクティス

pkg

Image Best Practices – Cloud Vision APIに書いてあるので、認識させる画像はなるべくそれに準拠させるようにしましょう。

画像の形式

Cloud Vision APIがサポートしている画像の形式です。

  • JPEG
  • PNG8/24
  • GIF/Animated GIF (first frame only)
  • BMP
  • WEBP
  • RAW
  • ICO

画像データの入力

今回のサンプルではbase64だけで説明をしましたが、Cloud Storage経由でも認識が可能です。

Cloud Storage

"image":{
  "source": {
    "gcs_image_uri":"gs://bucket-name/path_to_image_object"
  }
},

base64

"image":{
  "content": "base64-encoded data"
},

画像のサイズ

適切に画像を認識させる推奨サイズが存在します。

  • FACE_DETECTION: 1600 x 1200
  • LANDMARK_DETECTION: 640 x 480
  • LOGO_DETECTION: 640 x 480
  • LABEL_DETECTION: 640 x 480
  • TEXT_DETECTION: 1024 x 768
  • SAFE_SEARCH_DETECTION: 640 x 480

使用リミット

リミットも存在しているので、これを超すリクエストは送らないようにしましょう。

  • MB per image: 4 MB
  • MB per request: 8 MB
  • Requests per second: 10
  • Requests per feature per day: 700,000
  • Requests per feature per month: 20,000,000
  • Images per second: 8
  • Images per request: 16

おわりに

今回Cloud Vision APIを使用した理由の一つに、画像を高精度に読み取り・解析することができれば弊社が提供しているPairsサービスの品質向上へと繋げることが可能になります。
実際、APIを使用してみたところ顔認識も精度が高いですし、ラベル検知も使える場面があるので好印象です。

他にも、このAPIを使用したWebサービスも思いついたので時間があるときにでもサービスを作ろうかなと思っています。

まずは自分で撮影した大量の画像を分析して自動で分類したいものです。

  • このエントリーをはてなブックマークに追加

エウレカでは、一緒に働いていただける方を絶賛募集中です。募集中の職種はこちらからご確認ください!皆様のエントリーをお待ちしております!

Recommend

Pairsの検索機能をElasticsearchにリプレースした話

iOSエンジニアにも便利なSketchプラグイン6選