Development

食べ物の画像にモザイクをかける API と Chrome 拡張を作ってみた [Project Oxford Vision API]

飯テロ対策として、食べ物の画像にモザイクをかける API と Chrome 拡張を作ってみました。

Microsoft Project Oxford の Vision API を利用したもので、API 制限等からきちんと公開はしていませんが、API を試したり、コードを見たりはできます。先日話題になった How-Old.net は、Project Oxford の提供する API のうち Face API を利用しています。

Chrome 拡張

Vision API

食べ物の画像にモザイクをかける Web サービス

画像 URL を指定すると、食べ物の画像の場合、モザイク処理された画像が返ってきます。

http://foodtero.azurewebsites.net/api/?url=http://upload.wikimedia.org/wikipedia/ja/thumb/f/fc/Soy_ramen.jpg/260px-Soy_ramen.jpg

利用している Visio API は、1分に20回、月に5,000回までの制限があるので、エラーになった場合は、そのままの画像を返します。皆さん自身で API Key を取得して実装してみてください。

Vision API

Vison APIs は、以下の機能があります。

  • 画像認識
  • サムネイルの生成
  • OCR

今回は、画像認識を利用して、画像のカテゴリーが「食べ物」場合、モザイクをかけて返すという Web サービスにしてみました。Vison API では、86のカテゴリーに分類できます。

Microsoft Project Oxford Analyze Image

公式のデモはこちら。

Microsoft Project Oxford Demo Vision

アダルトコンテンツ、Racy コンテンツ(水着とか)の判別、背景・前景のカラーやアクセントカラー抽出などもできます。

Vision API を使ってみる

現在 Beta 版で無料で利用できます(呼び出し制限を緩和しようとも、無料版しかないのでできません)。また、Azure Market での購入が必要で、Azure アカウントが必要です。API は、RESTful API で、プラットフォームを選びません。

リクエスト URL: https://api.projectoxford.ai/vision/v1/analyses[?visualFeatures]

詳細は、Microsoft Project Oxford API Reference 参照。

Azure Marketplace でサービスの選択

Azure ポータルから、Marketplace の Vision API を追加します。

Vision API

Key の取得

https://dev.projectoxford.ai/Developer にアクセスして、Key を取得します。

Vision API

SDK のダウンロード、コードサンプル

.NET/Android の SDK が用意されています。その他の言語も ドキュメント のサンプルコードなどを見れば簡単に使えます。

Visual Basic で、SDK のライブラリを利用すれば、画像認識は次のように書けます。

visionapi.vb
Dim client = New VisionServiceClient("**key**")
Dim result = Await client.AnalyzeImageAsync("画像 URL") ' 画像の Stream も指定可能

If result.Categories IsNot Nothing AndAlso result.Categories.Any AndAlso
            result.Categories.First.Name.StartsWith("food_") Then 
    ' (画像のカテゴリーが食べ物の場合)
End If

Web サービスを作る

ASP.NET で Web サービスを作ります。

コントローラーのコードです。ルーティングを変更する以外は、他に書くコードはありません。

ApiController.vb
Imports System.Drawing
Imports System.Net
Imports Microsoft.ProjectOxford.Vision

Public Class ApiController
    Inherits System.Web.Mvc.Controller

    Async Function Index(url As String) As Threading.Tasks.Task(Of ActionResult)
        If url Is Nothing Then
            Return New HttpStatusCodeResult(HttpStatusCode.BadRequest)
        End If

        Dim result As Contract.AnalysisResult
        Try
            ' API 呼び出し
            Dim client = New VisionServiceClient("0b1ff4ab7a634bb0a6f7d532659f5d77")
            If Uri.IsWellFormedUriString(url, UriKind.Absolute) Then
                result = Await client.AnalyzeImageAsync(url)
            Else
                Return New HttpStatusCodeResult(HttpStatusCode.BadRequest)
            End If

        Catch cEx As ClientException
            Return FileStream(url)
        Catch ex As Exception
            Return FileStream(url)
        End Try

        If result.Categories IsNot Nothing AndAlso result.Categories.Any AndAlso
            result.Categories.First.Name.StartsWith("food_") Then ' 画像のカテゴリーが食べ物

            ' モザイク画像作成
            Dim webClient = New WebClient
            Dim inBmp = New Bitmap(webClient.OpenRead(url))
            Dim tmpBmp = New Bitmap(inBmp.Width \ 10, inBmp.Height \ 10)
            Dim outBmp = New Bitmap(inBmp.Width, inBmp.Height)

            Using g = Graphics.FromImage(tmpBmp)
                g.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
                g.DrawImage(inBmp, 0, 0, tmpBmp.Width, tmpBmp.Height)
            End Using

            Using g = Graphics.FromImage(outBmp)
                g.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
                g.DrawImage(tmpBmp, 0, 0, outBmp.Width, outBmp.Height)
            End Using

            Response.ContentType = "image/png"
            outBmp.Save(Response.OutputStream, Imaging.ImageFormat.Png)
            Return New EmptyResult

        Else
            Return FileStream(url)
        End If
    End Function

    Private Function FileStream(url As String) As ActionResult
        Try
            Dim req = HttpWebRequest.CreateHttp(url)
            Dim res = DirectCast(req.GetResponse, HttpWebResponse)

            Response.ContentType = res.ContentType
            res.GetResponseStream.CopyTo(Response.OutputStream)

        Catch ex As WebException
            If ex.Status = System.Net.WebExceptionStatus.ProtocolError Then
                Dim r = DirectCast(ex.Response, System.Net.HttpWebResponse)
                Response.StatusCode = r.StatusCode
            End If
        End Try

        Return New EmptyResult
    End Function

End Class

Chrome の拡張を作る

試しに Chrome 拡張を作ってみます。img の URL を、作った API の URL に差し替えます。

フォルダーに、custom.js、manifest.json、jquery.min.js を作ります。

custom.js
$(function() {
    $('img').each(function(){
        this.src = "http://foodtero.azurewebsites.net/api/?url=" + encodeURIComponent(this.src);
    });
});
manifest.json
{
    "manifest_version": 2,
    "name": "食べ物の画像にモザイクをかける拡張",
    "version": "1.0",
    "content_scripts": [{
        "matches": [ "<all_urls>" ],
        "js": [ "jquery.min.js", "custom.js" ],
        "run_at": "document_start"
    }]
}

Chrome のアドレス欄に「chrome://extensions/」を入力。「デベロッパーモード」にチェックを入れて「パッケージ化されていない拡張機能を読み込む」ボタンから、作成したフォルダーを指定すれば、拡張を追加できます。

Chrome Extension

以上で完成です。ただし、モザイク画像がロードされるまで、元の画像が見えるという欠点と、API 制限にすぐひっかかります。お遊びということで。あと、Data URI(data:image で始まる URL)にも対応できていません。

わざわざ Web サービスを作りましたが、Vison API は、JavaScript からも利用できるので、Chrome 拡張のみで完結も可能です。

関連サイト

“飯テロ”撲滅へ本腰、厚生労イ動省がWebブラウザーアドオンを公開 - 窓の社(やしろ)