ちょっと話題の記事

Amazon RekognitionのImage Moderationを活用してTwitterの不適切な画像を収集する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

「お前は何をやっているんだ」という意見は正しいと思います。

はじめに

先日Amazon RekognitionにImage Moderation機能が追加されました。

今回はこの機能を使って、TwitterのPublic timelineから、不適切と思われる画像を収集してみます。

やってみた

スクリプト本体は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/

スクリプト

スクリプトの内容は以下の通りです。詳細はコメントとして書きました。Golangとしてはもっと綺麗な書き方があるんだと思いますが、その辺はご容赦ください。もっと素敵なコードが書けるようになりたいものです。

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) {
	// 画像ファイルの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に渡すパラメータを設定
	params := &rekognition.DetectModerationLabelsInput{
		Image: &rekognition.Image{
			Bytes: bytes,
		},
		// Confidenceが70%以上
		MinConfidence: aws.Float64(0.7),
	}

	// svc.DetectModerationLabelsを実行
	resp, err := svc.DetectModerationLabels(params)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	// 対象であれば処理継続
	if len(resp.ModerationLabels) != 0 {
		// 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(resp.ModerationLabels)
		fmt.Println("Save " + filename + ".")
	}
	return
}

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

$ go fmt getpic.go

そしてbuildします。

$ go build

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

$ ls
getpic   getpic.go

実行結果

実行すると以下のように出力されます。

$ ./getpic
[{
  Confidence: 53.97080612182617,
  Name: "Explicit Nudity",
  ParentName: ""
} {
  Confidence: 53.97080612182617,
  Name: "Graphic Male Nudity",
  ParentName: "Explicit Nudity"
}]
Save C-KFERyXkAE1oGP.jpg.
[{
  Confidence: 57.758872985839844,
  Name: "Suggestive",
  ParentName: ""
} {
  Confidence: 57.758872985839844,
  Name: "Female Swimwear Or Underwear",
  ParentName: "Suggestive"
}]
Save C-H_9B1XkAIKTdK.jpg.
....snip....

そして保存された画像がこちら...なのですが、ちょっとお見せできないのでモザイクかけました。

temp

というような使い方もできますね!

さいごに

Image Moderationは一般的にはフィルタリングするために使われますが、こういった使い方もできます。今回は単純にConfidenceが70%以上の画像を取得しましたが、ParentNameNameを判別することで、特定のカテゴリと判定された画像のみを選別することも可能です。

以上、ちょっと変わったユースケースでした。