LoginSignup
6
5

More than 5 years have passed since last update.

GoogleCloudVisionAPIに画像を投げるエンドポイントをGAEに立ててアダルト判定しよう。

Last updated at Posted at 2017-07-13

Google CloudVisionAPIにアダルト判定をさせる話です。

そもそも何ができるのか。

以下を見ましょう。
Vision API - 画像コンテンツ分析  |  Google Cloud Platform

これを見ると
ラベル検出:画像に写っているカテゴリの物体を検出する。
不適切なコンテンツの検出:アダルトや暴力的コンテンツなどの検出
ロゴ検出:商品ロゴ検出
ランドマーク検出:人口建造物を検出できる。
光学式文字認識:OCR。テキスト検出と抽出ができる。
顔検出:顔があることを検出(=個人を特定する顔検出はできない)
画像属性:ドミナントカラーや切り抜きのヒントなど検出。

面白そう。
たぶんGoogleのエンジニア的には不適切なコンテンツを検出して弾く用途で作ったんだと思います。
でも逆に言えば、エロ画像の過激度を判定して分類してくれるのが作れそう。

料金

料金  |  Google Cloud Vision API ドキュメント  |  Google Cloud Platform

ここに詳しく書いてあります。明朗会計。

なぜAppEngineを使うのか

別にAppEngineを使う必要があるのかというと別にそんなことないです。
Detecting Safe Search Properties  |  Google Cloud Vision API Documentation  |  Google Cloud Platform

ここを見ると、普通にCloud Vision用のAPIに対してPOSTすればいいですね。

以上をふまえて、なぜAppEngineを使うのかというと…特に深い意味はなかったですね…。
この記事を書いてるときに初めてREST APIあることに気づきました。

まぁでもAppEngineに立てておけば、CloudVisionAPIから返ってくるJSONの値を加工してクライアント側に渡せるという点だけでも意味はあるのかなと思います。
クライアント側にBase64エンコードさせる必要がないのも1つの利点かもしれません。

コード

コントローラ

controller/safesearch.go
package safesearch

import (
    "bytes"
    "encoding/base64"
    "image"

    "image/jpeg"

    model "cvapi/model/safesearch"
    "log"

    "github.com/gin-gonic/gin"
)
func GetSafeSearchResult(g *gin.Context) {
    g.Request.ParseForm()
    //file="hogehoge.jpg"となっている場合
    file, _, err := g.Request.FormFile("file")
    if err != nil {
        g.AbortWithStatus(500)
    }
    //image.Image形式にDecodeする。
    img, _, err := image.Decode(file)
    if err != nil {
        g.AbortWithStatus(500)
    }

    buf := new(bytes.Buffer)
    //jpeg.Encodeでは、bufに対してByte配列が入る。
    err = jpeg.Encode(buf, img, nil)
    if err != nil {
        g.AbortWithStatus(500)
    }
    //base64にエンコードする。
    enc := base64.StdEncoding.EncodeToString(buf.Bytes())

    //base64エンコードされたものをmodel側に投げて判定のJSONを得る。
    json, err := model.CheckSafe(enc, g)
    if err != nil {
        g.AbortWithStatus(500)
    }
    //今回のデモでは特に加工せずJSONを出力する。
    g.JSON(200, json)
}

モデル側

model/safesearch.go
package safesearch

import (
    "io/ioutil"

    "github.com/gin-gonic/gin"
    "golang.org/x/oauth2/google"

    "google.golang.org/api/vision/v1"
    "google.golang.org/appengine"
)

func CheckSafe(enc string, g *gin.Context) (*vision.AnnotateImageResponse, error) {
    img := &vision.Image{Content: enc}
    ctx := appengine.NewContext(g.Request)

    //configFileはGCPのAPIManagerから認証情報のJSONファイルを発行しましょう
    confFile, err := ioutil.ReadFile("resources/{{認証情報.json}}")
    if err != nil {
        return nil, err
    }
    //GoogleDeveloperのサービスアカウントのJSONファイルを使って
    //認証情報を読んでリクエストに認可を与える
    cfg, err := google.JWTConfigFromJSON([]byte(confFile), vision.CloudPlatformScope)
    client := cfg.Client(ctx)

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

    //ここでVisionAPIの中で使用するサービスを指定する。
    //FACE_DETECTIONとかTEXT_DETECTIONとか。
    feature := &vision.Feature{
        Type:       "SAFE_SEARCH_DETECTION",
        MaxResults: 5,
    }
    //最初に作ったimg情報とFeatureを利用してリクエストを作成する。
    req := &vision.AnnotateImageRequest{
        Image:    img,
        Features: []*vision.Feature{feature},
    }

    batch := &vision.BatchAnnotateImagesRequest{
        Requests: []*vision.AnnotateImageRequest{req},
    }
    //リクエストを投げる。
    res, err := svc.Images.Annotate(batch).Do()
    if err != nil {
        return nil, err
    }
    //コントローラ側でJSON作成のために構造体を返す。
    return res.Responses[0], nil
}


エンドポイントの使い方:

上で作ったエンドポイントにPOSTで画像(.jpg)を投げるだけ。

参考

GolangとGoogle Cloud Vision APIを使って牛の画像認識をする - Developers Note

終わりに

勢いで作ってしまったけど、レスポンスは

response.json
{
  "responses": [
    {
      "safeSearchAnnotation": {
        "adult": "VERY_UNLIKELY",
        "spoof": "VERY_LIKELY",
        "medical": "UNLIKELY",
        "violence": "UNLIKELY"
      }
    }
  ]
}

という感じに帰ってくる。
Adult成分がVERY_UNLIKELYやPOSSIBLE、LIKELYなど返ってくるのがわかったので


こういうことができそうだなって思いました。
AppEngineで画像投げるだけでGCSに格納して、DataStoreにはAdult情報と画像を紐付けるデータを格納しておく、というところまではできるんじゃないでしょうか。
(多分作っても公開しませんが…)

7/15追記:作りました。(自動でストレージに分類して保存してくれて最高)

終わり。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5