Amazon RekognitionでTwitterから有名人の不適切な画像を収集する

乗るしかない、このビッグウェーブに。

はじめに

本日Amazon RekognitionにCelebrity Recognition(有名人認識)が追加されました。

そして先日、僕はこんなブログを書きました。

つまりそういうことです。

やってみた

Image Moderationによって不適切と判断されたものがCelebrityであれば保存します。

スクリプト本体はAWS SDK for Goを使用しました。新機能を使う前に最新版を取得しておきます。

$ go get -u github.com/aws/aws-sdk-go/

また、TwitterのPublic timelineの収集にはChimeraCoder/anacondaライブラリを使用しました。

$ go get -u github.com/ChimeraCoder/anaconda/

スクリプト

スクリプトの内容は以下の通りです。詳細はコメントとして書きました。

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/rekognition"

	"github.com/ChimeraCoder/anaconda"
)

func main() {
	// Twitter認証情報をセット
	consumerKey := os.Getenv("TWITTER_CONSUMER_KEY")
	consumerSecret := os.Getenv("TWITTER_CONSUMER_SECRET")
	AccessToken := os.Getenv("TWITTER_ACCESS_TOKEN")
	AccessTokenSecret := os.Getenv("TWITTER_ACCESS_TOKEN_SECRET")

	// Twitter認証
	anaconda.SetConsumerKey(consumerKey)
	anaconda.SetConsumerSecret(consumerSecret)
	api := anaconda.NewTwitterApi(AccessToken, AccessTokenSecret)

	// TwitterのPublicStream(statuses/sample)を取得
	twitterStream := api.PublicStreamSample(nil)

	for {
		// データを取得
		data := <-twitterStream.C

		switch tweet := data.(type) {

		// Tweetの場合
		case anaconda.Tweet:

			// 画像URLを格納する配列を定義
			var url []string

			// 画像URLを配列に格納
			m := tweet.ExtendedEntities.Media
			for i := 0; i < len(m); i++ {
				url = append(url, m[i].Media_url)
			}

			for i := 0; i < len(url); i++ {
				// 画像を取得
				getImage(url[i])
			}

		default:
		}
	}

}

func getImage(url string) {
  fmt.Println(url)

	// 画像URLを格納する配列を定義
	var result1 bool
	var result2 bool

	// 画像ファイルのURLに:largeを追加
	var buffer bytes.Buffer
	buffer.WriteString(url)
	buffer.WriteString(":large")

	// largeな画像ファイルを取得
	image, err := http.Get(buffer.String())
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer image.Body.Close()

	// 画像ファイルのデータを全て読み込み
	bytes, err := ioutil.ReadAll(image.Body)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	// セッション作成
	sess := session.Must(session.NewSession())

	// Rekognitionクライアントを作成
	svc := rekognition.New(sess, aws.NewConfig().WithRegion("us-east-1"))

	// svc.DetectModerationLabelsに渡すパラメータを設定
	dparams := &rekognition.DetectModerationLabelsInput{
		Image: &rekognition.Image{
			Bytes: bytes,
		},
		// Confidenceが70%以上
		MinConfidence: aws.Float64(0.7),
	}

	// svc.DetectModerationLabelsを実行
	dresp, err := svc.DetectModerationLabels(dparams)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	// 対象であればtrue
	if len(dresp.ModerationLabels) != 0 {
		result1 = true
	}

	// svc.RecognizeCelebritiesに渡すパラメータを設定
	cparams := &rekognition.RecognizeCelebritiesInput{
		Image: &rekognition.Image{
			Bytes: bytes,
		},
	}

	// svc.RecognizeCelebritiesを実行
	cresp, err := svc.RecognizeCelebrities(cparams)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	// 対象であればtrueをリターン
	if len(cresp.CelebrityFaces) != 0 {
		result2 = true
	}

	if result1 == true && result2 == true {
		// URLからファイル名を取得
		filename := filepath.Base(url)
		if err != nil {
			fmt.Println(err.Error())
			return
		}

		// ファイルを作成
		file, err := os.Create(filename)
		if err != nil {
			fmt.Println(err.Error())
			return
		}
		defer file.Close()

		// ファイルを書き込んで保存
		file.Write(bytes)

		// 保存した情報を出力
		fmt.Println(dresp.ModerationLabels)
		fmt.Println(cresp.CelebrityFaces)
		fmt.Println("Save " + filename + ".")

	}
}

作成したスクリプトはgo fmtで整形します。

$ go fmt getcelebpic.go

そしてbuildします。

$ go build

バイナリが出来上がります。

$ ls
getcelebpic   getcelebpic.go

実行結果

例の如く実行して保存された画像は公序良俗の観点からお見せできませんが、実際に取得出来た画像のCelebrityFacesの内容はこんな感じです。

  Id: "1YK3In0Q",
  MatchConfidence: 88,
  Name: "Fujita Nicole",
  Urls: ["www.imdb.com/name/nm7578700"]

まさかの藤田ニコルさん...!(水着でした)

さいごに

やらずにはいられませんでした。ごめんなさい。

補足すると著名人の方が自分の写真が肖像権を違反して流出しているのを検知するような使い方も出来そうです。